From 03253a15cf4c9631bee6a5949f825d8354fc6b2e Mon Sep 17 00:00:00 2001 From: Kris Thielemans Date: Mon, 5 Feb 2024 10:43:03 +0000 Subject: [PATCH 1/4] update clang-format [ci skip] use one-per-line for parameters/arguments if they don't fit on one line set AllowShortFunctionsOnASingleLine to InlineOnly, although it doesn't seem to quite work properly, i.e. it no longer puts short functions in the class on one line, but it does "spread" out-of-class definitions. --- .clang-format | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.clang-format b/.clang-format index 1606cc0cd..19d80912e 100644 --- a/.clang-format +++ b/.clang-format @@ -25,6 +25,8 @@ BraceWrapping: SplitEmptyFunction: false SplitEmptyRecord: true SplitEmptyNamespace: true +BinPackParameters: false +BinPackArguments: false ColumnLimit: 130 IndentPPDirectives: AfterHash PointerAlignment: Left @@ -32,5 +34,6 @@ SortIncludes: false SortUsingDeclarations: false SpaceBeforeParens: ControlStatements PackConstructorInitializers: Never +AllowShortFunctionsOnASingleLine: InlineOnly Standard: Cpp11 ... From 6377c74f62d1dc07b9826c3a5b082d047472fbca Mon Sep 17 00:00:00 2001 From: Kris Thielemans Date: Mon, 5 Feb 2024 11:02:10 +0000 Subject: [PATCH 2/4] correct URL for pre-commit hook [ci skip] --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fe361a407..3b29a13e0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,5 @@ repos: -- repo: git://github.com/doublify/pre-commit-clang-format +- repo: https://github.com/doublify/pre-commit-clang-format rev: '62302476' hooks: - id: clang-format From a4c49f9e928844042d759a253c6b6902bb430270 Mon Sep 17 00:00:00 2001 From: Kris Thielemans Date: Tue, 6 Feb 2024 09:51:49 +0000 Subject: [PATCH 3/4] add doc on clang-format process --- CONTRIBUTING.md | 20 +++++++++++--------- documentation/STIR-developers-overview.tex | 5 ++++- documentation/release_6.0.htm | 14 +++++++++++++- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3c8ea7411..c8ce45824 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,23 +29,25 @@ This is our recommended process. If it sounds too daunting, ask for help. 3. Create a branch in your fork with a descriptive name and put your fixes there. If your fix is simple you could do it on github by editing a file, otherwise clone your project (or add a remote to your current git clone) and work as usual. -4. If your change is important, add it to the release notesfor the upcoming version, [see](https://github.com/UCL/STIR/blob/master/documentation/) +4. Configure your editor and potentially even [pre-commit](https://pre-commit.com/), see +[documentation/devel/README.md](documentation/devel/README.md). +5. If your change is important, add it to the release notes for the upcoming version in the [documentation folder](https://github.com/UCL/STIR/tree/master/documentation/) and even the [User's Guide](https://github.com/UCL/STIR/blob/master/documentation/STIR-UsersGuide.tex) or other documentation files. -5. Use [well-formed commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) +6. Use [well-formed commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) for each change (in particular with a single "subject" line -followed by an empty line and then more details). If the change affects comments only, it is recommended to put `[ci skip]` in your subject line. This avoids unnecessary computation, and clogging our Travis/Appveyor queues. -6. Push the commits to your fork and submit a [pull request (PR)](https://help.github.com/articles/creating-a-pull-request) -(enable changes by project admins.) Give your pull request a descriptive name (i.e. don't call if *Fix #issuenumber*. Be prepared to add further commits to your branch after discussion. -In the description of the PR, add a statement about which Issue this applies to -using [a phrase such that github auto-closes the issue when merged to master](https://help.github.com/articles/closing-issues-using-keywords/). -7. Be prepared to add further commits to your branch after discussion. +followed by an empty line and then more details). Please by mindful about the resources used by our Continuous Integration (CI) workflows: - Group your commits and only push once your code compiles and tests succeed on your machine (ideally you have sensible commit messages at every stage) - Use specific keywords in the first line of the last commit that you push to prevent CI being run: - `[ci skip]` skips all CI runs (e.g. when you only change documentation, or when your update isn't ready yet) - `[actions skip]` does not run GitHub Actions, see [here](https://github.blog/changelog/2021-02-08-github-actions-skip-pull-request-and-push-workflows-with-skip-ci/). Note: this can be in the main commit message. - `[skip appveyor]` does not run Appveyor, see [here](https://www.appveyor.com/docs/how-to/filtering-commits/#skip-directive-in-commit-message) -8. After acceptance of your PR, go home with a nice warm feeling. +7. Push the commits to your fork and submit a [pull request (PR)](https://help.github.com/articles/creating-a-pull-request) +(enable changes by project admins.) Give your pull request a descriptive name (i.e. don't call if *Fix #issuenumber*. Be prepared to add further commits to your branch after discussion. +In the description of the PR, add a statement about which Issue this applies to +using [a phrase such that github auto-closes the issue when merged to master](https://help.github.com/articles/closing-issues-using-keywords/). +8. Be prepared to add further commits to your branch after discussion. +9. After acceptance of your PR, go home with a nice warm feeling. Suggested reading: https://help.github.com/articles/fork-a-repo/, https://git-scm.com/book/en/v2/GitHub-Contributing-to-a-Project or https://guides.github.com/activities/forking/. diff --git a/documentation/STIR-developers-overview.tex b/documentation/STIR-developers-overview.tex index 08f4d7121..5746a292f 100644 --- a/documentation/STIR-developers-overview.tex +++ b/documentation/STIR-developers-overview.tex @@ -1331,7 +1331,10 @@ \section{ \section{Contributing to STIR} See -\R2Lurl{https://github.com/UCL/STIR/blob/master/CONTRIBUTING.md}{STIR/CONTRIBUTING.md}. +\R2Lurl{https://github.com/UCL/STIR/blob/master/CONTRIBUTING.md}{STIR/CONTRIBUTING.md} +and +\R2Lurl{https://github.com/UCL/STIR/blob/master/documentation/devel/README.md}{documentation/devel/README.md} +for more information on editor settings etc. \subsection{Continuous integration testing} We use GitHub Actions and Appveyor for testing of every pull-request that was submitted on GitHub. PRs diff --git a/documentation/release_6.0.htm b/documentation/release_6.0.htm index 9c4e249ce..38cf9921e 100644 --- a/documentation/release_6.0.htm +++ b/documentation/release_6.0.htm @@ -9,7 +9,7 @@

Summary of changes in STIR release 6.0

This version is 99% backwards compatible with STIR 5.x for the user (see below). Developers might need to make code changes as - detailed below. Note though that the location of installed files have changed. + detailed below. Note though that the locations of installed files have changed. Developers of other software that uses STIR via CMake will need to adapt (see below).

Overall summary

@@ -285,6 +285,18 @@

New deprecations for future versions

What's new for developers (aside from what should be obvious from the above):

+

White-space and style enforcement

+
    +
  • We now use clang-format to enforce C++-style, including white-space settings, line-breaks + etc. This uses the .clang-format file in the root directory of STIR. Developers should + configure their editor encordingly, and ideally use pre-commit. It also has + consequences for existing branches as you might experience more conflicts than usual + during a merge. More detail is in + documentation/devel/README.md.
    + PR #1368. +
  • +
+

Backward incompatibities

  • From 88f4ce70929a41c745fc39030e90c87bfaf046b7 Mon Sep 17 00:00:00 2001 From: stir_maintenance Date: Tue, 6 Feb 2024 09:57:45 +0000 Subject: [PATCH 4/4] run pre-commit --- .../General_Reconstruction.cxx | 51 +- .../General_Reconstruction.h | 24 +- examples/C++/using_STIR_LOCAL/demo1.cxx | 34 +- examples/C++/using_STIR_LOCAL/demo2.cxx | 39 +- examples/C++/using_STIR_LOCAL/demo3.cxx | 61 +- .../C++/using_STIR_LOCAL/demo4_obj_fun.cxx | 69 +- .../using_STIR_LOCAL/demo5_line_search.cxx | 194 +- .../demo_create_image.cxx | 33 +- src/IO/ECAT6OutputFileFormat.cxx | 100 +- ...namicDiscretisedDensityInputFileFormat.cxx | 65 +- ...amicDiscretisedDensityOutputFileFormat.cxx | 75 +- src/IO/ECAT7OutputFileFormat.cxx | 91 +- ...ECAT7ParametricDensityOutputFileFormat.cxx | 117 +- src/IO/GEHDF5Wrapper.cxx | 1296 ++--- src/IO/GIPL_ImageFormat.cxx | 1056 ++-- src/IO/IO_registries.cxx | 61 +- src/IO/ITKImageInputFileFormat.cxx | 550 +- src/IO/ITKOutputFileFormat.cxx | 103 +- src/IO/InputFileFormatRegistry.cxx | 10 +- src/IO/InputStreamFromROOTFile.cxx | 303 +- ...putStreamFromROOTFileForCylindricalPET.cxx | 292 +- src/IO/InputStreamFromROOTFileForECATPET.cxx | 197 +- src/IO/InputStreamWithRecordsFromUPENN.cxx | 65 +- src/IO/InputStreamWithRecordsFromUPENNbin.cxx | 299 +- src/IO/InputStreamWithRecordsFromUPENNtxt.cxx | 174 +- ...amicDiscretisedDensityOutputFileFormat.cxx | 61 +- src/IO/InterfileHeader.cxx | 1686 +++--- src/IO/InterfileHeaderSiemens.cxx | 327 +- src/IO/InterfileOutputFileFormat.cxx | 46 +- src/IO/InterfilePDFSHeaderSPECT.cxx | 185 +- ...tricDiscretisedDensityOutputFileFormat.cxx | 54 +- ...amicDiscretisedDensityOutputFileFormat.cxx | 88 +- ...tricDiscretisedDensityOutputFileFormat.cxx | 84 +- src/IO/OutputFileFormat.cxx | 20 +- src/IO/OutputFileFormat_default.cxx | 62 +- src/IO/ecat6_utils.cxx | 689 +-- src/IO/interfile.cxx | 1549 +++--- src/IO/stir_ecat6.cxx | 1366 +++-- src/IO/stir_ecat7.cxx | 2808 +++++----- src/IO/stir_ecat_common.cxx | 281 +- src/Shape_buildblock/Box3D.cxx | 98 +- src/Shape_buildblock/DiscretisedShape3D.cxx | 106 +- src/Shape_buildblock/Ellipsoid.cxx | 89 +- src/Shape_buildblock/EllipsoidalCylinder.cxx | 319 +- src/Shape_buildblock/GenerateImage.cxx | 292 +- src/Shape_buildblock/Shape3D.cxx | 206 +- .../Shape3DWithOrientation.cxx | 63 +- .../Shape_buildblock_registries.cxx | 2 +- src/SimSET/conv_SimSET_projdata_to_STIR.cxx | 218 +- src/SimSET/conv_to_SimSET_att_image.cxx | 112 +- src/SimSET/write_phg_image_info.c | 129 +- src/analytic/FBP2D/FBP2D.cxx | 26 +- src/analytic/FBP2D/FBP2DReconstruction.cxx | 233 +- src/analytic/FBP2D/RampFilter.cxx | 165 +- src/analytic/FBP3DRP/ColsherFilter.cxx | 569 +-- src/analytic/FBP3DRP/FBP3DRP.cxx | 26 +- .../FBP3DRP/FBP3DRPReconstruction.cxx | 1019 ++-- src/buildblock/ArcCorrection.cxx | 310 +- src/buildblock/Array.cxx | 35 +- .../ArrayFilter1DUsingConvolution.cxx | 227 +- ...ilter1DUsingConvolutionSymmetricKernel.cxx | 80 +- .../ArrayFilter2DUsingConvolution.cxx | 112 +- .../ArrayFilter3DUsingConvolution.cxx | 207 +- .../ArrayFilterUsingRealDFTWithPadding.cxx | 99 +- src/buildblock/ByteOrder.cxx | 16 +- src/buildblock/ChainedDataProcessor.cxx | 85 +- .../DataSymmetriesForViewSegmentNumbers.cxx | 30 +- src/buildblock/DetectorCoordinateMap.cxx | 318 +- src/buildblock/DiscretisedDensity.cxx | 159 +- src/buildblock/DynamicDiscretisedDensity.cxx | 216 +- src/buildblock/DynamicProjData.cxx | 388 +- src/buildblock/ExamData.cxx | 16 +- src/buildblock/ExamInfo.cxx | 47 +- src/buildblock/FilePath.cxx | 529 +- src/buildblock/GatedDiscretisedDensity.cxx | 172 +- src/buildblock/GatedProjData.cxx | 220 +- .../GeneralisedPoissonNoiseGenerator.cxx | 126 +- .../GeometryBlocksOnCylindrical.cxx | 187 +- src/buildblock/HUToMuImageProcessor.cxx | 141 +- src/buildblock/IndexRange.cxx | 70 +- src/buildblock/KeyParser.cxx | 1689 +++--- src/buildblock/ML_norm.cxx | 2085 ++++---- src/buildblock/MaximalArrayFilter3D.cxx | 79 +- src/buildblock/MaximalImageFilter3D.cxx | 43 +- src/buildblock/MedianArrayFilter3D.cxx | 105 +- src/buildblock/MedianImageFilter3D.cxx | 46 +- src/buildblock/MinimalArrayFilter3D.cxx | 76 +- src/buildblock/MinimalImageFilter3D.cxx | 43 +- src/buildblock/MultipleDataSetHeader.cxx | 60 +- src/buildblock/MultipleProjData.cxx | 72 +- ...ableConvolutionUsingRealDFTImageFilter.cxx | 109 +- src/buildblock/NumericType.cxx | 225 +- .../ParseDiscretisedDensityParameters.cxx | 146 +- src/buildblock/ParsingObject.cxx | 118 +- src/buildblock/PatientPosition.cxx | 71 +- src/buildblock/ProjData.cxx | 350 +- src/buildblock/ProjDataFromStream.cxx | 867 ++-- src/buildblock/ProjDataGEHDF5.cxx | 187 +- src/buildblock/ProjDataInMemory.cxx | 418 +- src/buildblock/ProjDataInfo.cxx | 744 ++- ...ojDataInfoBlocksOnCylindricalNoArcCorr.cxx | 104 +- src/buildblock/ProjDataInfoCylindrical.cxx | 597 +-- .../ProjDataInfoCylindricalArcCorr.cxx | 148 +- .../ProjDataInfoCylindricalNoArcCorr.cxx | 634 ++- src/buildblock/ProjDataInfoGeneric.cxx | 67 +- .../ProjDataInfoGenericNoArcCorr.cxx | 406 +- src/buildblock/ProjDataInfoSubsetByView.cxx | 10 +- src/buildblock/ProjDataInterfile.cxx | 84 +- src/buildblock/Radionuclide.cxx | 86 +- src/buildblock/RadionuclideDB.cxx | 206 +- src/buildblock/RelatedViewgrams.cxx | 279 +- src/buildblock/SSRB.cxx | 398 +- src/buildblock/Scanner.cxx | 2762 ++++++---- src/buildblock/Segment.cxx | 54 +- src/buildblock/SegmentBySinogram.cxx | 144 +- src/buildblock/SegmentByView.cxx | 136 +- .../SeparableArrayFunctionObject.cxx | 63 +- .../SeparableCartesianMetzImageFilter.cxx | 107 +- .../SeparableConvolutionImageFilter.cxx | 165 +- .../SeparableGaussianArrayFilter.cxx | 136 +- .../SeparableGaussianImageFilter.cxx | 119 +- src/buildblock/SeparableMetzArrayFilter.cxx | 381 +- src/buildblock/Sinogram.cxx | 94 +- src/buildblock/TextWriter.cxx | 27 +- ...ldMinToSmallPositiveValueDataProcessor.cxx | 66 +- src/buildblock/TimeFrameDefinitions.cxx | 234 +- src/buildblock/TimeGateDefinitions.cxx | 90 +- ...TruncateToCylindricalFOVImageProcessor.cxx | 56 +- src/buildblock/Verbosity.cxx | 15 +- src/buildblock/Viewgram.cxx | 92 +- src/buildblock/VoxelsOnCartesianGrid.cxx | 399 +- src/buildblock/buildblock_registries.cxx | 10 +- src/buildblock/centre_of_gravity.cxx | 107 +- src/buildblock/date_time_functions.cxx | 123 +- src/buildblock/error.cxx | 31 +- src/buildblock/extend_projdata.cxx | 138 +- src/buildblock/find_STIR_config.cxx | 41 +- src/buildblock/find_fwhm_in_image.cxx | 416 +- src/buildblock/getopt.c | 727 ++- .../interfile_keyword_functions.cxx | 53 +- src/buildblock/interpolate_projdata.cxx | 405 +- src/buildblock/inverse_SSRB.cxx | 29 +- src/buildblock/line.cxx | 385 +- src/buildblock/linear_regression.cxx | 130 +- src/buildblock/multiply_crystal_factors.cxx | 180 +- src/buildblock/num_threads.cxx | 33 +- src/buildblock/overlap_interpolate.cxx | 508 +- src/buildblock/recon_array_functions.cxx | 560 +- src/buildblock/scale_sinograms.cxx | 154 +- src/buildblock/utilities.cxx | 382 +- src/buildblock/warning.cxx | 26 +- src/buildblock/zoom.cxx | 476 +- src/data_buildblock/SinglesRates.cxx | 79 +- .../SinglesRatesForTimeFrames.cxx | 45 +- .../SinglesRatesForTimeSlices.cxx | 419 +- src/data_buildblock/SinglesRatesFromECAT7.cxx | 132 +- .../SinglesRatesFromGEHDF5.cxx | 101 +- .../SinglesRatesFromSglFile.cxx | 353 +- .../data_buildblock_registries.cxx | 9 +- src/data_buildblock/randoms_from_singles.cxx | 24 +- src/display/display_array.cxx | 710 ++- src/display/gen.c | 149 +- src/display/gen.h | 141 +- src/display/mathlinkhelp.c | 176 +- src/display/screen.c | 885 ++-- src/display/screen.h | 303 +- src/display/screengen.c | 149 +- src/eval_buildblock/ROIValues.cxx | 46 +- src/eval_buildblock/compute_ROI_values.cxx | 210 +- ...amicDiscretisedDensityOutputFileFormat.cxx | 75 +- .../IO/OutputFileFormat_default.cxx | 4 +- .../IO/local_InputFileFormatRegistry.cxx | 1 - .../IO/local_OutputFileFormat_default.cxx | 4 +- .../AbsTimeIntervalFromDynamicData.cxx | 72 +- .../AbsTimeIntervalFromECAT7ACF.cxx | 56 +- .../buildblock/AbsTimeIntervalWithParsing.cxx | 36 +- .../buildblock/DAVArrayFilter3D.cxx | 165 +- .../buildblock/DAVImageFilter3D.cxx | 51 +- ...ModifiedInverseAveragingImageFilterAll.cxx | 4550 +++++++++-------- .../ModifiedInverseAverigingArrayFilter.cxx | 513 +- .../ModifiedInverseAverigingImageFilter.cxx | 2183 ++++---- .../NonseparableSpatiallyVaryingFilters.cxx | 2021 ++++---- .../NonseparableSpatiallyVaryingFilters3D.cxx | 1799 +++---- src/experimental/buildblock/Quaternion.cxx | 14 +- .../SeparableLowPassArrayFilter.cxx | 72 +- .../SeparableLowPassImageFilter.cxx | 111 +- .../fwd_and_bck_manipulation_for_SAF.cxx | 221 +- .../local_buildblock_registries.cxx | 33 +- .../buildblock/local_helping_functions.cxx | 467 +- ...iply_plane_scale_factorsImageProcessor.cxx | 90 +- .../iterative/OSSPS/line_search.cxx | 258 +- .../listmode/CListModeDataLMF.cxx | 75 +- .../listmode/LmToProjDataWithMC.cxx | 136 +- .../change_lm_time_tags.cxx | 117 +- .../listmode_utilities/get_singles_info.cxx | 48 +- .../lm_to_projdata_with_MC.cxx | 34 +- .../motion/MatchTrackerAndScanner.cxx | 296 +- ...RigidObjectTransformationUsingBSplines.cxx | 405 +- ...ModelForMeanAndGatedProjDataWithMotion.cxx | 465 +- src/experimental/motion/Polaris_MT_File.cxx | 280 +- .../motion/RigidObject3DMotion.cxx | 51 +- .../motion/RigidObject3DMotionFromPolaris.cxx | 1117 ++-- .../motion/RigidObject3DTransformation.cxx | 611 +-- src/experimental/motion/TimeFrameMotion.cxx | 122 +- .../Transform3DObjectImageProcessor.cxx | 256 +- .../motion/local_motion_registries.cxx | 9 +- .../motion/transform_3d_object.cxx | 345 +- .../test_BSpline_transformations.cxx | 156 +- .../motion_utilities/add_planes_to_image.cxx | 47 +- .../find_motion_corrected_norm_factors.cxx | 596 +-- .../list_deformation_vectors.cxx | 130 +- .../motion_utilities/list_polaris_info.cxx | 65 +- .../match_tracker_and_scanner.cxx | 24 +- .../motion_utilities/move_image.cxx | 182 +- .../motion_utilities/move_projdata.cxx | 188 +- .../motion_utilities/non_rigid_transform.cxx | 166 +- .../remove_corrupted_sinograms.cxx | 342 +- .../motion_utilities/report_movement.cxx | 228 +- .../rigid_object_transform_image.cxx | 150 +- .../rigid_object_transform_projdata.cxx | 114 +- .../motion_utilities/sync_polaris.cxx | 74 +- .../BinNormalisationFromML2D.cxx | 216 +- .../BinNormalisationSinogramRescaling.cxx | 134 +- .../BinNormalisationUsingProfile.cxx | 89 +- ...SymmetriesForDensels_PET_CartesianGrid.cxx | 236 +- .../ParametricQuadraticPrior.cxx | 200 +- ...thLinearModelForMeanAndDynamicProjData.cxx | 162 +- .../PostsmoothingForwardProjectorByBin.cxx | 253 +- .../ProjMatrixByBinSinglePhoton.cxx | 74 +- .../ProjMatrixByBinUsingSolidAngle.cxx | 381 +- .../ProjMatrixByBinWithPositronRange.cxx | 100 +- .../recon_buildblock/ProjMatrixByDensel.cxx | 70 +- ...rixByDenselOnCartesianGridUsingElement.cxx | 447 +- .../ProjMatrixByDenselUsingRayTracing.cxx | 391 +- .../local_recon_buildblock_registries.cxx | 29 +- src/experimental/recon_test/fwdtestDensel.cxx | 473 +- ...test_ProjMatrixByBinUsingInterpolation.cxx | 769 ++- src/experimental/test/test_Fourier.cxx | 402 +- .../test/test_LmToProjdataWithMC.cxx | 87 +- src/experimental/test/test_Quaternion.cxx | 235 +- .../test/test_RigidObject3DTransformation.cxx | 650 ++- .../test/test_proj_data_info_LOR.cxx | 263 +- .../utilities/Bland_Altman_plot.cxx | 210 +- src/experimental/utilities/CoG.cxx | 66 +- .../utilities/add_ecat7_header_to_sgl.cxx | 167 +- .../utilities/add_side_shields.cxx | 146 +- .../utilities/add_time_frame_info.cxx | 42 +- .../utilities/apply_plane_rescale_factors.cxx | 57 +- .../utilities/change_mhead_file_type.cxx | 42 +- .../utilities/compute_gradient.cxx | 81 +- .../compute_plane_rescale_factors.cxx | 72 +- .../utilities/create_normfactors.cxx | 155 +- .../utilities/create_normfactors3D.cxx | 109 +- src/experimental/utilities/fillwith1.cxx | 37 +- .../utilities/fillwithotherprojdata.cxx | 57 +- .../find_sinogram_rescaling_factors.cxx | 112 +- src/experimental/utilities/fit_cylinder.cxx | 122 +- src/experimental/utilities/image_flip_x.cxx | 89 +- .../utilities/interpolate_blocks.cxx | 265 +- .../utilities/interpolate_projdata.cxx | 112 +- src/experimental/utilities/inverse_SSRB.cxx | 63 +- .../utilities/inverse_proj_data.cxx | 193 +- .../line_profiles_through_projdata.cxx | 127 +- .../utilities/list_TAC_ROI_values.cxx | 203 +- src/experimental/utilities/make_cylinder.cxx | 117 +- .../utilities/make_grid_image.cxx | 92 +- src/experimental/utilities/mode.cxx | 199 +- .../utilities/normalizedbckproj.cxx | 272 +- .../utilities/precompute_denominator_SPS.cxx | 345 +- .../utilities/prepare_projdata.cxx | 409 +- .../utilities/remove_sinograms.cxx | 99 +- .../utilities/set_blocks_to_value.cxx | 220 +- .../utilities/shift_projdata_along_axis.cxx | 47 +- .../utilities/show_ecat7_header.cxx | 213 +- .../utilities/threshold_norm_data.cxx | 87 +- .../utilities/zero_projdata_from_norm.cxx | 87 +- src/include/stir/ArcCorrection.h | 66 +- src/include/stir/Array.h | 275 +- src/include/stir/Array.inl | 538 +- .../stir/ArrayFilter1DUsingConvolution.h | 47 +- ...yFilter1DUsingConvolutionSymmetricKernel.h | 36 +- .../stir/ArrayFilter2DUsingConvolution.h | 36 +- .../stir/ArrayFilter3DUsingConvolution.h | 38 +- .../stir/ArrayFilterUsingRealDFTWithPadding.h | 45 +- src/include/stir/ArrayFunction.h | 168 +- src/include/stir/ArrayFunction.inl | 344 +- src/include/stir/ArrayFunctionObject.h | 47 +- ...ayFunctionObject_1ArgumentImplementation.h | 27 +- ...ayFunctionObject_2ArgumentImplementation.h | 27 +- src/include/stir/Array_complex_numbers.h | 49 +- src/include/stir/BasicCoordinate.h | 167 +- src/include/stir/BasicCoordinate.inl | 411 +- src/include/stir/Bin.h | 74 +- src/include/stir/Bin.inl | 139 +- src/include/stir/BoundaryConditions.h | 12 +- src/include/stir/ByteOrder.h | 56 +- src/include/stir/ByteOrder.inl | 32 +- src/include/stir/ByteOrderDefine.h | 33 +- src/include/stir/CPUTimer.h | 41 +- src/include/stir/CPUTimer.inl | 83 +- src/include/stir/CartesianCoordinate2D.h | 20 +- src/include/stir/CartesianCoordinate2D.inl | 31 +- src/include/stir/CartesianCoordinate3D.h | 17 +- src/include/stir/CartesianCoordinate3D.inl | 40 +- src/include/stir/ChainedDataProcessor.h | 76 +- src/include/stir/Coordinate2D.h | 18 +- src/include/stir/Coordinate2D.inl | 20 +- src/include/stir/Coordinate3D.h | 14 +- src/include/stir/Coordinate3D.inl | 21 +- src/include/stir/Coordinate4D.h | 17 +- src/include/stir/Coordinate4D.inl | 22 +- src/include/stir/DataProcessor.h | 64 +- src/include/stir/DataProcessor.inl | 48 +- .../DataSymmetriesForViewSegmentNumbers.h | 41 +- src/include/stir/Densel.h | 4 +- src/include/stir/DetectionPosition.h | 55 +- src/include/stir/DetectionPosition.inl | 74 +- src/include/stir/DetectionPositionPair.h | 24 +- src/include/stir/DetectionPositionPair.inl | 76 +- src/include/stir/DetectorCoordinateMap.h | 173 +- src/include/stir/DiscretisedDensity.h | 165 +- src/include/stir/DiscretisedDensity.inl | 249 +- .../stir/DiscretisedDensityOnCartesianGrid.h | 75 +- .../DiscretisedDensityOnCartesianGrid.inl | 135 +- src/include/stir/DynamicDiscretisedDensity.h | 165 +- .../stir/DynamicDiscretisedDensity.inl | 21 +- src/include/stir/DynamicProjData.h | 150 +- src/include/stir/ExamData.h | 37 +- src/include/stir/ExamInfo.h | 64 +- src/include/stir/ExamInfo.inl | 21 +- src/include/stir/FactoryRegistry.h | 40 +- src/include/stir/FactoryRegistry.inl | 87 +- src/include/stir/FilePath.h | 194 +- src/include/stir/FilePath.inl | 59 +- src/include/stir/FullArrayIterator.h | 68 +- src/include/stir/FullArrayIterator.inl | 114 +- src/include/stir/GatedDiscretisedDensity.h | 116 +- src/include/stir/GatedProjData.h | 27 +- .../stir/GeneralisedPoissonNoiseGenerator.h | 35 +- .../stir/GeometryBlocksOnCylindrical.h | 29 +- src/include/stir/HUToMuImageProcessor.h | 47 +- src/include/stir/HighResWallClockTimer.h | 626 +-- .../stir/IO/ECAT6ImageInputFileFormat.h | 83 +- src/include/stir/IO/ECAT6OutputFileFormat.h | 40 +- ...DynamicDiscretisedDensityInputFileFormat.h | 25 +- ...ynamicDiscretisedDensityOutputFileFormat.h | 39 +- .../stir/IO/ECAT7ImageInputFileFormat.h | 49 +- src/include/stir/IO/ECAT7OutputFileFormat.h | 41 +- .../ECAT7ParametricDensityOutputFileFormat.h | 43 +- .../IO/ECAT8_32bitListmodeInputFileFormat.h | 53 +- .../stir/IO/ECAT962ListmodeInputFileFormat.h | 56 +- .../stir/IO/ECAT966ListmodeInputFileFormat.h | 64 +- src/include/stir/IO/FileSignature.h | 47 +- src/include/stir/IO/GEHDF5Wrapper.h | 230 +- src/include/stir/IO/GEHDF5Wrapper.inl | 36 +- src/include/stir/IO/GIPL_ImageFormat.h | 207 +- src/include/stir/IO/ITKImageInputFileFormat.h | 40 +- src/include/stir/IO/ITKOutputFileFormat.h | 48 +- src/include/stir/IO/InputFileFormat.h | 31 +- src/include/stir/IO/InputFileFormatRegistry.h | 92 +- .../stir/IO/InputFileFormatRegistry.txx | 51 +- src/include/stir/IO/InputStreamFromROOTFile.h | 426 +- .../stir/IO/InputStreamFromROOTFile.inl | 96 +- ...InputStreamFromROOTFileForCylindricalPET.h | 159 +- ...putStreamFromROOTFileForCylindricalPET.inl | 97 +- .../IO/InputStreamFromROOTFileForECATPET.h | 120 +- .../IO/InputStreamFromROOTFileForECATPET.inl | 35 +- src/include/stir/IO/InputStreamWithRecords.h | 74 +- .../stir/IO/InputStreamWithRecords.inl | 143 +- .../stir/IO/InputStreamWithRecordsFromHDF5.h | 78 +- .../IO/InputStreamWithRecordsFromHDF5.inl | 149 +- .../stir/IO/InputStreamWithRecordsFromUPENN.h | 131 +- .../IO/InputStreamWithRecordsFromUPENN.inl | 10 +- .../IO/InputStreamWithRecordsFromUPENNbin.h | 119 +- .../IO/InputStreamWithRecordsFromUPENNbin.inl | 31 +- .../IO/InputStreamWithRecordsFromUPENNtxt.h | 88 +- .../IO/InputStreamWithRecordsFromUPENNtxt.inl | 8 +- ...DynamicDiscretisedDensityInputFileFormat.h | 28 +- ...ynamicDiscretisedDensityOutputFileFormat.h | 45 +- src/include/stir/IO/InterfileHeader.h | 143 +- src/include/stir/IO/InterfileHeaderSiemens.h | 193 +- .../stir/IO/InterfileImageInputFileFormat.h | 26 +- .../stir/IO/InterfileOutputFileFormat.h | 44 +- .../stir/IO/InterfilePDFSHeaderSPECT.h | 19 +- ...ametricDiscretisedDensityInputFileFormat.h | 28 +- ...metricDiscretisedDensityOutputFileFormat.h | 51 +- ...DynamicDiscretisedDensityInputFileFormat.h | 51 +- ...ynamicDiscretisedDensityOutputFileFormat.h | 48 +- ...ametricDiscretisedDensityInputFileFormat.h | 47 +- ...metricDiscretisedDensityOutputFileFormat.h | 49 +- src/include/stir/IO/OutputFileFormat.h | 86 +- src/include/stir/IO/OutputFileFormat.txx | 229 +- .../stir/IO/PENNListmodeInputFileFormat.h | 65 +- .../stir/IO/ROOTListmodeInputFileFormat.h | 68 +- .../stir/IO/SAFIRCListmodeInputFileFormat.h | 287 +- src/include/stir/IO/ecat6_types.h | 47 +- src/include/stir/IO/ecat6_utils.h | 138 +- src/include/stir/IO/interfile.h | 237 +- src/include/stir/IO/read_data.h | 58 +- src/include/stir/IO/read_data.inl | 103 +- src/include/stir/IO/read_data_1d.h | 19 +- src/include/stir/IO/read_data_1d.inl | 78 +- src/include/stir/IO/read_from_file.h | 16 +- src/include/stir/IO/stir_ecat6.h | 137 +- src/include/stir/IO/stir_ecat7.h | 190 +- src/include/stir/IO/stir_ecat_common.h | 57 +- src/include/stir/IO/test/test_IO.h | 363 +- src/include/stir/IO/write_data.h | 104 +- src/include/stir/IO/write_data.inl | 207 +- src/include/stir/IO/write_data_1d.h | 26 +- src/include/stir/IO/write_data_1d.inl | 133 +- src/include/stir/IO/write_to_file.h | 11 +- src/include/stir/ImagingModality.h | 121 +- src/include/stir/IndexRange.h | 56 +- src/include/stir/IndexRange.inl | 139 +- src/include/stir/IndexRange2D.h | 6 +- src/include/stir/IndexRange2D.inl | 22 +- src/include/stir/IndexRange3D.h | 14 +- src/include/stir/IndexRange3D.inl | 21 +- src/include/stir/IndexRange4D.h | 24 +- src/include/stir/IndexRange4D.inl | 31 +- .../stir/KOSMAPOSL/KOSMAPOSLReconstruction.h | 155 +- src/include/stir/KeyParser.h | 258 +- src/include/stir/LORCoordinates.h | 770 +-- src/include/stir/LORCoordinates.inl | 441 +- src/include/stir/ML_norm.h | 372 +- src/include/stir/MaximalArrayFilter3D.h | 38 +- src/include/stir/MaximalImageFilter3D.h | 57 +- src/include/stir/MedianArrayFilter3D.h | 30 +- src/include/stir/MedianImageFilter3D.h | 55 +- src/include/stir/MinimalArrayFilter3D.h | 30 +- src/include/stir/MinimalImageFilter3D.h | 53 +- src/include/stir/MultipleDataSetHeader.h | 53 +- src/include/stir/MultipleDataSetHeader.inl | 8 +- src/include/stir/MultipleProjData.h | 178 +- src/include/stir/NestedIterator.h | 61 +- src/include/stir/NestedIterator.inl | 115 +- src/include/stir/NestedIteratorHelpers.h | 85 +- ...arableConvolutionUsingRealDFTImageFilter.h | 74 +- src/include/stir/NumericInfo.h | 263 +- src/include/stir/NumericType.h | 104 +- src/include/stir/NumericType.inl | 22 +- src/include/stir/NumericVectorWithOffset.h | 83 +- src/include/stir/NumericVectorWithOffset.inl | 227 +- .../stir/OSMAPOSL/OSMAPOSLReconstruction.h | 109 +- src/include/stir/OSSPS/OSSPSReconstruction.h | 129 +- src/include/stir/ParseAndCreateFrom.h | 59 +- src/include/stir/ParseAndCreateFrom.inl | 34 +- .../stir/ParseDiscretisedDensityParameters.h | 46 +- src/include/stir/ParsingObject.h | 51 +- src/include/stir/PatientPosition.h | 116 +- src/include/stir/PixelsOnCartesianGrid.h | 95 +- src/include/stir/PixelsOnCartesianGrid.inl | 115 +- src/include/stir/PostFiltering.h | 26 +- src/include/stir/PostFiltering.inl | 23 +- src/include/stir/ProjData.h | 213 +- src/include/stir/ProjData.inl | 146 +- src/include/stir/ProjDataFromStream.h | 128 +- src/include/stir/ProjDataFromStream.inl | 48 +- src/include/stir/ProjDataGEHDF5.h | 81 +- src/include/stir/ProjDataInMemory.h | 141 +- src/include/stir/ProjDataInfo.h | 240 +- src/include/stir/ProjDataInfo.inl | 170 +- .../stir/ProjDataInfoBlocksOnCylindrical.h | 3 +- ...ProjDataInfoBlocksOnCylindricalNoArcCorr.h | 29 +- ...ojDataInfoBlocksOnCylindricalNoArcCorr.inl | 3 +- src/include/stir/ProjDataInfoCylindrical.h | 139 +- src/include/stir/ProjDataInfoCylindrical.inl | 160 +- .../stir/ProjDataInfoCylindricalArcCorr.h | 32 +- .../stir/ProjDataInfoCylindricalArcCorr.inl | 10 +- .../stir/ProjDataInfoCylindricalNoArcCorr.h | 199 +- .../stir/ProjDataInfoCylindricalNoArcCorr.inl | 183 +- src/include/stir/ProjDataInfoGeneric.h | 36 +- src/include/stir/ProjDataInfoGeneric.inl | 54 +- .../stir/ProjDataInfoGenericNoArcCorr.h | 99 +- .../stir/ProjDataInfoGenericNoArcCorr.inl | 138 +- src/include/stir/ProjDataInterfile.h | 46 +- src/include/stir/Radionuclide.h | 27 +- src/include/stir/RadionuclideDB.h | 22 +- src/include/stir/RegisteredObject.h | 29 +- src/include/stir/RegisteredObject.inl | 17 +- src/include/stir/RegisteredObjectBase.h | 9 +- src/include/stir/RegisteredParsingObject.h | 31 +- src/include/stir/RegisteredParsingObject.inl | 26 +- src/include/stir/RelatedViewgrams.h | 139 +- src/include/stir/RelatedViewgrams.inl | 115 +- src/include/stir/RunTests.h | 415 +- src/include/stir/SSRB.h | 83 +- src/include/stir/Scanner.h | 283 +- src/include/stir/Scanner.inl | 330 +- src/include/stir/Segment.h | 59 +- src/include/stir/Segment.inl | 28 +- src/include/stir/SegmentBySinogram.h | 46 +- src/include/stir/SegmentBySinogram.inl | 63 +- src/include/stir/SegmentByView.h | 55 +- src/include/stir/SegmentByView.inl | 62 +- src/include/stir/SegmentIndices.inl | 3 +- .../stir/SeparableArrayFunctionObject.h | 27 +- .../stir/SeparableCartesianMetzImageFilter.h | 81 +- .../stir/SeparableConvolutionImageFilter.h | 78 +- .../stir/SeparableGaussianArrayFilter.h | 37 +- .../stir/SeparableGaussianImageFilter.h | 72 +- src/include/stir/SeparableMetzArrayFilter.h | 41 +- src/include/stir/Shape/Box3D.h | 45 +- src/include/stir/Shape/CombinedShape3D.h | 31 +- src/include/stir/Shape/CombinedShape3D.inl | 43 +- src/include/stir/Shape/DiscretisedShape3D.h | 101 +- src/include/stir/Shape/DiscretisedShape3D.inl | 8 +- src/include/stir/Shape/Ellipsoid.h | 43 +- src/include/stir/Shape/EllipsoidalCylinder.h | 60 +- .../stir/Shape/EllipsoidalCylinder.inl | 16 +- src/include/stir/Shape/GenerateImage.h | 88 +- src/include/stir/Shape/Shape3D.h | 72 +- src/include/stir/Shape/Shape3D.inl | 28 +- .../stir/Shape/Shape3DWithOrientation.h | 29 +- src/include/stir/Sinogram.h | 67 +- src/include/stir/Sinogram.inl | 97 +- src/include/stir/SinogramIndices.h | 16 +- src/include/stir/SinogramIndices.inl | 52 +- src/include/stir/StirException.h | 53 +- src/include/stir/Succeeded.h | 21 +- src/include/stir/TOF_conversions.h | 7 +- src/include/stir/TextWriter.h | 184 +- ...holdMinToSmallPositiveValueDataProcessor.h | 57 +- src/include/stir/TimeFrameDefinitions.h | 35 +- src/include/stir/TimeGateDefinitions.h | 31 +- src/include/stir/TimedBlock.h | 119 +- src/include/stir/TimedObject.h | 19 +- src/include/stir/TimedObject.inl | 17 +- src/include/stir/Timer.h | 11 +- src/include/stir/Timer.inl | 51 +- ...ivialDataSymmetriesForViewSegmentNumbers.h | 21 +- ...ialDataSymmetriesForViewSegmentNumbers.inl | 20 +- .../TruncateToCylindricalFOVImageProcessor.h | 82 +- src/include/stir/VectorWithOffset.h | 168 +- src/include/stir/VectorWithOffset.inl | 623 ++- src/include/stir/Verbosity.h | 4 +- src/include/stir/ViewSegmentNumbers.h | 6 +- src/include/stir/ViewSegmentNumbers.inl | 64 +- src/include/stir/Viewgram.h | 63 +- src/include/stir/Viewgram.inl | 96 +- src/include/stir/ViewgramIndices.h | 4 +- src/include/stir/ViewgramIndices.inl | 2 +- src/include/stir/VoxelsOnCartesianGrid.h | 243 +- src/include/stir/VoxelsOnCartesianGrid.inl | 103 +- src/include/stir/ZoomOptions.h | 37 +- .../stir/analytic/FBP2D/FBP2DReconstruction.h | 85 +- src/include/stir/analytic/FBP2D/RampFilter.h | 34 +- .../stir/analytic/FBP3DRP/ColsherFilter.h | 118 +- .../analytic/FBP3DRP/FBP3DRPReconstruction.h | 205 +- src/include/stir/array_index_functions.h | 31 +- src/include/stir/array_index_functions.inl | 84 +- src/include/stir/assign.h | 58 +- src/include/stir/assign_to_subregion.h | 19 +- src/include/stir/assign_to_subregion.inl | 35 +- src/include/stir/centre_of_gravity.h | 43 +- src/include/stir/common.h | 256 +- src/include/stir/config/gcc.h | 8 +- src/include/stir/config/visualc.h | 24 +- src/include/stir/convert_array.h | 70 +- src/include/stir/convert_array.inl | 25 +- src/include/stir/convert_range.h | 32 +- src/include/stir/convert_range.inl | 236 +- src/include/stir/copy_fill.h | 77 +- src/include/stir/cross_product.h | 22 +- src/include/stir/data/SinglesRates.h | 148 +- src/include/stir/data/SinglesRates.inl | 17 +- .../stir/data/SinglesRatesForTimeFrames.h | 88 +- .../stir/data/SinglesRatesForTimeSlices.h | 205 +- src/include/stir/data/SinglesRatesFromECAT7.h | 31 +- .../stir/data/SinglesRatesFromGEHDF5.h | 46 +- .../stir/data/SinglesRatesFromSglFile.h | 72 +- src/include/stir/data/randoms_from_singles.h | 7 +- src/include/stir/date_time_functions.h | 35 +- src/include/stir/decay_correction_factor.h | 31 +- src/include/stir/deprecated.h | 13 +- src/include/stir/detail/test_if_1d.h | 114 +- src/include/stir/display.h | 116 +- src/include/stir/display.inl | 151 +- src/include/stir/doxygen_doc_for_boost.h | 53 +- src/include/stir/doxygengroups.h | 52 +- src/include/stir/doxygenmain.h | 16 +- src/include/stir/error.h | 10 +- src/include/stir/evaluation/ROIValues.h | 76 +- .../stir/evaluation/compute_ROI_values.h | 102 +- src/include/stir/extend_projdata.h | 13 +- src/include/stir/extract_line.h | 10 +- src/include/stir/extract_line.inl | 28 +- src/include/stir/find_STIR_config.h | 3 +- src/include/stir/find_fwhm_in_image.h | 88 +- src/include/stir/find_fwhm_in_image.inl | 54 +- src/include/stir/geometry/line_distances.h | 132 +- src/include/stir/getopt.h | 273 +- src/include/stir/index_at_maximum.h | 77 +- src/include/stir/info.h | 13 +- .../stir/interfile_keyword_functions.h | 18 +- src/include/stir/interpolate.h | 5 +- src/include/stir/interpolate_projdata.h | 55 +- src/include/stir/inverse_SSRB.h | 24 +- src/include/stir/is_null_ptr.h | 28 +- src/include/stir/line.h | 40 +- src/include/stir/linear_regression.h | 80 +- src/include/stir/linear_regression.inl | 223 +- ...tCylindricalScannerWithDiscreteDetectors.h | 10 +- ...ricalScannerWithViewTangRingRingEncoding.h | 37 +- ...calScannerWithViewTangRingRingEncoding.inl | 100 +- .../CListEventScannerWithDiscreteDetectors.h | 28 +- ...CListEventScannerWithDiscreteDetectors.inl | 73 +- src/include/stir/listmode/CListModeData.h | 25 +- src/include/stir/listmode/CListModeDataECAT.h | 38 +- .../stir/listmode/CListModeDataECAT8_32bit.h | 29 +- .../stir/listmode/CListModeDataGEHDF5.h | 43 +- src/include/stir/listmode/CListModeDataPENN.h | 78 +- src/include/stir/listmode/CListModeDataROOT.h | 178 +- .../stir/listmode/CListModeDataSAFIR.h | 102 +- src/include/stir/listmode/CListRecord.h | 19 +- .../stir/listmode/CListRecordECAT8_32bit.h | 219 +- .../stir/listmode/CListRecordECAT962.h | 235 +- .../stir/listmode/CListRecordECAT966.h | 227 +- src/include/stir/listmode/CListRecordGEHDF5.h | 400 +- src/include/stir/listmode/CListRecordPENN.h | 143 +- src/include/stir/listmode/CListRecordROOT.h | 200 +- src/include/stir/listmode/CListRecordROOT.inl | 16 +- src/include/stir/listmode/CListRecordSAFIR.h | 359 +- .../stir/listmode/CListRecordSAFIR.inl | 79 +- src/include/stir/listmode/ListEvent.h | 13 +- src/include/stir/listmode/ListModeData.h | 63 +- .../stir/listmode/ListModeData_dummy.h | 88 +- src/include/stir/listmode/ListRecord.h | 11 +- .../stir/listmode/ListRecordWithGatingInput.h | 6 +- src/include/stir/listmode/ListTime.h | 16 +- src/include/stir/listmode/LmToProjData.h | 46 +- .../stir/listmode/LmToProjDataAbstract.h | 21 +- .../stir/listmode/LmToProjDataBootstrap.h | 22 +- .../LmToProjDataWithRandomRejection.h | 24 +- .../NiftyPET_listmode/LmToProjDataNiftyPET.h | 110 +- src/include/stir/listmode/SPECTListEvent.h | 6 +- src/include/stir/listmode/SPECTListModeData.h | 27 +- src/include/stir/listmode/SPECTListRecord.h | 12 +- .../listmode/SPECTListRecordWithGatingInput.h | 6 +- src/include/stir/make_array.h | 212 +- src/include/stir/make_array.inl | 311 +- src/include/stir/min_positive_element.h | 17 +- src/include/stir/modelling/KineticModel.h | 13 +- .../stir/modelling/KineticParameters.h | 24 +- .../stir/modelling/KineticParameters.inl | 43 +- src/include/stir/modelling/ModelMatrix.h | 136 +- src/include/stir/modelling/ModelMatrix.inl | 425 +- .../modelling/ParametricDiscretisedDensity.h | 102 +- ...ndCreateParametricDiscretisedDensityFrom.h | 21 +- ...CreateParametricDiscretisedDensityFrom.inl | 39 +- src/include/stir/modelling/PatlakPlot.h | 166 +- src/include/stir/modelling/PlasmaData.h | 101 +- src/include/stir/modelling/PlasmaData.inl | 314 +- src/include/stir/modelling/PlasmaSample.h | 34 +- src/include/stir/modelling/PlasmaSample.inl | 75 +- src/include/stir/modulo.h | 86 +- src/include/stir/more_algorithms.h | 35 +- src/include/stir/more_algorithms.inl | 55 +- src/include/stir/multiply_crystal_factors.h | 5 +- src/include/stir/num_threads.h | 10 +- src/include/stir/numerics/BSplines.h | 96 +- .../stir/numerics/BSplines1DRegularGrid.h | 184 +- .../stir/numerics/BSplines1DRegularGrid.inl | 266 +- src/include/stir/numerics/BSplinesDetail.inl | 523 +- .../stir/numerics/BSplinesRegularGrid.h | 249 +- .../stir/numerics/BSplinesRegularGrid.inl | 106 +- src/include/stir/numerics/BSplines_coef.inl | 195 +- .../stir/numerics/BSplines_weights.inl | 739 ++- src/include/stir/numerics/FastErf.h | 52 +- src/include/stir/numerics/FastErf.inl | 20 +- src/include/stir/numerics/IR_filters.h | 47 +- src/include/stir/numerics/IR_filters.inl | 122 +- src/include/stir/numerics/MatrixFunction.h | 61 +- src/include/stir/numerics/MatrixFunction.inl | 188 +- src/include/stir/numerics/determinant.h | 12 +- src/include/stir/numerics/divide.h | 22 +- src/include/stir/numerics/divide.inl | 25 +- src/include/stir/numerics/erf.h | 16 +- src/include/stir/numerics/erf.inl | 741 ++- src/include/stir/numerics/fourier.h | 85 +- src/include/stir/numerics/ieeefp.h | 54 +- .../numerics/integrate_discrete_function.h | 11 +- .../numerics/integrate_discrete_function.inl | 40 +- src/include/stir/numerics/max_eigenvector.h | 146 +- src/include/stir/numerics/norm.h | 77 +- src/include/stir/numerics/norm.inl | 48 +- .../stir/numerics/overlap_interpolate.h | 71 +- .../stir/numerics/overlap_interpolate.inl | 146 +- .../stir/numerics/sampling_functions.h | 21 +- .../stir/numerics/sampling_functions.inl | 81 +- .../stir/numerics/stir_NumericalRecipes.h | 89 +- src/include/stir/recon_array_functions.h | 69 +- .../recon_buildblock/AnalyticReconstruction.h | 58 +- .../recon_buildblock/BackProjectorByBin.h | 153 +- .../BackProjectorByBinUsingInterpolation.h | 269 +- .../BackProjectorByBinUsingProjMatrixByBin.h | 59 +- ...ProjectorByBinUsingSquareProjMatrixByBin.h | 61 +- .../stir/recon_buildblock/BinNormalisation.h | 65 +- .../BinNormalisationFromAttenuationImage.h | 47 +- .../BinNormalisationFromECAT7.h | 36 +- .../BinNormalisationFromECAT8.h | 43 +- .../BinNormalisationFromGEHDF5.h | 52 +- .../BinNormalisationFromProjData.h | 41 +- .../BinNormalisationPETFromComponents.h | 25 +- .../recon_buildblock/BinNormalisationSPECT.h | 58 +- .../BinNormalisationWithCalibration.h | 28 +- .../ChainedBinNormalisation.h | 56 +- .../recon_buildblock/DataSymmetriesForBins.h | 86 +- .../DataSymmetriesForBins.inl | 27 +- .../DataSymmetriesForBins_PET_CartesianGrid.h | 126 +- ...ataSymmetriesForBins_PET_CartesianGrid.inl | 1316 +++-- .../DataSymmetriesForDensels.h | 52 +- .../DataSymmetriesForDensels.inl | 18 +- .../DistributedCachingInformation.h | 69 +- .../stir/recon_buildblock/DistributedWorker.h | 89 +- .../stir/recon_buildblock/FilterRootPrior.h | 59 +- .../recon_buildblock/ForwardProjectorByBin.h | 142 +- ...orwardProjectorByBinUsingProjMatrixByBin.h | 59 +- .../ForwardProjectorByBinUsingRayTracing.h | 238 +- .../stir/recon_buildblock/FourierRebinning.h | 310 +- .../GeneralisedObjectiveFunction.h | 254 +- .../stir/recon_buildblock/GeneralisedPrior.h | 51 +- .../recon_buildblock/GeneralisedPrior.inl | 23 +- .../IterativeReconstruction.h | 135 +- .../stir/recon_buildblock/LogcoshPrior.h | 253 +- ...L_estimate_component_based_normalisation.h | 12 +- .../BackProjectorByBinNiftyPET.h | 42 +- .../ForwardProjectorByBinNiftyPET.h | 85 +- .../NiftyPET_projector/NiftyPETHelper.h | 186 +- .../ProjectorByBinPairUsingNiftyPET.h | 23 +- src/include/stir/recon_buildblock/PLSPrior.h | 109 +- .../BackProjectorByBinParallelproj.h | 66 +- .../ForwardProjectorByBinParallelproj.h | 97 +- .../ParallelprojHelper.h | 45 +- .../ProjectorByBinPairUsingParallelproj.h | 31 +- .../recon_buildblock/PinholeSPECTUB_Tools.h | 555 +- .../PinholeSPECTUB_Weight3d.h | 65 +- ...nearKineticModelAndDynamicProjectionData.h | 86 +- ...arKineticModelAndDynamicProjectionData.txx | 673 ++- ...issonLogLikelihoodWithLinearModelForMean.h | 138 +- ...arModelForMeanAndGatedProjDataWithMotion.h | 96 +- ...ModelForMeanAndGatedProjDataWithMotion.txx | 613 ++- ...oodWithLinearModelForMeanAndListModeData.h | 234 +- ...orMeanAndListModeDataWithProjMatrixByBin.h | 63 +- ...elihoodWithLinearModelForMeanAndProjData.h | 126 +- .../PostsmoothingBackProjectorByBin.h | 57 +- .../PresmoothingForwardProjectorByBin.h | 53 +- .../PriorWithParabolicSurrogate.h | 23 +- .../stir/recon_buildblock/ProjDataRebinning.h | 46 +- .../stir/recon_buildblock/ProjMatrixByBin.h | 123 +- .../stir/recon_buildblock/ProjMatrixByBin.inl | 147 +- .../ProjMatrixByBinFromFile.h | 71 +- .../ProjMatrixByBinPinholeSPECTUB.h | 327 +- .../recon_buildblock/ProjMatrixByBinSPECTUB.h | 103 +- .../ProjMatrixByBinUsingInterpolation.h | 172 +- .../ProjMatrixByBinUsingRayTracing.h | 66 +- .../ProjMatrixElemsForOneBin.h | 87 +- .../ProjMatrixElemsForOneBin.inl | 72 +- .../ProjMatrixElemsForOneBinValue.h | 36 +- .../ProjMatrixElemsForOneBinValue.inl | 134 +- .../ProjMatrixElemsForOneDensel.h | 73 +- .../ProjMatrixElemsForOneDensel.inl | 65 +- .../ProjMatrixElemsForOneDenselValue.h | 31 +- .../ProjMatrixElemsForOneDenselValue.inl | 110 +- .../recon_buildblock/ProjectorByBinPair.h | 57 +- .../ProjectorByBinPairUsingProjMatrixByBin.h | 33 +- ...rojectorByBinPairUsingSeparateProjectors.h | 27 +- .../stir/recon_buildblock/QuadraticPrior.h | 106 +- .../RayTraceVoxelsOnCartesianGrid.h | 20 +- .../stir/recon_buildblock/Reconstruction.h | 76 +- .../stir/recon_buildblock/RelatedBins.h | 52 +- .../stir/recon_buildblock/RelatedBins.inl | 38 +- .../stir/recon_buildblock/RelatedDensels.h | 52 +- .../stir/recon_buildblock/RelatedDensels.inl | 39 +- .../RelativeDifferencePrior.h | 97 +- .../stir/recon_buildblock/SPECTUB_Tools.h | 525 +- .../stir/recon_buildblock/SPECTUB_Weight3d.h | 122 +- .../stir/recon_buildblock/SqrtHessianRowSum.h | 160 +- .../SumOfGeneralisedObjectiveFunctions.h | 55 +- .../SumOfGeneralisedObjectiveFunctions.inl | 55 +- .../stir/recon_buildblock/SymmetryOperation.h | 55 +- .../SymmetryOperations_PET_CartesianGrid.h | 430 +- .../SymmetryOperations_PET_CartesianGrid.inl | 687 ++- .../TrivialBinNormalisation.h | 12 +- .../TrivialDataSymmetriesForBins.h | 55 +- .../stir/recon_buildblock/distributable.h | 132 +- .../distributableMPICacheEnabled.h | 29 +- .../recon_buildblock/distributable_main.h | 9 +- .../recon_buildblock/distributed_functions.h | 706 ++- .../distributed_test_functions.h | 95 +- .../find_basic_vs_nums_in_subsets.h | 34 +- .../test/PoissonLLReconstructionTests.h | 34 +- .../test/ReconstructionTests.h | 110 +- src/include/stir/round.h | 29 +- src/include/stir/round.inl | 63 +- src/include/stir/scale_sinograms.h | 14 +- .../stir/scatter/CreateTailMaskFromACFs.h | 89 +- src/include/stir/scatter/ScatterEstimation.h | 607 ++- .../stir/scatter/ScatterEstimation.inl | 43 +- src/include/stir/scatter/ScatterSimulation.h | 649 ++- .../stir/scatter/ScatterSimulation.inl | 54 +- .../stir/scatter/SingleScatterSimulation.h | 77 +- src/include/stir/shared_ptr.h | 48 +- .../GatedSpatialTransformation.h | 56 +- .../stir/spatial_transformation/InvertAxis.h | 30 +- .../SpatialTransformation.h | 18 +- .../stir/spatial_transformation/warp_image.h | 20 +- src/include/stir/stir_math.h | 19 +- src/include/stir/stream.h | 90 +- src/include/stir/stream.inl | 147 +- src/include/stir/thresholding.h | 47 +- src/include/stir/unique_ptr.h | 11 +- src/include/stir/utilities.h | 167 +- src/include/stir/utilities.inl | 91 +- src/include/stir/warning.h | 19 +- src/include/stir/zoom.h | 171 +- .../stir_experimental/AbsTimeInterval.h | 36 +- .../AbsTimeIntervalFromDynamicData.h | 22 +- .../AbsTimeIntervalFromECAT7ACF.h | 23 +- .../AbsTimeIntervalWithParsing.h | 15 +- .../stir_experimental/DAVArrayFilter3D.h | 30 +- .../stir_experimental/DAVImageFilter3D.h | 33 +- src/include/stir_experimental/Filter.h | 161 +- .../ModifiedInverseAveragingImageFilterAll.h | 128 +- .../ModifiedInverseAverigingArrayFilter.h | 64 +- .../ModifiedInverseAverigingImageFilter.h | 100 +- .../NonseparableSpatiallyVaryingFilters.h | 126 +- .../NonseparableSpatiallyVaryingFilters3D.h | 124 +- src/include/stir_experimental/Quaternion.h | 56 +- src/include/stir_experimental/Quaternion.inl | 132 +- .../SeparableGaussianArrayFilter.h | 41 +- .../SeparableGaussianImageFilter.h | 55 +- .../SeparableLowPassArrayFilter.h | 34 +- .../SeparableLowPassArrayFilter2.h | 126 +- .../SeparableLowPassImageFilter.h | 59 +- src/include/stir_experimental/fft.h | 42 +- .../fwd_and_bck_manipulation_for_SAF.h | 89 +- .../listmode/CListModeDataLMF.h | 37 +- .../listmode/CListRecordLMF.h | 106 +- .../listmode/LmToProjDataWithMC.h | 18 +- .../local_helping_functions.h | 50 +- .../stir_experimental/modelling/BloodFrame.h | 56 +- .../modelling/BloodFrame.inl | 103 +- .../modelling/BloodFrameData.h | 88 +- .../modelling/BloodFrameData.inl | 147 +- .../modelling/OneParamModel.h | 7 +- .../modelling/OneParamModel.inl | 53 +- .../motion/MatchTrackerAndScanner.h | 52 +- ...onRigidObjectTransformationUsingBSplines.h | 40 +- .../motion/ObjectTransformation.h | 14 +- ...arModelForMeanAndGatedProjDataWithMotion.h | 76 +- .../motion/Polaris_MT_File.h | 83 +- .../motion/RigidObject3DMotion.h | 61 +- .../motion/RigidObject3DMotionFromPolaris.h | 64 +- .../motion/RigidObject3DTransformation.h | 83 +- .../motion/TimeFrameMotion.h | 42 +- .../motion/Transform3DObjectImageProcessor.h | 56 +- .../motion/bin_interpolate.h | 243 +- .../motion/transform_3d_object.h | 98 +- .../motion/transform_3d_object.inl | 103 +- ...ltiply_plane_scale_factorsImageProcessor.h | 55 +- .../numerics/linear_extrapolation.h | 18 +- .../numerics/more_interpolators.h | 100 +- .../numerics/more_interpolators.inl | 157 +- .../phantoms/CylindersWithLineSource.h | 193 +- src/include/stir_experimental/phantoms/Utah.h | 112 +- .../BinNormalisationFromML2D.h | 26 +- .../BinNormalisationSinogramRescaling.h | 25 +- .../BinNormalisationUsingProfile.h | 12 +- ...taSymmetriesForDensels_PET_CartesianGrid.h | 55 +- ...SymmetriesForDensels_PET_CartesianGrid.inl | 176 +- .../ParametricQuadraticPrior.h | 88 +- ...WithLinearModelForMeanAndDynamicProjData.h | 44 +- .../PostsmoothingForwardProjectorByBin.h | 57 +- .../ProjMatrixByBinSinglePhoton.h | 47 +- .../ProjMatrixByBinUsingSolidAngle.h | 50 +- .../ProjMatrixByBinWithPositronRange.h | 53 +- .../recon_buildblock/ProjMatrixByDensel.h | 116 +- .../recon_buildblock/ProjMatrixByDensel.inl | 83 +- ...atrixByDenselOnCartesianGridUsingElement.h | 48 +- .../ProjMatrixByDenselUsingRayTracing.h | 59 +- src/iterative/KOSMAPOSL/KOSMAPOSL.cxx | 39 +- .../KOSMAPOSL/KOSMAPOSLReconstruction.cxx | 1402 +++-- src/iterative/OSMAPOSL/OSMAPOSL.cxx | 39 +- .../OSMAPOSL/OSMAPOSLReconstruction.cxx | 503 +- src/iterative/OSSPS/OSSPS.cxx | 17 +- src/iterative/OSSPS/OSSPSReconstruction.cxx | 404 +- src/iterative/POSMAPOSL/POSMAPOSL.cxx | 17 +- src/iterative/POSSPS/POSSPS.cxx | 13 +- src/listmode_buildblock/CListEvent.cxx | 12 +- src/listmode_buildblock/CListModeDataECAT.cxx | 206 +- .../CListModeDataECAT8_32bit.cxx | 81 +- .../CListModeDataGEHDF5.cxx | 83 +- src/listmode_buildblock/CListModeDataPENN.cxx | 123 +- src/listmode_buildblock/CListModeDataROOT.cxx | 480 +- .../CListModeDataSAFIR.cxx | 81 +- .../CListRecordECAT8_32bit.cxx | 44 +- .../CListRecordECAT962.cxx | 51 +- .../CListRecordECAT966.cxx | 39 +- src/listmode_buildblock/CListRecordPENN.cxx | 93 +- src/listmode_buildblock/CListRecordROOT.cxx | 80 +- src/listmode_buildblock/ListEvent.cxx | 9 +- src/listmode_buildblock/ListModeData.cxx | 25 +- src/listmode_buildblock/LmToProjData.cxx | 807 ++- .../LmToProjDataAbstract.cxx | 5 +- .../LmToProjDataBootstrap.cxx | 210 +- .../LmToProjDataWithRandomRejection.cxx | 87 +- .../LmToProjDataNiftyPET.cxx | 69 +- .../add_ecat7_header_to_sgl.cxx | 167 +- src/listmode_utilities/conv_NiftyPET_stir.cxx | 315 +- src/listmode_utilities/list_lm_countrates.cxx | 98 +- src/listmode_utilities/list_lm_events.cxx | 210 +- src/listmode_utilities/list_lm_info.cxx | 65 +- src/listmode_utilities/lm_fansums.cxx | 243 +- src/listmode_utilities/lm_to_projdata.cxx | 37 +- .../lm_to_projdata_NiftyPET.cxx | 218 +- .../lm_to_projdata_bootstrap.cxx | 32 +- .../lm_to_projdata_with_random_rejection.cxx | 30 +- src/listmode_utilities/print_sgl_values.cxx | 97 +- src/listmode_utilities/rebin_sgl_file.cxx | 177 +- src/listmode_utilities/scan_sgl_file.cxx | 417 +- src/modelling_buildblock/KineticModel.cxx | 15 +- .../ParametricDiscretisedDensity.cxx | 120 +- src/modelling_buildblock/PatlakPlot.cxx | 395 +- .../modelling_registries.cxx | 3 +- .../apply_patlak_to_images.cxx | 66 +- ...ct_single_images_from_parametric_image.cxx | 138 +- ..._dynamic_images_from_parametric_images.cxx | 137 +- .../make_parametric_image_from_components.cxx | 114 +- .../mult_image_parameters.cxx | 102 +- .../mult_model_with_dyn_images.cxx | 74 +- .../write_patlak_matrix.cxx | 41 +- src/numerics_buildblock/determinant.cxx | 76 +- src/numerics_buildblock/fourier.cxx | 384 +- .../AnalyticReconstruction.cxx | 166 +- src/recon_buildblock/BackProjectorByBin.cxx | 354 +- .../BackProjectorByBinUsingInterpolation.cxx | 1172 +++-- ...ProjectorByBinUsingInterpolation_3DCho.cxx | 3897 +++++++------- ...rojectorByBinUsingInterpolation_linear.cxx | 2 +- ...BinUsingInterpolation_piecewise_linear.cxx | 2 +- ...BackProjectorByBinUsingProjMatrixByBin.cxx | 266 +- ...ojectorByBinUsingSquareProjMatrixByBin.cxx | 119 +- src/recon_buildblock/BinNormalisation.cxx | 228 +- .../BinNormalisationFromAttenuationImage.cxx | 123 +- .../BinNormalisationFromECAT7.cxx | 588 +-- .../BinNormalisationFromECAT8.cxx | 693 ++- .../BinNormalisationFromGEHDF5.cxx | 632 ++- .../BinNormalisationFromProjData.cxx | 141 +- .../BinNormalisationPETFromComponents.cxx | 25 +- .../BinNormalisationSPECT.cxx | 455 +- .../BinNormalisationWithCalibration.cxx | 59 +- .../ChainedBinNormalisation.cxx | 115 +- .../DataSymmetriesForBins.cxx | 90 +- ...ataSymmetriesForBins_PET_CartesianGrid.cxx | 559 +- .../DataSymmetriesForDensels.cxx | 29 +- .../DistributedCachingInformation.cxx | 132 +- src/recon_buildblock/DistributedWorker.cxx | 654 +-- src/recon_buildblock/FilterRootPrior.cxx | 132 +- .../ForwardProjectorByBin.cxx | 296 +- ...wardProjectorByBinUsingProjMatrixByBin.cxx | 250 +- .../ForwardProjectorByBinUsingRayTracing.cxx | 1719 ++++--- ...rdProjectorByBinUsingRayTracing_Siddon.cxx | 778 +-- src/recon_buildblock/FourierRebinning.cxx | 1077 ++-- .../GeneralisedObjectiveFunction.cxx | 427 +- src/recon_buildblock/GeneralisedPrior.cxx | 56 +- .../IterativeReconstruction.cxx | 582 +-- src/recon_buildblock/LogcoshPrior.cxx | 707 ++- ...estimate_component_based_normalisation.cxx | 31 +- .../BackProjectorByBinNiftyPET.cxx | 151 +- .../ForwardProjectorByBinNiftyPET.cxx | 152 +- .../NiftyPET_projector/NiftyPETHelper.cxx | 2102 ++++---- .../ProjectorByBinPairUsingNiftyPET.cxx | 69 +- src/recon_buildblock/PLSPrior.cxx | 738 +-- .../BackProjectorByBinParallelproj.cxx | 209 +- .../ForwardProjectorByBinParallelproj.cxx | 180 +- .../ParallelprojHelper.cxx | 87 +- .../ProjectorByBinPairUsingParallelproj.cxx | 59 +- src/recon_buildblock/PinholeSPECTUB_Tools.cxx | 1468 +++--- .../PinholeSPECTUB_Weight3d.cxx | 1956 +++---- ...arKineticModelAndDynamicProjectionData.cxx | 11 +- ...sonLogLikelihoodWithLinearModelForMean.cxx | 282 +- ...ModelForMeanAndGatedProjDataWithMotion.cxx | 17 +- ...dWithLinearModelForMeanAndListModeData.cxx | 300 +- ...MeanAndListModeDataWithProjMatrixByBin.cxx | 1173 +++-- ...ihoodWithLinearModelForMeanAndProjData.cxx | 1477 +++--- .../PostsmoothingBackProjectorByBin.cxx | 98 +- .../PresmoothingForwardProjectorByBin.cxx | 90 +- src/recon_buildblock/ProjDataRebinning.cxx | 108 +- src/recon_buildblock/ProjMatrixByBin.cxx | 228 +- .../ProjMatrixByBinFromFile.cxx | 479 +- .../ProjMatrixByBinPinholeSPECTUB.cxx | 1286 ++--- .../ProjMatrixByBinSPECTUB.cxx | 1194 ++--- .../ProjMatrixByBinUsingInterpolation.cxx | 322 +- .../ProjMatrixByBinUsingRayTracing.cxx | 923 ++-- .../ProjMatrixElemsForOneBin.cxx | 455 +- .../ProjMatrixElemsForOneDensel.cxx | 190 +- src/recon_buildblock/ProjectorByBinPair.cxx | 39 +- ...ProjectorByBinPairUsingProjMatrixByBin.cxx | 49 +- ...jectorByBinPairUsingSeparateProjectors.cxx | 44 +- src/recon_buildblock/QuadraticPrior.cxx | 928 ++-- .../RayTraceVoxelsOnCartesianGrid.cxx | 229 +- src/recon_buildblock/Reconstruction.cxx | 153 +- .../RelativeDifferencePrior.cxx | 682 +-- src/recon_buildblock/SPECTUB_Tools.cxx | 1444 +++--- src/recon_buildblock/SPECTUB_Weight3d.cxx | 1847 +++---- src/recon_buildblock/SqrtHessianRowSum.cxx | 118 +- src/recon_buildblock/SymmetryOperation.cxx | 48 +- .../SymmetryOperations_PET_CartesianGrid.cxx | 719 ++- .../TrivialBinNormalisation.cxx | 4 +- .../TrivialDataSymmetriesForBins.cxx | 92 +- src/recon_buildblock/distributable.cxx | 762 +-- .../distributableMPICacheEnabled.cxx | 403 +- .../distributed_functions.cxx | 1534 +++--- .../distributed_test_functions.cxx | 490 +- .../find_basic_vs_nums_in_subset.cxx | 72 +- .../recon_buildblock_registries.cxx | 37 +- src/recon_test/bcktest.cxx | 497 +- src/recon_test/fwdtest.cxx | 617 +-- src/recon_test/recontest.cxx | 104 +- ...ataSymmetriesForBins_PET_CartesianGrid.cxx | 1079 ++-- src/recon_test/test_FBP2D.cxx | 81 +- src/recon_test/test_FBP3DRP.cxx | 74 +- src/recon_test/test_OSMAPOSL.cxx | 80 +- ...ihoodWithLinearModelForMeanAndProjData.cxx | 347 +- .../test_blocks_on_cylindrical_projectors.cxx | 125 +- src/recon_test/test_consistency_with_GATE.cxx | 207 +- .../test_data_processor_projectors.cxx | 483 +- src/recon_test/test_priors.cxx | 363 +- .../CreateTailMaskFromACFs.cxx | 221 +- src/scatter_buildblock/ScatterEstimation.cxx | 1800 ++++--- src/scatter_buildblock/ScatterSimulation.cxx | 1324 +++-- .../SingleScatterSimulation.cxx | 87 +- .../cached_single_scatter_integrals.cxx | 177 +- src/scatter_buildblock/extradebug.cxx | 102 +- .../sample_scatter_points.cxx | 68 +- .../scatter_detection_modelling.cxx | 186 +- ...scatter_estimate_for_one_scatter_point.cxx | 146 +- .../single_scatter_estimate.cxx | 44 +- .../single_scatter_integrals.cxx | 128 +- .../upsample_and_fit_scatter_estimate.cxx | 131 +- .../create_tail_mask_from_ACFs.cxx | 141 +- src/scatter_utilities/estimate_scatter.cxx | 45 +- src/scatter_utilities/simulate_scatter.cxx | 75 +- .../upsample_and_fit_single_scatter.cxx | 145 +- .../GatedSpatialTransformation.cxx | 252 +- .../InvertAxis.cxx | 137 +- .../SpatialTransformation.cxx | 25 +- .../spatial_transformation_registries.cxx | 19 +- .../warp_image.cxx | 87 +- src/test/IO/test_IO_DiscretisedDensity.cxx | 76 +- .../IO/test_IO_DynamicDiscretisedDensity.cxx | 139 +- src/test/IO/test_IO_ITKMulticomponent.cxx | 67 +- .../test_IO_ParametricDiscretisedDensity.cxx | 146 +- .../test_ProjectorNiftyPET_adjoint.cxx | 577 ++- .../test_ParametricDiscretisedDensity.cxx | 189 +- src/test/modelling/test_modelling.cxx | 287 +- src/test/numerics/BSplines_timing.cxx | 369 +- src/test/numerics/test_BSplines.cxx | 733 ++- .../numerics/test_BSplinesRegularGrid.cxx | 958 ++-- .../numerics/test_BSplinesRegularGrid1D.cxx | 431 +- src/test/numerics/test_Fourier.cxx | 109 +- src/test/numerics/test_IR_filters.cxx | 168 +- src/test/numerics/test_erf.cxx | 150 +- .../test_integrate_discrete_function.cxx | 104 +- src/test/numerics/test_matrices.cxx | 454 +- .../numerics/test_overlap_interpolate.cxx | 264 +- src/test/test_ArcCorrection.cxx | 219 +- src/test/test_Array.cxx | 742 ++- src/test/test_ArrayFilter.cxx | 545 +- src/test/test_ByteOrder.cxx | 14 +- src/test/test_DateTime.cxx | 97 +- src/test/test_DetectionPosition.cxx | 22 +- src/test/test_DetectorCoordinateMap.cxx | 223 +- src/test/test_DynamicDiscretisedDensity.cxx | 497 +- .../test_GeneralisedPoissonNoiseGenerator.cxx | 39 +- src/test/test_ImagingModality.cxx | 5 +- src/test/test_IndexRange.cxx | 105 +- src/test/test_KeyParser.cxx | 35 +- src/test/test_ML_norm.cxx | 104 +- src/test/test_NestedIterator.cxx | 393 +- src/test/test_OutputFileFormat.cxx | 172 +- src/test/test_ROIs.cxx | 376 +- src/test/test_Scanner.cxx | 147 +- src/test/test_ScatterSimulation.cxx | 694 ++- .../test_SeparableGaussianArrayFilter.cxx | 65 +- src/test/test_SeparableMetzArrayFilter.cxx | 62 +- src/test/test_VectorWithOffset.cxx | 932 ++-- src/test/test_VoxelsOnCartesianGrid.cxx | 293 +- src/test/test_convert_array.cxx | 179 +- src/test/test_coordinates.cxx | 297 +- src/test/test_display.cxx | 73 +- src/test/test_export_array.cxx | 436 +- src/test/test_filename_functions.cxx | 631 ++- src/test/test_find_fwhm_in_image.cxx | 376 +- src/test/test_interpolate.cxx | 218 +- src/test/test_interpolate_projdata.cxx | 456 +- src/test/test_linear_regression.cxx | 264 +- src/test/test_multiple_proj_data.cxx | 97 +- src/test/test_proj_data.cxx | 331 +- src/test/test_proj_data_in_memory.cxx | 234 +- src/test/test_proj_data_info.cxx | 356 +- src/test/test_proj_data_info_subsets.cxx | 220 +- src/test/test_proj_data_maths.cxx | 159 +- src/test/test_radionuclide.cxx | 25 +- src/test/test_stir_math.cxx | 334 +- src/test/test_time_of_flight.cxx | 614 +-- src/test/test_warp_image.cxx | 181 +- src/test/test_zoom_image.cxx | 130 +- src/utilities/GE/print_GE_singles_values.cxx | 56 +- src/utilities/SPECT_dicom_to_interfile.cxx | 615 ++- src/utilities/SSRB.cxx | 79 +- .../UPENN/conv_UPENN_projdata_to_STIR.cxx | 348 +- src/utilities/abs_image.cxx | 161 +- src/utilities/apply_normfactors.cxx | 161 +- src/utilities/apply_normfactors3D.cxx | 4 +- ...ttenuation_coefficients_to_projections.cxx | 106 +- src/utilities/back_project.cxx | 55 +- .../calculate_attenuation_coefficients.cxx | 133 +- src/utilities/compare_image.cxx | 160 +- src/utilities/compare_projdata.cxx | 157 +- .../compute_sqrt_Hessian_row_sum.cxx | 16 +- .../construct_randoms_from_GEsingles.cxx | 25 +- .../construct_randoms_from_singles.cxx | 49 +- ...nv_GATE_raw_ECAT_projdata_to_interfile.cxx | 138 +- src/utilities/conv_gipl_to_interfile.cxx | 235 +- src/utilities/conv_interfile_to_gipl.cxx | 199 +- src/utilities/convert_to_binary_image.cxx | 52 +- src/utilities/correct_projdata.cxx | 438 +- src/utilities/create_multi_header.cxx | 40 +- src/utilities/create_projdata_template.cxx | 32 +- src/utilities/ctac_to_mu_values.cxx | 124 +- src/utilities/display_projdata.cxx | 64 +- src/utilities/do_linear_regression.cxx | 101 +- src/utilities/ecat/conv_to_ecat6.cxx | 408 +- src/utilities/ecat/conv_to_ecat7.cxx | 424 +- src/utilities/ecat/convecat6_if.cxx | 214 +- src/utilities/ecat/copy_ecat7_header.cxx | 568 +- src/utilities/ecat/ecat_swap_corners.cxx | 254 +- src/utilities/ecat/ifheaders_for_ecat7.cxx | 88 +- src/utilities/ecat/is_ecat7_file.cxx | 76 +- .../ecat/print_ecat_singles_values.cxx | 104 +- ..._triple_energy_window_scatter_sinogram.cxx | 199 +- src/utilities/extract_segments.cxx | 88 +- ...tract_single_images_from_dynamic_image.cxx | 114 +- src/utilities/find_ML_normfactors.cxx | 349 +- src/utilities/find_ML_normfactors3D.cxx | 109 +- .../find_ML_singles_from_delayed.cxx | 230 +- src/utilities/find_fwhm_in_image.cxx | 145 +- src/utilities/find_maxima_in_image.cxx | 173 +- .../find_normfactors_from_cylinder_data.cxx | 200 +- ...ents_in_image_quality_phantom_nema_nu4.cxx | 380 +- ...um_projection_of_viewgram_and_sinogram.cxx | 105 +- src/utilities/forward_project.cxx | 67 +- src/utilities/generate_image.cxx | 18 +- src/utilities/get_time_frame_info.cxx | 144 +- src/utilities/invert_axis.cxx | 45 +- src/utilities/list_ROI_values.cxx | 270 +- src/utilities/list_detector_and_bin_info.cxx | 70 +- src/utilities/list_image_info.cxx | 139 +- src/utilities/list_image_values.cxx | 110 +- src/utilities/list_projdata_info.cxx | 147 +- src/utilities/manip_image.cxx | 909 ++-- src/utilities/manip_projdata.cxx | 753 +-- src/utilities/poisson_noise.cxx | 65 +- src/utilities/postfilter.cxx | 225 +- src/utilities/rebin_projdata.cxx | 75 +- ...rate_true_from_random_scatter_for_necr.cxx | 358 +- src/utilities/shift_image.cxx | 126 +- src/utilities/shift_image_origin.cxx | 59 +- src/utilities/stir_config.cxx | 40 +- src/utilities/stir_list_registries.cxx | 29 +- src/utilities/stir_math.cxx | 771 +-- src/utilities/stir_timings.cxx | 23 +- src/utilities/stir_write_pgm.cxx | 209 +- .../warp_and_accumulate_gated_images.cxx | 39 +- src/utilities/warp_image.cxx | 73 +- src/utilities/write_proj_matrix_by_bin.cxx | 90 +- src/utilities/write_sinogram_to_txt.cxx | 93 +- src/utilities/zeropad_planes.cxx | 79 +- src/utilities/zoom_image.cxx | 158 +- 1181 files changed, 109161 insertions(+), 116793 deletions(-) mode change 100755 => 100644 src/buildblock/GeometryBlocksOnCylindrical.cxx mode change 100755 => 100644 src/buildblock/ProjDataInfoGeneric.cxx mode change 100755 => 100644 src/data_buildblock/SinglesRatesFromGEHDF5.cxx mode change 100755 => 100644 src/include/stir/data/SinglesRatesFromGEHDF5.h mode change 100755 => 100644 src/listmode_utilities/conv_NiftyPET_stir.cxx mode change 100755 => 100644 src/utilities/UPENN/conv_UPENN_projdata_to_STIR.cxx mode change 100755 => 100644 src/utilities/construct_randoms_from_GEsingles.cxx mode change 100755 => 100644 src/utilities/invert_axis.cxx diff --git a/examples/C++/General_Reconstruction/General_Reconstruction.cxx b/examples/C++/General_Reconstruction/General_Reconstruction.cxx index 277dc792f..1926455b8 100644 --- a/examples/C++/General_Reconstruction/General_Reconstruction.cxx +++ b/examples/C++/General_Reconstruction/General_Reconstruction.cxx @@ -5,53 +5,50 @@ #include START_NAMESPACE_STIR -General_Reconstruction:: -General_Reconstruction() +General_Reconstruction::General_Reconstruction() { - this->set_defaults(); + this->set_defaults(); } void General_Reconstruction::set_defaults() -{ - -} +{} void General_Reconstruction::initialise_keymap() { - this->parser.add_start_key("General reconstruction"); - this->parser.add_stop_key("End General reconstruction"); + 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; + 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; - } + 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 a97321c60..b49fa29ab 100644 --- a/examples/C++/General_Reconstruction/General_Reconstruction.h +++ b/examples/C++/General_Reconstruction/General_Reconstruction.h @@ -16,7 +16,6 @@ #include "stir/CartesianCoordinate3D.h" #include "Reconstruction.h" - START_NAMESPACE_STIR class Succeeded; @@ -24,23 +23,20 @@ class Succeeded; 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++/using_STIR_LOCAL/demo1.cxx b/examples/C++/using_STIR_LOCAL/demo1.cxx index 8162c8ded..42f279132 100644 --- a/examples/C++/using_STIR_LOCAL/demo1.cxx +++ b/examples/C++/using_STIR_LOCAL/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 */ @@ -35,25 +35,21 @@ #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++/using_STIR_LOCAL/demo2.cxx b/examples/C++/using_STIR_LOCAL/demo2.cxx index 411c3fbc4..68fd828b4 100644 --- a/examples/C++/using_STIR_LOCAL/demo2.cxx +++ b/examples/C++/using_STIR_LOCAL/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,26 @@ #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++/using_STIR_LOCAL/demo3.cxx b/examples/C++/using_STIR_LOCAL/demo3.cxx index ec2ecba3d..4df712be0 100644 --- a/examples/C++/using_STIR_LOCAL/demo3.cxx +++ b/examples/C++/using_STIR_LOCAL/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 */ @@ -39,9 +39,10 @@ #include "stir/display.h" #include -namespace stir { +namespace stir +{ -class MyStuff: public ParsingObject +class MyStuff : public ParsingObject { public: void set_defaults(); @@ -52,7 +53,7 @@ class MyStuff: public ParsingObject 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 @@ -60,10 +61,10 @@ MyStuff::set_defaults() { auto projection_matrix_sptr = std::make_shared(); back_projector_sptr = std::make_shared(projection_matrix_sptr); - output_file_format_sptr = OutputFileFormat >::default_sptr(); + output_file_format_sptr = OutputFileFormat>::default_sptr(); } -void +void MyStuff::initialise_keymap() { parser.add_start_key("MyStuff parameters"); @@ -78,13 +79,10 @@ void MyStuff::run(const bool display_off) { - 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); @@ -100,28 +98,29 @@ MyStuff::run(const bool display_off) 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; MyStuff my_stuff; my_stuff.set_defaults(); bool display_off = false; - if (argc<2) - { - std::cerr << "Normal usage: " << argv[0] << " parameter-file [--display_off]\n"; - std::cerr << "I will now ask you the questions interactively\n"; - my_stuff.ask_parameters(); - } + if (argc < 2) + { + std::cerr << "Normal usage: " << argv[0] << " parameter-file [--display_off]\n"; + std::cerr << "I will now ask you the questions interactively\n"; + my_stuff.ask_parameters(); + } else - { - my_stuff.parse(argv[1]); - if (argc>=3) - // Set the display_off to true if the second argument is "--display_off" - display_off = (strcmp(argv[2], "--display_off")==0); - } + { + my_stuff.parse(argv[1]); + if (argc >= 3) + // Set the display_off to true if the second argument is "--display_off" + display_off = (strcmp(argv[2], "--display_off") == 0); + } my_stuff.run(display_off); return EXIT_SUCCESS; } diff --git a/examples/C++/using_STIR_LOCAL/demo4_obj_fun.cxx b/examples/C++/using_STIR_LOCAL/demo4_obj_fun.cxx index 041fc9a5e..791b6de94 100644 --- a/examples/C++/using_STIR_LOCAL/demo4_obj_fun.cxx +++ b/examples/C++/using_STIR_LOCAL/demo4_obj_fun.cxx @@ -21,12 +21,12 @@ See README.txt in the directory where this file is located. - \author Kris Thielemans and Robert Twyman + \author Kris Thielemans and Robert Twyman */ /* Copyright (C) 2020 University College London - 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 */ @@ -37,25 +37,26 @@ #include "stir/is_null_ptr.h" #include "stir/error.h" -namespace stir { +namespace stir +{ -class MyStuff: public ParsingObject +class MyStuff : public ParsingObject { public: MyStuff(); void set_defaults(); void run(); - typedef DiscretisedDensity<3,float> 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(); }; @@ -69,12 +70,12 @@ void 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 +void MyStuff::initialise_keymap() { parser.add_start_key("MyStuff parameters"); @@ -86,14 +87,14 @@ MyStuff::initialise_keymap() parser.add_stop_key("End"); } -bool MyStuff:: -post_processing() +bool +MyStuff::post_processing() { if (is_null_ptr(this->objective_function_sptr)) - { + { error("objective_function_sptr is null"); return true; - } + } return false; } @@ -101,12 +102,10 @@ void 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); @@ -117,41 +116,43 @@ MyStuff::run() /////// Iteratively compute and add objective function gradients to density_sptr /////// Update formula: x_{k+1} = x_k + step_size * gradient /////// Note the lack of positivity constraint on the images. - for (int k = 0; k < num_iterations; k++) { - std::cout << "Iteration number: " << k << "\n"; - objective_function_sptr->compute_sub_gradient(*gradient_sptr, *density_sptr, 0); - *density_sptr += (*gradient_sptr) * step_size; - - /////// save density and estimates - std::string density_filename = "demo4_density_" + std::to_string(k); - std::string gradient_filename = "demo4_gradient_" + std::to_string(k); - output_file_format_sptr->write_to_file(density_filename, *density_sptr); - output_file_format_sptr->write_to_file(gradient_filename, *gradient_sptr); - } + for (int k = 0; k < num_iterations; k++) + { + std::cout << "Iteration number: " << k << "\n"; + objective_function_sptr->compute_sub_gradient(*gradient_sptr, *density_sptr, 0); + *density_sptr += (*gradient_sptr) * step_size; + + /////// save density and estimates + std::string density_filename = "demo4_density_" + std::to_string(k); + std::string gradient_filename = "demo4_gradient_" + std::to_string(k); + output_file_format_sptr->write_to_file(density_filename, *density_sptr); + output_file_format_sptr->write_to_file(gradient_filename, *gradient_sptr); + } /////// Compute objective function value of image + gradient const double my_objective_function_value2 = objective_function_sptr->compute_objective_function(*density_sptr); /////// 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) + 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/C++/using_STIR_LOCAL/demo5_line_search.cxx b/examples/C++/using_STIR_LOCAL/demo5_line_search.cxx index b40a3ea8d..66a9315f7 100644 --- a/examples/C++/using_STIR_LOCAL/demo5_line_search.cxx +++ b/examples/C++/using_STIR_LOCAL/demo5_line_search.cxx @@ -48,9 +48,8 @@ compute_linear_alphas(const float alpha_min, const float alpha_max, const float float d_alpha = (alpha_max - alpha_min) / num_evaluations; std::cout << "\nComputing linear alphas:" - "\n alpha_min = " << alpha_min << - "\n alpha_max = " << alpha_max << - "\n delta_alpha = " << d_alpha << "\n"; + "\n alpha_min = " + << alpha_min << "\n alpha_max = " << alpha_max << "\n delta_alpha = " << d_alpha << "\n"; /// Explicitly add alpha = 0.0 and/or alpha_min alphas.push_back(0.0); @@ -64,7 +63,6 @@ compute_linear_alphas(const float alpha_min, const float alpha_max, const float return alphas; } - std::vector compute_exponential_alphas(const float alpha_min, const float alpha_max, const float num_evaluations) { @@ -73,9 +71,8 @@ compute_exponential_alphas(const float alpha_min, const float alpha_max, const f float d_alpha = (alpha_max - alpha_min) / num_evaluations; std::cout << "\nComputing exponential alphas:" - "\n exponential min = " << alpha_min << - "\n exponential max = " << alpha_max << - "\n exponential delta = " << d_alpha << "\n"; + "\n exponential min = " + << alpha_min << "\n exponential max = " << alpha_max << "\n exponential delta = " << d_alpha << "\n"; /// Explicitly add alpha = 0.0 and/or alpha_min alphas.push_back(0.0); @@ -87,65 +84,65 @@ compute_exponential_alphas(const float alpha_min, const float alpha_max, const f return alphas; } - void save_doubles_vector_to_file(std::string filename, std::vector vector) { /// This function is used to save the line search results (alpha and Phi values) to separate files. - std::ofstream myfile (filename); + std::ofstream myfile(filename); int precision = 40; - if (myfile.is_open()){ - for (double v : vector){ - myfile << std::fixed << std::setprecision(precision) << v << std::endl; + if (myfile.is_open()) + { + for (double v : vector) + { + myfile << std::fixed << std::setprecision(precision) << v << std::endl; + } + myfile.close(); } - myfile.close(); - } } - using namespace stir; -class LineSearcher: public ParsingObject +class LineSearcher : public ParsingObject { public: - LineSearcher(); - /// Methods - void set_defaults(); - void setup(); - double compute_line_search_value(const double alpha); - void apply_update_step(const double alpha); - void perform_line_search(); - void save_data(); - void save_max_line_search_image(); - - typedef DiscretisedDensity<3,float> target_type; - - /// Class variables - int num_evaluations; - float alpha_min; - float alpha_max; - bool use_exponential_alphas; - double image_lower_bound; - - /// Measurements - std::vector alphas; - std::vector Phis; - - /// Image volumes - shared_ptr > image_sptr; - shared_ptr > gradient_sptr; - shared_ptr > eval_image_sptr; + LineSearcher(); + /// Methods + void set_defaults(); + void setup(); + double compute_line_search_value(const double alpha); + void apply_update_step(const double alpha); + void perform_line_search(); + void save_data(); + void save_max_line_search_image(); + + typedef DiscretisedDensity<3, float> target_type; + + /// Class variables + int num_evaluations; + float alpha_min; + float alpha_max; + bool use_exponential_alphas; + double image_lower_bound; + + /// Measurements + std::vector alphas; + std::vector Phis; + + /// Image volumes + shared_ptr> image_sptr; + shared_ptr> gradient_sptr; + shared_ptr> eval_image_sptr; protected: - shared_ptr > objective_function_sptr; + shared_ptr> objective_function_sptr; private: - void initialise_keymap(); - bool post_processing(); + void initialise_keymap(); + bool post_processing(); - std::string image_filename; - bool is_setup; - shared_ptr > > output_file_format_sptr; + std::string image_filename; + bool is_setup; + shared_ptr>> output_file_format_sptr; }; LineSearcher::LineSearcher() @@ -153,7 +150,6 @@ LineSearcher::LineSearcher() set_defaults(); } - void LineSearcher::set_defaults() { @@ -164,10 +160,9 @@ LineSearcher::set_defaults() use_exponential_alphas = false; is_setup = false; image_lower_bound = 0.0; - output_file_format_sptr = OutputFileFormat >::default_sptr(); + output_file_format_sptr = OutputFileFormat>::default_sptr(); } - void LineSearcher::initialise_keymap() { @@ -182,21 +177,19 @@ LineSearcher::initialise_keymap() parser.add_stop_key("End"); } - -bool LineSearcher:: -post_processing() +bool +LineSearcher::post_processing() { if (is_null_ptr(this->objective_function_sptr)) - { - error("objective_function_sptr is null"); - return true; - } + { + error("objective_function_sptr is null"); + return true; + } return false; } - -void LineSearcher:: -setup() +void +LineSearcher::setup() { /// Setup LineSearcher this->is_setup = false; @@ -206,7 +199,7 @@ setup() error("LineSearcher setup. No image filename has been given."); std::cout << "Loading image: \n " << image_filename << "\n"; - this->image_sptr = read_from_file >(image_filename); + this->image_sptr = read_from_file>(image_filename); /// Gradient it copied density filled with 0's this->gradient_sptr.reset(this->image_sptr->get_empty_copy()); @@ -222,9 +215,9 @@ setup() this->is_setup = true; } - void -LineSearcher::perform_line_search() { +LineSearcher::perform_line_search() +{ /// Performs the line search /// Gets the step sizes /// Computes the objective function value of the image at every step size @@ -234,12 +227,12 @@ LineSearcher::perform_line_search() { error("LineSearcher is not setup, please run setup()"); double Phi; // Used to store objective function values of each iterate - std::cout << "Computing objective function values of alphas from " << this->alpha_min << " to " - << this->alpha_max << " in increments of " << this->num_evaluations << "\n"; + std::cout << "Computing objective function values of alphas from " << this->alpha_min << " to " << this->alpha_max + << " in increments of " << this->num_evaluations << "\n"; /// get alpha values as a vector { - if ( this->use_exponential_alphas ) + if (this->use_exponential_alphas) alphas = compute_exponential_alphas(this->alpha_min, this->alpha_max, this->num_evaluations); else alphas = compute_linear_alphas(this->alpha_min, this->alpha_max, this->num_evaluations); @@ -247,29 +240,26 @@ LineSearcher::perform_line_search() { /// Iterate over each of the alphas and compute Phi for (auto a = alphas.begin(); a != alphas.end(); ++a) - { - Phi = this->compute_line_search_value(*a); - Phis.push_back(Phi); - std::cout << "alpha = " << *a << ". Phi = " << Phi << "\n"; - } + { + Phi = this->compute_line_search_value(*a); + Phis.push_back(Phi); + std::cout << "alpha = " << *a << ". Phi = " << Phi << "\n"; + } /// Output alpha and Phi values to console std::cout << "\n\n====================================\n" "Alpha and Phi values: \n"; - for (int i = 0 ; i < alphas.size() ; ++i) + for (int i = 0; i < alphas.size(); ++i) std::cout << std::setprecision(20) << " alpha = " << alphas[i] << ". Phis = " << Phis[i] << "\n"; - } - double LineSearcher::compute_line_search_value(const double alpha) { /// For a given alpha, computes the objective function value at the update step apply_update_step(alpha); - std::cout << "\nimage_min = " << image_sptr->find_min() - << "\ngrad_min = " << gradient_sptr->find_min() + std::cout << "\nimage_min = " << image_sptr->find_min() << "\ngrad_min = " << gradient_sptr->find_min() << "\neval_min = " << eval_image_sptr->find_min() << "\n"; return objective_function_sptr->compute_objective_function(*eval_image_sptr); } @@ -283,7 +273,6 @@ LineSearcher::apply_update_step(const double alpha) this->eval_image_sptr->apply_lower_threshold(this->image_lower_bound); } - void LineSearcher::save_data() { @@ -299,7 +288,6 @@ LineSearcher::save_data() output_file_format_sptr->write_to_file("LineSearchGradient.hv", *this->gradient_sptr); } - void LineSearcher::save_max_line_search_image() { @@ -308,37 +296,41 @@ LineSearcher::save_max_line_search_image() double max_alpha = alphas[0]; /// Find the alpha Phi combination that is max Phi and save that image. - for (int i = 0 ; i < alphas.size() ; ++i){ - if (Phis[i] > max_Phi){ - max_Phi = Phis[i]; - max_alpha = alphas[i]; + for (int i = 0; i < alphas.size(); ++i) + { + if (Phis[i] > max_Phi) + { + max_Phi = Phis[i]; + max_alpha = alphas[i]; + } } - } /// Check if alpha == 0 is optimal, otherwise save the image at the maximum evaluation. if (max_alpha != alphas[0]) - { - apply_update_step(max_alpha); - std::cout << "Saving max line search value image, computed at alpha = " << max_alpha << "\n" - << "and Phi = " << max_Phi << '\n'; - output_file_format_sptr->write_to_file("MaxObjectiveFunctionImage.hv", *this->eval_image_sptr); - } else { - std::cout << "Max line search value image is at alpha = 0.0\n"; - } + { + apply_update_step(max_alpha); + std::cout << "Saving max line search value image, computed at alpha = " << max_alpha << "\n" + << "and Phi = " << max_Phi << '\n'; + output_file_format_sptr->write_to_file("MaxObjectiveFunctionImage.hv", *this->eval_image_sptr); + } + else + { + std::cout << "Max line search value image is at alpha = 0.0\n"; + } } - -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"; + } LineSearcher my_stuff; - if (argc!=2) + if (argc != 2) my_stuff.ask_parameters(); else my_stuff.parse(argv[1]); diff --git a/examples/C++/using_installed_STIR/demo_create_image.cxx b/examples/C++/using_installed_STIR/demo_create_image.cxx index f3d391c9b..ffc3c53ea 100644 --- a/examples/C++/using_installed_STIR/demo_create_image.cxx +++ b/examples/C++/using_installed_STIR/demo_create_image.cxx @@ -25,7 +25,8 @@ #include "stir/VoxelsOnCartesianGrid.h" #include -int main() +int +main() { std::string output_filename("test.hv"); @@ -36,7 +37,7 @@ int main() float output_voxel_size_y = 4.F; float output_voxel_size_z = 3.F; double image_duration = 100.; // secs - double rel_start_time = 1; //secs + double rel_start_time = 1; // secs auto exam_info_sptr = std::make_shared(stir::ImagingModality::PT); { @@ -45,24 +46,22 @@ int main() frame_defs.set_time_frame(1, rel_start_time, image_duration); exam_info_sptr->set_time_frame_definitions(frame_defs); } - stir::VoxelsOnCartesianGrid - image(exam_info_sptr, - stir::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), - stir::CartesianCoordinate3D(0,0,0), - stir::CartesianCoordinate3D(output_voxel_size_z, - output_voxel_size_y, - output_voxel_size_x)); + stir::VoxelsOnCartesianGrid image( + exam_info_sptr, + stir::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), + stir::CartesianCoordinate3D(0, 0, 0), + stir::CartesianCoordinate3D(output_voxel_size_z, output_voxel_size_y, output_voxel_size_x)); // add shape to image { - const auto centre = - image.get_physical_coordinates_for_indices(stir::make_coordinate(output_image_size_z/2,0,0)); + const auto centre = image.get_physical_coordinates_for_indices(stir::make_coordinate(output_image_size_z / 2, 0, 0)); stir::EllipsoidalCylinder shape(40.F, 30.F, 20.F, centre); - shape.construct_volume(image, stir::make_coordinate(2,2,2)); + shape.construct_volume(image, stir::make_coordinate(2, 2, 2)); } // write output for checking @@ -75,5 +74,5 @@ int main() { return EXIT_FAILURE; } - return EXIT_SUCCESS; + return EXIT_SUCCESS; } diff --git a/src/IO/ECAT6OutputFileFormat.cxx b/src/IO/ECAT6OutputFileFormat.cxx index 68bbd0762..89bc80537 100644 --- a/src/IO/ECAT6OutputFileFormat.cxx +++ b/src/IO/ECAT6OutputFileFormat.cxx @@ -29,22 +29,17 @@ START_NAMESPACE_STIR START_NAMESPACE_ECAT START_NAMESPACE_ECAT6 +const char* const ECAT6OutputFileFormat::registered_name = "ECAT6"; -const char * const -ECAT6OutputFileFormat::registered_name = "ECAT6"; - -ECAT6OutputFileFormat:: -ECAT6OutputFileFormat(const NumericType& type, - const ByteOrder& byte_order) +ECAT6OutputFileFormat::ECAT6OutputFileFormat(const NumericType& type, const ByteOrder& byte_order) { base_type::set_defaults(); set_type_of_numbers(type); set_byte_order(byte_order); } -void -ECAT6OutputFileFormat:: -initialise_keymap() +void +ECAT6OutputFileFormat::initialise_keymap() { parser.add_start_key("ECAT6 Output File Format Parameters"); parser.add_stop_key("End ECAT6 Output File Format Parameters"); @@ -52,103 +47,84 @@ initialise_keymap() base_type::initialise_keymap(); } -void -ECAT6OutputFileFormat:: -set_defaults() +void +ECAT6OutputFileFormat::set_defaults() { default_scanner_name = "ECAT 953"; base_type::set_defaults(); file_byte_order = ByteOrder::little_endian; type_of_numbers = NumericType::SHORT; - } bool -ECAT6OutputFileFormat:: -post_processing() +ECAT6OutputFileFormat::post_processing() { if (base_type::post_processing()) return true; - shared_ptr 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) + if (find_ECAT_system_type(*scanner_ptr) == 0) { - warning("ECAT6OutputFileFormat: default_scanner_name %s is not supported\n", - default_scanner_name.c_str()); + 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) +NumericType +ECAT6OutputFileFormat::set_type_of_numbers(const NumericType& new_type, const bool warn) { - const NumericType supported_type_of_numbers = - NumericType("signed integer", 2); + 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; - } + { + 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 type_of_numbers = new_type; return type_of_numbers; - } -ByteOrder -ECAT6OutputFileFormat:: -set_byte_order(const ByteOrder& new_byte_order, const bool warn) +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; - } + { + if (warn) + warning("ECAT6OutputFileFormat: byte_order is currently fixed to little-endian\n"); + file_byte_order = ByteOrder::little_endian; + } 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 +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)); - + 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); + + 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*/); + { + 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*/); 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 6009369b6..e019db573 100644 --- a/src/IO/ECAT7DynamicDiscretisedDensityInputFileFormat.cxx +++ b/src/IO/ECAT7DynamicDiscretisedDensityInputFileFormat.cxx @@ -27,9 +27,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" @@ -42,10 +41,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; @@ -56,38 +53,32 @@ actual_can_read(const FileSignature& signature, } unique_ptr -ECAT7DynamicDiscretisedDensityInputFileFormat:: -read_from_file(std::istream& input) const +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(); + // 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 +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(); - } + { + 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) - ); + 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); @@ -98,17 +89,18 @@ read_from_file(const std::string& filename) const // 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 ); - } + 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 @@ -122,4 +114,3 @@ read_from_file(const std::string& filename) const END_NAMESPACE_ECAT END_NAMESPACE_ECAT7 END_NAMESPACE_STIR - diff --git a/src/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.cxx b/src/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.cxx index 8e3c592e4..3ed0b1343 100644 --- a/src/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.cxx +++ b/src/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.cxx @@ -28,21 +28,18 @@ 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"); @@ -50,9 +47,8 @@ initialise_keymap() base_type::initialise_keymap(); } -void -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -set_defaults() +void +ECAT7DynamicDiscretisedDensityOutputFileFormat::set_defaults() { this->default_scanner_name = "ECAT 962"; base_type::set_defaults(); @@ -63,69 +59,62 @@ 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) + if (find_ECAT_system_type(*scanner_ptr) == 0) { warning("ECAT7DynamicDiscretisedDensityOutputFileFormat: default_scanner_name %s is not supported\n", - this->default_scanner_name.c_str()); + this->default_scanner_name.c_str()); return true; } return false; } -NumericType -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -set_type_of_numbers(const NumericType& new_type, const bool warn) +NumericType +ECAT7DynamicDiscretisedDensityOutputFileFormat::set_type_of_numbers(const NumericType& new_type, const bool warn) { - const NumericType supported_type_of_numbers = - NumericType("signed integer", 2); + 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"); - this->type_of_numbers = supported_type_of_numbers; - } + { + if (warn) + 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 this->type_of_numbers = new_type; return this->type_of_numbers; } -ByteOrder -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -set_byte_order(const ByteOrder& new_byte_order, const bool warn) +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; - } + { + if (warn) + warning("ECAT7DynamicDiscretisedDensityOutputFileFormat: byte_order is currently fixed to big-endian\n"); + this->file_byte_order = ByteOrder::big_endian; + } 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 defdc3238..28e13e3c0 100644 --- a/src/IO/ECAT7OutputFileFormat.cxx +++ b/src/IO/ECAT7OutputFileFormat.cxx @@ -27,21 +27,17 @@ 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"); @@ -49,9 +45,8 @@ initialise_keymap() base_type::initialise_keymap(); } -void -ECAT7OutputFileFormat:: -set_defaults() +void +ECAT7OutputFileFormat::set_defaults() { default_scanner_name = "ECAT 962"; base_type::set_defaults(); @@ -59,88 +54,76 @@ set_defaults() 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) + if (find_ECAT_system_type(*scanner_ptr) == 0) { - warning("ECAT7OutputFileFormat: default_scanner_name %s is not supported\n", - default_scanner_name.c_str()); + 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) +NumericType +ECAT7OutputFileFormat::set_type_of_numbers(const NumericType& new_type, const bool warn) { - const NumericType supported_type_of_numbers = - NumericType("signed integer", 2); + 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; - } + { + 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 type_of_numbers = new_type; return type_of_numbers; - } -ByteOrder -ECAT7OutputFileFormat:: -set_byte_order(const ByteOrder& new_byte_order, const bool warn) +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; - } + { + if (warn) + warning("ECAT7OutputFileFormat: byte_order is currently fixed to big-endian\n"); + file_byte_order = ByteOrder::big_endian; + } 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); + 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*/); + { + 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*/); matrix_close(mptr); - + return success; } diff --git a/src/IO/ECAT7ParametricDensityOutputFileFormat.cxx b/src/IO/ECAT7ParametricDensityOutputFileFormat.cxx index 9da8ca8a8..b731d5d9c 100644 --- a/src/IO/ECAT7ParametricDensityOutputFileFormat.cxx +++ b/src/IO/ECAT7ParametricDensityOutputFileFormat.cxx @@ -28,13 +28,11 @@ 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); @@ -42,9 +40,8 @@ ECAT7ParametricDensityOutputFileFormat(const NumericType& type, } 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"); @@ -53,9 +50,8 @@ initialise_keymap() } template -void -ECAT7ParametricDensityOutputFileFormat:: -set_defaults() +void +ECAT7ParametricDensityOutputFileFormat::set_defaults() { this->default_scanner_name = "ECAT 962"; base_type::set_defaults(); @@ -63,24 +59,21 @@ set_defaults() 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) + if (find_ECAT_system_type(*scanner_ptr) == 0) { warning("ECAT7ParametricDensityOutputFileFormat: default_scanner_name %s is not supported\n", - this->default_scanner_name.c_str()); + this->default_scanner_name.c_str()); return true; } @@ -88,54 +81,47 @@ post_processing() } template -NumericType -ECAT7ParametricDensityOutputFileFormat:: -set_type_of_numbers(const NumericType& new_type, const bool warn) +NumericType +ECAT7ParametricDensityOutputFileFormat::set_type_of_numbers(const NumericType& new_type, const bool warn) { - const NumericType supported_type_of_numbers = - NumericType("signed integer", 2); + 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"); - this->type_of_numbers = supported_type_of_numbers; - } + { + if (warn) + 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 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) +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; - } + { + if (warn) + warning("ECAT7ParametricDensityOutputFileFormat: byte_order is currently fixed to big-endian\n"); + this->file_byte_order = ByteOrder::big_endian; + } 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 +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)); - + 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; @@ -146,34 +132,31 @@ 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); + + 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); + { + 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; - } + { + 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 130ed98ec..45978ba2e 100644 --- a/src/IO/GEHDF5Wrapper.cxx +++ b/src/IO/GEHDF5Wrapper.cxx @@ -32,15 +32,16 @@ #include "stir/error.h" #include - START_NAMESPACE_STIR -namespace GE { -namespace RDF_HDF5 { +namespace GE +{ +namespace RDF_HDF5 +{ std::uint32_t GEHDF5Wrapper::read_dataset_uint32(const std::string& dataset_name) { - std::uint32_t tmp=0U; + std::uint32_t tmp = 0U; H5::DataSet dataset = file.openDataSet(dataset_name); dataset.read(&tmp, H5::PredType::NATIVE_UINT32); return tmp; @@ -49,14 +50,14 @@ GEHDF5Wrapper::read_dataset_uint32(const std::string& dataset_name) std::int32_t GEHDF5Wrapper::read_dataset_int32(const std::string& dataset_name) { - std::int32_t tmp=0; + std::int32_t tmp = 0; H5::DataSet dataset = file.openDataSet(dataset_name); dataset.read(&tmp, H5::PredType::NATIVE_INT32); return tmp; } - -static float read_float(const H5::H5File& file, const std::string& dataset) +static float +read_float(const H5::H5File& file, const std::string& dataset) { float tmp = 0.F; H5::DataSet ds = file.openDataSet(dataset.c_str()); @@ -64,532 +65,563 @@ static float read_float(const H5::H5File& file, const std::string& dataset) return tmp; } -bool GEHDF5Wrapper::check_GE_signature(const std::string& filename) +bool +GEHDF5Wrapper::check_GE_signature(const std::string& filename) { - try + try { - if(!H5::H5File::isHdf5(filename)) + if (!H5::H5File::isHdf5(filename)) return false; H5::H5File file; - file.openFile( filename, H5F_ACC_RDONLY ); + file.openFile(filename, H5F_ACC_RDONLY); return (check_GE_signature(file)); } - catch(...) + catch (...) { - return false; - } + return false; + } } -bool GEHDF5Wrapper::check_GE_signature(H5::H5File& file) +bool +GEHDF5Wrapper::check_GE_signature(H5::H5File& file) { - if(file.getId() == -1) - error("File is not open. Aborting"); + 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::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); - H5::DataSet dataset2= file.openDataSet("/HeaderData/ExamData/manufacturer"); - dataset2.read(read_str_manufacturer,vlst); - - if(read_str_manufacturer == "GE MEDICAL SYSTEMS") + if (read_str_manufacturer == "GE MEDICAL SYSTEMS") { - return true; + return true; } - return false; + return false; } bool GEHDF5Wrapper::is_list_file() const { - // have we already checked this? (note: initially set to false in check_file()) - 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; - + // have we already checked this? (note: initially set to false in check_file()) + 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; + 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 ); + // 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"); + 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. + // Not much. } GEHDF5Wrapper::GEHDF5Wrapper(const std::string& filename) { - if(open(filename) == Succeeded::no) - error("GEHDF5Wrapper: Error opening HDF5 file. Abort."); + 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; + 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 +// 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()) + 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_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"); + // 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; + return Succeeded::yes; } - if(is_sino_file()) + if (is_sino_file()) { - is_sino = true; - return Succeeded::yes; + is_sino = true; + return Succeeded::yes; } - if(is_norm_file()) + 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; + 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()) + if (is_geo_file()) { - is_geo=true; - geo_dims = check_geo_type(); - - return Succeeded::yes; + is_geo = true; + geo_dims = check_geo_type(); + + return Succeeded::yes; } - // should not get here. - return Succeeded::no; + // 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."); + 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() +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"); + 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); + + // TOF related + const float timingResolutionInPico = read_float(file, "/HeaderData/SystemGeometry/timingResolutionInPico"); + const int posCoincidenceWindow = read_dataset_int32("/HeaderData/AcqParameters/EDCATParameters/posCoincidenceWindow"); + const int negCoincidenceWindow = read_dataset_int32("/HeaderData/AcqParameters/EDCATParameters/negCoincidenceWindow"); + const float coincTimingPrecisionInPico + = read_float(file, "/HeaderData/AcqParameters/EDCATParameters/coincTimingPrecision") * 1000; // in nanoSecs in file + const int num_tof_bins = posCoincidenceWindow + negCoincidenceWindow + 1; + + 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_intrinsic_azimuthal_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 (timingResolutionInPico > 0 // Signa files seem to have zero in this field + && (fabs(scanner_sptr->get_timing_resolution() - timingResolutionInPico) > .1F)) + { + warning("GEHDF5Wrapper: default STIR timing resolution is " + std::to_string(scanner_sptr->get_timing_resolution()) + + ", while RDF says " + std::to_string(timingResolutionInPico) + + "\nWill adjust scanner info to fit with the RDF file"); + scanner_sptr->set_timing_resolution(timingResolutionInPico); + } + if (fabs(scanner_sptr->get_size_of_timing_pos() - coincTimingPrecisionInPico) > .1F) + { + warning("GEHDF5Wrapper: default STIR size of (unmashed) TOF bins is " + + std::to_string(scanner_sptr->get_size_of_timing_pos()) + ", while RDF says " + + std::to_string(coincTimingPrecisionInPico) + "\nWill adjust scanner info to fit with the RDF file"); + scanner_sptr->set_size_of_timing_poss(coincTimingPrecisionInPico); + } + if (std::abs(scanner_sptr->get_max_num_timing_poss() - num_tof_bins) > 0) + { + warning("GEHDF5Wrapper: default STIR number of (unmashed) TOF bins is " + + std::to_string(scanner_sptr->get_max_num_timing_poss()) + ", while RDF says " + std::to_string(num_tof_bins) + + "\nWill adjust scanner info to fit with the RDF file"); + scanner_sptr->set_max_num_timing_poss(num_tof_bins); + } + 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"); } - 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); - - // TOF related - const float timingResolutionInPico = read_float(file, "/HeaderData/SystemGeometry/timingResolutionInPico"); - const int posCoincidenceWindow = read_dataset_int32("/HeaderData/AcqParameters/EDCATParameters/posCoincidenceWindow"); - const int negCoincidenceWindow = read_dataset_int32("/HeaderData/AcqParameters/EDCATParameters/negCoincidenceWindow"); - const float coincTimingPrecisionInPico = read_float(file, "/HeaderData/AcqParameters/EDCATParameters/coincTimingPrecision") * 1000; // in nanoSecs in file - const int num_tof_bins = posCoincidenceWindow + negCoincidenceWindow + 1; - - 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_intrinsic_azimuthal_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 (timingResolutionInPico > 0 // Signa files seem to have zero in this field - && (fabs(scanner_sptr->get_timing_resolution() - timingResolutionInPico) > .1F)) - { - warning("GEHDF5Wrapper: default STIR timing resolution is " - + std::to_string(scanner_sptr->get_timing_resolution()) - + ", while RDF says " + std::to_string(timingResolutionInPico) - + "\nWill adjust scanner info to fit with the RDF file"); - scanner_sptr->set_timing_resolution(timingResolutionInPico); - } - if (fabs(scanner_sptr->get_size_of_timing_pos() - coincTimingPrecisionInPico)> .1F) - { - warning("GEHDF5Wrapper: default STIR size of (unmashed) TOF bins is " - + std::to_string(scanner_sptr->get_size_of_timing_pos()) - + ", while RDF says " + std::to_string(coincTimingPrecisionInPico) - + "\nWill adjust scanner info to fit with the RDF file"); - scanner_sptr->set_size_of_timing_poss(coincTimingPrecisionInPico); - } - if (std::abs(scanner_sptr->get_max_num_timing_poss() - num_tof_bins) > 0) - { - warning("GEHDF5Wrapper: default STIR number of (unmashed) TOF bins is " - + std::to_string(scanner_sptr->get_max_num_timing_poss()) - + ", while RDF says " + std::to_string(num_tof_bins) - + "\nWill adjust scanner info to fit with the RDF file"); - scanner_sptr->set_max_num_timing_poss(num_tof_bins); - } - 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; + 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->is_list_file() ? 1 : 0 // TODO change when reading sinos as TOF - ); - 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 */ + 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->is_list_file() ? 1 : 0 // TODO change when reading sinos as TOF + ); + 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() +unsigned int +GEHDF5Wrapper::get_num_singles_samples() { - return m_num_singles_samples; + return m_num_singles_samples; } - -void GEHDF5Wrapper::initialise_exam_info() +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); - } - // 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); - - // radionuclide - { - auto rn_name_ds = file.openDataSet("/HeaderData/ExamData/radionuclideName"); - H5::StrType str_type(rn_name_ds); - std::string rn_name; - rn_name_ds.read(rn_name, str_type); - RadionuclideDB radionuclide_db; - Radionuclide radionuclide = radionuclide_db.get_radionuclide(exam_info_sptr->imaging_modality,rn_name); - - const float positron_fraction = read_float(file, "/HeaderData/ExamData/positronFraction"); - const float half_life = read_float(file, "/HeaderData/ExamData/halfLife"); - if (radionuclide.get_half_life(false) < 0) - radionuclide = Radionuclide(rn_name, 511.F, positron_fraction, half_life, exam_info_sptr->imaging_modality); - exam_info_sptr->set_radionuclide(radionuclide); - } + 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); + } + // 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); + + // radionuclide + { + auto rn_name_ds = file.openDataSet("/HeaderData/ExamData/radionuclideName"); + H5::StrType str_type(rn_name_ds); + std::string rn_name; + rn_name_ds.read(rn_name, str_type); + RadionuclideDB radionuclide_db; + Radionuclide radionuclide = radionuclide_db.get_radionuclide(exam_info_sptr->imaging_modality, rn_name); + + const float positron_fraction = read_float(file, "/HeaderData/ExamData/positronFraction"); + const float half_life = read_float(file, "/HeaderData/ExamData/halfLife"); + if (radionuclide.get_half_life(false) < 0) + radionuclide = Radionuclide(rn_name, 511.F, positron_fraction, half_life, exam_info_sptr->imaging_modality); + exam_info_sptr->set_radionuclide(radionuclide); + } } -Succeeded GEHDF5Wrapper::initialise_listmode_data() +Succeeded +GEHDF5Wrapper::initialise_listmode_data() { - if(!is_list_file()) - error("The file provided is not listmode. Aborting"); + if (!is_list_file()) + error("The file provided is not listmode. Aborting"); - if(rdf_ver==9) + 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) + 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"); + 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; } - else - return Succeeded::no; + else + return Succeeded::no; - m_dataset_sptr.reset(new H5::DataSet(file.openDataSet(m_address))); + m_dataset_sptr.reset(new H5::DataSet(file.openDataSet(m_address))); - m_dataspace = m_dataset_sptr->getSpace(); - m_dataset_list_Ndims = m_dataspace.getSimpleExtentNdims(); + m_dataspace = m_dataset_sptr->getSpace(); + m_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 (m_dataset_list_Ndims>m_max_dataset_dims) - error("Dataset dimensions ("+ std::to_string(m_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]; + // We allocate dims_out in the stack for efficiecy and safety but we need an error check just in case then + if (m_dataset_list_Ndims > m_max_dataset_dims) + error("Dataset dimensions (" + std::to_string(m_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]; + m_dataspace.getSimpleExtentDims(dims_out, NULL); + m_list_size = dims_out[0]; - return Succeeded::yes; + return Succeeded::yes; } -Succeeded GEHDF5Wrapper::initialise_singles_data() +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... + if (!is_list_file() && !is_sino_file()) + error("The file provided is not listmode or sinogram data. Aborting"); - 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) + 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"); + 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 @@ -597,18 +629,19 @@ Succeeded GEHDF5Wrapper::initialise_singles_data() 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) +Succeeded +GEHDF5Wrapper::initialise_proj_data(const unsigned int view_num) { - if(!is_sino_file()) - error("The file provided is not sinogram data. Aborting"); + if (!is_sino_file()) + error("The file provided is not sinogram data. Aborting"); - if(rdf_ver==9) + if (rdf_ver == 9) { // Is the file compressed? unsigned int is_compressed; @@ -618,28 +651,29 @@ Succeeded GEHDF5Wrapper::initialise_proj_data(const unsigned int view_num) error("The RDF9 file sinogram is compressed, we won't be able to read it. Please uncompress it and retry. 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) + 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]; + 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 @@ -647,255 +681,257 @@ Succeeded GEHDF5Wrapper::initialise_proj_data(const unsigned int view_num) 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) +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 (!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"; - { - // 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... + 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... #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() +Succeeded +GEHDF5Wrapper::initialise_efficiency_factors() { - if(!is_norm_file()) - error("The file provided is not norm data. Aborting"); + if (!is_norm_file()) + error("The file provided is not norm data. Aborting"); - if(rdf_ver==9) + 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]; + 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; } // Developed for listmode access -Succeeded GEHDF5Wrapper::read_list_data( char* output, - const std::streampos offset, const hsize_t size) const +Succeeded +GEHDF5Wrapper::read_list_data(char* output, const std::streampos offset, const hsize_t size) const { - if(!is_list_file()) - error("The file provided is not list data. Aborting"); - const hsize_t pos = static_cast(offset); - m_dataspace.selectHyperslab( H5S_SELECT_SET, &size, &pos ); - const H5::DataSpace memspace( m_dataset_list_Ndims, &size); - m_dataset_sptr->read( output, H5::PredType::STD_U8LE, memspace, m_dataspace ); - - return Succeeded::yes; + if (!is_list_file()) + error("The file provided is not list data. Aborting"); + const hsize_t pos = static_cast(offset); + m_dataspace.selectHyperslab(H5S_SELECT_SET, &size, &pos); + const H5::DataSpace memspace(m_dataset_list_Ndims, &size); + m_dataset_sptr->read(output, H5::PredType::STD_U8LE, memspace, m_dataspace); + + return Succeeded::yes; } // Developed for ProjData -Succeeded GEHDF5Wrapper::read_sinogram(Array<3, unsigned char> &output, - const std::array& offset, - const std::array& stride) +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"); + // 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"); + 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} ; + // 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); - // 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()); - H5::DataSpace memspace(3, str_dimsf); - m_dataset_sptr->read(static_cast(aux_buffer.data()), H5::PredType::STD_U8LE, memspace, m_dataspace); + m_dataspace.selectHyperslab(H5S_SELECT_SET, str_dimsf, offset.data()); + H5::DataSpace memspace(3, str_dimsf); + m_dataset_sptr->read(static_cast(aux_buffer.data()), H5::PredType::STD_U8LE, memspace, 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) + // 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& 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()); - H5::DataSpace memspace(2, count.data()); - m_dataset_sptr->read(aux_reader.get_data_ptr(), H5::PredType::NATIVE_UINT32, memspace, 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()); + H5::DataSpace memspace(2, count.data()); + m_dataset_sptr->read(aux_reader.get_data_ptr(), H5::PredType::NATIVE_UINT32, memspace, 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) - +// 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()); - H5::DataSpace memspace(2, str_dimsf); - m_dataset_sptr->read(aux_reader.get_data_ptr(), H5::PredType::NATIVE_FLOAT, memspace, 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(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()); + H5::DataSpace memspace(2, str_dimsf); + m_dataset_sptr->read(aux_reader.get_data_ptr(), H5::PredType::NATIVE_FLOAT, memspace, 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) +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"); + 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) + 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; + this->vData_f[i] = 0.F; vData = NULL; } - else if(this->m_image_type == 15) + else if (this->m_image_type == 15) { vData = new short[this->MaxLength]; for (int i = 0; i < this->MaxLength; i++) - this->vData[i] = 0; + this->vData[i] = 0; vData_f = NULL; } else { - vData = NULL; - vData_f = NULL; + 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; + vDownsample[0] = 1; + vDownsample[1] = 1; + vDownsample[2] = 1; + + vCenter[0] = 0; + vCenter[1] = 0; + vCenter[2] = 0; + vCenter[3] = 0; } // ------------------------------------------------------------------------- @@ -109,10 +109,10 @@ Image::Image(const int num_voxels, const short data_type_case) Image::~Image() { - if (vData) - delete[] vData; - if (vData_f) - delete[] vData_f; + if (vData) + delete[] vData; + if (vData_f) + delete[] vData_f; } // ------------------------------------------------------------------------- @@ -121,555 +121,572 @@ 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) +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(); + 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() +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]; - } - } + 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) +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)); - + 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) +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(); + // 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) +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)); + 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])); - 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)); + ByteSwap(&(m_pixval_offset)); + ByteSwap(&(m_pixval_cal)); + ByteSwap(&(m_user_def1)); + ByteSwap(&(m_user_def2)); + ByteSwap((int*)&(m_magic_number)); - return; + return; } // ------------------------------------------------------------------------- /** -* \brief Initialize zero image -* -* \param Input Input image -*/ + * \brief Initialize zero image + * + * \param Input Input image + */ // ------------------------------------------------------------------------- -void Image::Zeros(Image* Input, short iType) +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; + // 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() +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; + // 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) +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; + // 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) +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]; - } + // 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) +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; + // 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) +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]; - } + // 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 -{ - typedef struct { +void +Image::ByteSwap(int* i) // for PC little endian +{ + typedef struct + { unsigned char byte1; unsigned char byte2; unsigned char byte3; unsigned char byte4; } Bytes; - typedef union { + typedef union + { int integer; Bytes bytes; } intUnion; @@ -681,19 +698,22 @@ 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 -{ - typedef struct { +void +Image::ByteSwap(short* s) // for PC little endian +{ + typedef struct + { unsigned char byte1; unsigned char byte2; } Bytes; - typedef union { + typedef union + { short shortint; Bytes bytes; } shortUnion; @@ -708,16 +728,19 @@ void Image::ByteSwap(short *s) // for PC little endian return; } -void Image::ByteSwap(float *f) // for PC little endian -{ - typedef struct { +void +Image::ByteSwap(float* f) // for PC little endian +{ + typedef struct + { unsigned char byte1; unsigned char byte2; unsigned char byte3; unsigned char byte4; } Bytes; - typedef union { + typedef union + { float floatnum; Bytes bytes; } floatUnion; @@ -734,9 +757,11 @@ void Image::ByteSwap(float *f) // for PC little endian return; } -void Image::ByteSwap(double *d) // for PC little endian -{ - typedef struct { +void +Image::ByteSwap(double* d) // for PC little endian +{ + typedef struct + { unsigned char byte1; unsigned char byte2; unsigned char byte3; @@ -747,7 +772,8 @@ void Image::ByteSwap(double *d) // for PC little endian unsigned char byte8; } Bytes; - typedef union { + typedef union + { double doublenum; Bytes bytes; } doubleUnion; diff --git a/src/IO/IO_registries.cxx b/src/IO/IO_registries.cxx index 63f006168..e969d3ff0 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. SPDX-License-Identifier: Apache-2.0 @@ -33,48 +33,47 @@ #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_UPENN -#include "stir/IO/PENNListmodeInputFileFormat.h" -#include "stir/IO/InputStreamWithRecordsFromUPENNbin.h" -#include "stir/IO/InputStreamWithRecordsFromUPENNtxt.h" +# include "stir/IO/PENNListmodeInputFileFormat.h" +# include "stir/IO/InputStreamWithRecordsFromUPENNbin.h" +# include "stir/IO/InputStreamWithRecordsFromUPENNtxt.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 @@ -102,8 +101,6 @@ static InputStreamFromROOTFileForCylindricalPET::RegisterIt dummy60606; static InputStreamFromROOTFileForECATPET::RegisterIt dummy606062; #endif - - #ifdef HAVE_LLN_MATRIX START_NAMESPACE_ECAT START_NAMESPACE_ECAT6 @@ -117,12 +114,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); @@ -130,15 +126,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); @@ -153,8 +148,8 @@ static RegisterInputFileFormat LMdu static RegisterInputFileFormat LMdummyPENN(8); static InputStreamWithRecordsFromUPENNbin::RegisterIt dummy68606; static InputStreamWithRecordsFromUPENNtxt::RegisterIt dummy686062; -//static RegisterInputFileFormat LMdummyPENNbin(9); -//static RegisterInputFileFormat idummy1(2); +// static RegisterInputFileFormat LMdummyPENNbin(9); +// static RegisterInputFileFormat idummy1(2); #endif END_NAMESPACE_STIR diff --git a/src/IO/ITKImageInputFileFormat.cxx b/src/IO/ITKImageInputFileFormat.cxx index 8835b22b7..c429e3609 100644 --- a/src/IO/ITKImageInputFileFormat.cxx +++ b/src/IO/ITKImageInputFileFormat.cxx @@ -48,74 +48,64 @@ 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; +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; // internal function to do the conversion. Note that it can throw an exception. -template -static -STIRImageType * -read_file_itk(const std::string &filename); +template +static STIRImageType* read_file_itk(const std::string& filename); template -bool -ITKImageInputFileFormat::actual_can_read(const FileSignature& signature, - std::istream& input) const +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(); + try + { + reader->Update(); return true; - } - catch( itk::ExceptionObject & /*err*/ ) - { - + } + 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(); + 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 +ITKImageInputFileFormat::read_from_file(const std::string& filename) const { - return - unique_ptr - (read_file_itk< STIRImageType >(filename)); + return unique_ptr(read_file_itk(filename)); } /* Convert ITK (LPS) coordinates into STIR physical coordinates and @@ -125,56 +115,48 @@ 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) - { - CartesianCoordinate3D stir_origin_index(0, 0, 0); + { + 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()); + // 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()); - stir_coord += stir_origin_wrt_itk_origin; - } + stir_coord += stir_origin_wrt_itk_origin; + } return stir_coord; } /* 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 +template <> +inline typename STIRImageMultiConcrete::full_value_type ITK_pixel_to_STIR_pixel(typename ITKImageMulti::PixelType itk_pixel, - const STIRImageMultiConcrete &stir_image, + const STIRImageMultiConcrete& stir_image, bool is_displacement_field) { // ITK VariableLengthVector to ITK FixedArray @@ -183,46 +165,37 @@ ITK_pixel_to_STIR_pixel(typename ITKImageMulti::PixelType itk_pixel, // 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> +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. @@ -237,11 +210,10 @@ 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 +static shared_ptr construct_exam_info_from_metadata_dictionary(itk::MetaDataDictionary dictionary) { - shared_ptr exam_info_sptr (new ExamInfo()); + shared_ptr exam_info_sptr(new ExamInfo()); #if 0 //example data to read @@ -285,9 +257,10 @@ construct_exam_info_from_metadata_dictionary(itk::MetaDataDictionary dictionary) 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] = std::stod(actual_frame_duration)/1000.; + 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] = std::stod(actual_frame_duration) / 1000.; exam_info_sptr->set_time_frame_definitions(TimeFrameDefinitions(start_times, durations)); } if (!series_datetime.empty()) @@ -309,22 +282,22 @@ 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); - ++position_idx) { - 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; + 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) + { + patient_position = possible_position; + } } - } // warn if we got nothing - if (patient_position.get_position() == PatientPosition::unknown_position) { - warning("Unable to determine patient position. " - "Internally this will generally be handled by assuming HFS"); - } + if (patient_position.get_position() == PatientPosition::unknown_position) + { + warning("Unable to determine patient position. " + "Internally this will generally be handled by assuming HFS"); + } exam_info_sptr->patient_position = patient_position; return exam_info_sptr; @@ -334,26 +307,21 @@ 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; } @@ -361,225 +329,207 @@ 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()); + 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); - } + { + *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) +orient_ITK_image(const typename ITKImageType::Pointer itk_image_orig, const shared_ptr exam_info_sptr) { - typedef itk::OrientImageFilter OrienterType; + typedef itk::OrientImageFilter OrienterType; typename OrienterType::Pointer orienter = OrienterType::New(); orienter->UseImageDirectionOn(); orienter->SetInput(itk_image_orig); // We need the origin to be in the minimum x, y, z corner. This // depends on the patient position - switch (exam_info_sptr->patient_position.get_position()) { - case PatientPosition::unknown_position: - // If unknown, assume HFS - case PatientPosition::HFS: - // HFS means currently in LPI - // So origin is in RAS direction - 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); - break; - - case PatientPosition::FFS: - // FFS means currently in RPS - // So origin is in LAI direction - 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); - break; - - default: - throw std::runtime_error("Unsupported patient position, not sure how to read."); - } + switch (exam_info_sptr->patient_position.get_position()) + { + case PatientPosition::unknown_position: + // If unknown, assume HFS + case PatientPosition::HFS: + // HFS means currently in LPI + // So origin is in RAS direction + 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); + break; + + case PatientPosition::FFS: + // FFS means currently in RPS + // So origin is in LAI direction + 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); + break; + + default: + throw std::runtime_error("Unsupported patient position, not sure how to read."); + } orienter->Update(); return orienter->GetOutput(); } /* 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) +// To read any file format via ITK +template <> +inline STIRImageSingle* +read_file_itk(const std::string& filename) { - typedef itk::GDCMImageIO ImageIOType; + typedef itk::GDCMImageIO ImageIOType; ImageIOType::Pointer dicomIO = ImageIOType::New(); - { - 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); - - } - } + { + 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 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(); + + // Update custom patient position tag in metadata + itk_image->SetMetaDataDictionary(dicomIO->GetMetaDataDictionary()); + + // Finally, convert to STIR! + return convert_ITK_to_STIR(itk_image); + } + } } -//To read any file format via ITK -template<> -inline -STIRImageMulti* -read_file_itk(const std::string &filename) +// To read any file format via ITK +template <> +inline STIRImageMulti* +read_file_itk(const std::string& filename) { - { - // 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; } + { + // 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 + 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; } - - 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."); + ) + { + error("read_file_itk: Image type should be vector %s:%d.", __FILE__, __LINE__); + return NULL; + } - ITKImageMulti::Pointer itk_image = reader->GetOutput(); + 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."); - return convert_ITK_to_STIR - (itk_image, true); + ITKImageMulti::Pointer itk_image = reader->GetOutput(); - } + return convert_ITK_to_STIR(itk_image, true); + } } // explicit instantiations diff --git a/src/IO/ITKOutputFileFormat.cxx b/src/IO/ITKOutputFileFormat.cxx index f170127b6..0e8224655 100644 --- a/src/IO/ITKOutputFileFormat.cxx +++ b/src/IO/ITKOutputFileFormat.cxx @@ -30,30 +30,24 @@ 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); @@ -61,9 +55,8 @@ initialise_keymap() base_type::initialise_keymap(); } -bool -ITKOutputFileFormat:: -post_processing() +bool +ITKOutputFileFormat::post_processing() { if (base_type::post_processing()) return true; @@ -71,20 +64,15 @@ post_processing() } // 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: @@ -95,20 +83,19 @@ actual_write_to_file(std::string& filename, { add_extension(filename, this->default_extension); - const VoxelsOnCartesianGrid& image = - dynamic_cast& >(density); + 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; + { + warning("ITK writer: can handle only regular index ranges."); + return Succeeded::no; + } + + 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 @@ -117,8 +104,7 @@ actual_write_to_file(std::string& filename, // find ITK origin (i.e. coordinates of first voxel) ImageType::PointType origin; - CartesianCoordinate3D stir_offset - = density.get_LPS_coordinates_for_indices(min_indices); + 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(); @@ -138,38 +124,40 @@ actual_write_to_file(std::string& filename, // 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); + 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); + } } - } ImageType::RegionType region; - region.SetSize( size ); - region.SetIndex( start ); + region.SetSize(size); + region.SetIndex(start); - //Creating the image + // Creating the image ImageType::Pointer itk_image = ImageType::New(); itk_image->SetSpacing(spacing); - itk_image->SetRegions( region ); + itk_image->SetRegions(region); itk_image->SetOrigin(origin); - itk_image->SetDirection( matrix ); + 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::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); @@ -182,9 +170,6 @@ actual_write_to_file(std::string& filename, { return Succeeded::no; } - } END_NAMESPACE_STIR - - diff --git a/src/IO/InputFileFormatRegistry.cxx b/src/IO/InputFileFormatRegistry.cxx index 18465b2e1..23e2e602e 100644 --- a/src/IO/InputFileFormatRegistry.cxx +++ b/src/IO/InputFileFormatRegistry.cxx @@ -19,17 +19,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 eaddbd251..4321fd539 100644 --- a/src/IO/InputStreamFromROOTFile.cxx +++ b/src/IO/InputStreamFromROOTFile.cxx @@ -33,12 +33,11 @@ START_NAMESPACE_STIR -InputStreamFromROOTFile:: -InputStreamFromROOTFile() +InputStreamFromROOTFile::InputStreamFromROOTFile() { - set_defaults(); - reset(); - least_significant_clock_bit = 1.0e+12; // TODO remove cst or rename + set_defaults(); + reset(); + least_significant_clock_bit = 1.0e+12; // TODO remove cst or rename } #if 0 // disabled as unused and incorrect @@ -61,144 +60,140 @@ InputStreamFromROOTFile(std::string filename, void InputStreamFromROOTFile::set_defaults() { - starting_stream_position = 0; - singles_readout_depth = -1; - exclude_nonrandom = false; - exclude_scattered = false; - exclude_unscattered = false; - exclude_randoms = false; - check_energy_window_information = true; - 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; + starting_stream_position = 0; + singles_readout_depth = -1; + exclude_nonrandom = false; + exclude_scattered = false; + exclude_unscattered = false; + exclude_randoms = false; + check_energy_window_information = true; + 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 non-random events", &this->exclude_nonrandom); - this->parser.add_key("exclude scattered events", &this->exclude_scattered); - this->parser.add_key("exclude unscattered events", &this->exclude_unscattered); - this->parser.add_key("exclude random events", &this->exclude_randoms); - this->parser.add_key("check energy window information", &this->check_energy_window_information); + 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 non-random events", &this->exclude_nonrandom); + this->parser.add_key("exclude scattered events", &this->exclude_scattered); + this->parser.add_key("exclude unscattered events", &this->exclude_unscattered); + this->parser.add_key("exclude random events", &this->exclude_randoms); + this->parser.add_key("check energy window information", &this->check_energy_window_information); #ifdef STIR_ROOT_ROTATION_AS_V4 - this->parser.add_key("offset (num of detectors)", &this->offset_dets); + this->parser.add_key("offset (num of detectors)", &this->offset_dets); #endif - 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("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); + 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; + return false; } Succeeded -InputStreamFromROOTFile::set_up(const std::string & header_path) +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()); - } + // 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); - stream_ptr = new TChain(this->chain_name.c_str()); - stream_ptr->Add(fullfilename.c_str()); - // Turn off all branches - stream_ptr->SetBranchStatus("*",0); - - // Branches are turned back on by SetBranchAddress() - stream_ptr->SetBranchAddress("time1", &time1, &br_time1); - stream_ptr->SetBranchAddress("time2", &time2, &br_time2); - stream_ptr->SetBranchAddress("eventID1",&eventID1, &br_eventID1); - stream_ptr->SetBranchAddress("eventID2",&eventID2, &br_eventID2); - stream_ptr->SetBranchAddress("energy1", &energy1, &br_energy1); - stream_ptr->SetBranchAddress("energy2", &energy2, &br_energy2); - stream_ptr->SetBranchAddress("comptonPhantom1", &comptonphantom1, &br_comptonPhantom1); - stream_ptr->SetBranchAddress("comptonPhantom2", &comptonphantom2, &br_comptonPhantom2); - - if (read_optional_root_fields) + 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) { - stream_ptr->SetBranchAddress("axialPos",&axialPos, &br_axialPos); - stream_ptr->SetBranchAddress("globalPosX1",&globalPosX1, &br_globalPosX1); - stream_ptr->SetBranchAddress("globalPosX2",&globalPosX2, &br_globalPosX2); - stream_ptr->SetBranchAddress("globalPosY1",&globalPosY1, &br_globalPosY1); - stream_ptr->SetBranchAddress("globalPosY2",&globalPosY2, &br_globalPosY2); - stream_ptr->SetBranchAddress("globalPosZ1",&globalPosZ1, &br_globalPosZ1); - stream_ptr->SetBranchAddress("globalPosZ2",&globalPosZ2, &br_globalPosZ2); - stream_ptr->SetBranchAddress("rotationAngle",&rotation_angle, &br_rotation_angle); - stream_ptr->SetBranchAddress("runID",&runID, &br_runID); - stream_ptr->SetBranchAddress("sinogramS",&sinogramS, &br_sinogramS); - stream_ptr->SetBranchAddress("sinogramTheta",&sinogramTheta, &br_sinogramTheta); - stream_ptr->SetBranchAddress("sourceID1",&sourceID1, &br_sourceID1); - stream_ptr->SetBranchAddress("sourceID2",&sourceID2, &br_sourceID2); - stream_ptr->SetBranchAddress("sourcePosX1",&sourcePosX1, &br_sourcePosX1); - stream_ptr->SetBranchAddress("sourcePosX2",&sourcePosX2, &br_sourcePosX2); - stream_ptr->SetBranchAddress("sourcePosY1",&sourcePosY1, &br_sourcePosY1); - stream_ptr->SetBranchAddress("sourcePosY2",&sourcePosY2, &br_sourcePosY2); - stream_ptr->SetBranchAddress("sourcePosZ1",&sourcePosZ1, &br_sourcePosZ1); - stream_ptr->SetBranchAddress("sourcePosZ2",&sourcePosZ2, &br_sourcePosZ2); + 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()); + // Turn off all branches + stream_ptr->SetBranchStatus("*", 0); + + // Branches are turned back on by SetBranchAddress() + stream_ptr->SetBranchAddress("time1", &time1, &br_time1); + stream_ptr->SetBranchAddress("time2", &time2, &br_time2); + stream_ptr->SetBranchAddress("eventID1", &eventID1, &br_eventID1); + stream_ptr->SetBranchAddress("eventID2", &eventID2, &br_eventID2); + stream_ptr->SetBranchAddress("energy1", &energy1, &br_energy1); + stream_ptr->SetBranchAddress("energy2", &energy2, &br_energy2); + stream_ptr->SetBranchAddress("comptonPhantom1", &comptonphantom1, &br_comptonPhantom1); + stream_ptr->SetBranchAddress("comptonPhantom2", &comptonphantom2, &br_comptonPhantom2); + + if (read_optional_root_fields) { - // Ensure that two conflicting exclusions are not applied - if (this->exclude_nonrandom && this->exclude_randoms) - error("InputStreamFromROOTFile: Both the exclusion of true and random events has been set. Therefore, " - "no data will be processed."); - if (this->exclude_scattered && this->exclude_unscattered) - error("InputStreamFromROOTFile: Both the exclusion of scattered and unscattered events has been set. Therefore, " - "no data will be processed."); - - // Show which event types will be unlisted based upon the exclusion criteria - bool trues = true; - bool randoms = true; - bool scattered = true; - bool scattered_randoms = true; - if (this->exclude_nonrandom || this->exclude_unscattered) - trues = false; - if ( this->exclude_randoms || this->exclude_unscattered ) - randoms= false; - if ( this->exclude_scattered || this->exclude_nonrandom ) - scattered = false; - if ( this->exclude_scattered || this->exclude_randoms ) - scattered_randoms = false; - - std::string status = "InputStreamFromROOTFile: Processing data with the following event type inclusions:" - "\n Unscattered from same eventID: " + std::to_string(trues) + - "\n Unscattered from different eventIDs: " + std::to_string(randoms) + - "\n Scattered from same eventID: " + std::to_string(scattered) + - "\n Scattered different eventIDs: " + std::to_string(scattered_randoms); - info(status, 2); + stream_ptr->SetBranchAddress("axialPos", &axialPos, &br_axialPos); + stream_ptr->SetBranchAddress("globalPosX1", &globalPosX1, &br_globalPosX1); + stream_ptr->SetBranchAddress("globalPosX2", &globalPosX2, &br_globalPosX2); + stream_ptr->SetBranchAddress("globalPosY1", &globalPosY1, &br_globalPosY1); + stream_ptr->SetBranchAddress("globalPosY2", &globalPosY2, &br_globalPosY2); + stream_ptr->SetBranchAddress("globalPosZ1", &globalPosZ1, &br_globalPosZ1); + stream_ptr->SetBranchAddress("globalPosZ2", &globalPosZ2, &br_globalPosZ2); + stream_ptr->SetBranchAddress("rotationAngle", &rotation_angle, &br_rotation_angle); + stream_ptr->SetBranchAddress("runID", &runID, &br_runID); + stream_ptr->SetBranchAddress("sinogramS", &sinogramS, &br_sinogramS); + stream_ptr->SetBranchAddress("sinogramTheta", &sinogramTheta, &br_sinogramTheta); + stream_ptr->SetBranchAddress("sourceID1", &sourceID1, &br_sourceID1); + stream_ptr->SetBranchAddress("sourceID2", &sourceID2, &br_sourceID2); + stream_ptr->SetBranchAddress("sourcePosX1", &sourcePosX1, &br_sourcePosX1); + stream_ptr->SetBranchAddress("sourcePosX2", &sourcePosX2, &br_sourcePosX2); + stream_ptr->SetBranchAddress("sourcePosY1", &sourcePosY1, &br_sourcePosY1); + stream_ptr->SetBranchAddress("sourcePosY2", &sourcePosY2, &br_sourcePosY2); + stream_ptr->SetBranchAddress("sourcePosZ1", &sourcePosZ1, &br_sourcePosZ1); + stream_ptr->SetBranchAddress("sourcePosZ2", &sourcePosZ2, &br_sourcePosZ2); } - return Succeeded::yes; + { + // Ensure that two conflicting exclusions are not applied + if (this->exclude_nonrandom && this->exclude_randoms) + error("InputStreamFromROOTFile: Both the exclusion of true and random events has been set. Therefore, " + "no data will be processed."); + if (this->exclude_scattered && this->exclude_unscattered) + error("InputStreamFromROOTFile: Both the exclusion of scattered and unscattered events has been set. Therefore, " + "no data will be processed."); + + // Show which event types will be unlisted based upon the exclusion criteria + bool trues = true; + bool randoms = true; + bool scattered = true; + bool scattered_randoms = true; + if (this->exclude_nonrandom || this->exclude_unscattered) + trues = false; + if (this->exclude_randoms || this->exclude_unscattered) + randoms = false; + if (this->exclude_scattered || this->exclude_nonrandom) + scattered = false; + if (this->exclude_scattered || this->exclude_randoms) + scattered_randoms = false; + + std::string status = "InputStreamFromROOTFile: Processing data with the following event type inclusions:" + "\n Unscattered from same eventID: " + + std::to_string(trues) + "\n Unscattered from different eventIDs: " + std::to_string(randoms) + + "\n Scattered from same eventID: " + std::to_string(scattered) + + "\n Scattered different eventIDs: " + std::to_string(scattered_randoms); + info(status, 2); + } + + return Succeeded::yes; } bool @@ -208,65 +203,65 @@ InputStreamFromROOTFile::check_brentry_randoms_scatter_energy_conditions(Long64_ return false; // Scattered/unscattered event exclusion condition. - if (this->exclude_scattered || this->exclude_unscattered) { - GetEntryCheck(br_comptonPhantom1->GetEntry(brentry)); - GetEntryCheck(br_comptonPhantom2->GetEntry(brentry)); - - // Check if either event has been Compton scattered and should be excluded - if (this->exclude_scattered && (this->comptonphantom1 > 0 || this->comptonphantom2 > 0)) - return false; - if (this->exclude_unscattered && (this->comptonphantom1 == 0 && this->comptonphantom2 == 0)) - return false; - } + if (this->exclude_scattered || this->exclude_unscattered) + { + GetEntryCheck(br_comptonPhantom1->GetEntry(brentry)); + GetEntryCheck(br_comptonPhantom2->GetEntry(brentry)); + + // Check if either event has been Compton scattered and should be excluded + if (this->exclude_scattered && (this->comptonphantom1 > 0 || this->comptonphantom2 > 0)) + return false; + if (this->exclude_unscattered && (this->comptonphantom1 == 0 && this->comptonphantom2 == 0)) + return false; + } // Trues/Random event exclusion condition. - if (this->exclude_randoms || this->exclude_nonrandom) { - GetEntryCheck(br_eventID1->GetEntry(brentry)); - GetEntryCheck(br_eventID2->GetEntry(brentry)); + if (this->exclude_randoms || this->exclude_nonrandom) + { + GetEntryCheck(br_eventID1->GetEntry(brentry)); + GetEntryCheck(br_eventID2->GetEntry(brentry)); - // exclude randoms - if (this->exclude_randoms && this->eventID1 != this->eventID2) - return false; + // exclude randoms + if (this->exclude_randoms && this->eventID1 != this->eventID2) + return false; - // exclude trues - if (this->exclude_nonrandom && this->eventID1 == this->eventID2) - return false; - } + // exclude trues + if (this->exclude_nonrandom && this->eventID1 == this->eventID2) + return false; + } // Energy condition. - if (this->check_energy_window_information){ - GetEntryCheck(br_energy1->GetEntry(brentry)); - GetEntryCheck(br_energy2->GetEntry(brentry)); - - // Check both energy values are within window - 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) + if (this->check_energy_window_information) { - return false; + GetEntryCheck(br_energy1->GetEntry(brentry)); + GetEntryCheck(br_energy2->GetEntry(brentry)); + + // Check both energy values are within window + 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) + { + return false; + } } - } return true; } - void InputStreamFromROOTFile::set_crystal_repeater_x(int val) { - crystal_repeater_x = val; + crystal_repeater_x = val; } void InputStreamFromROOTFile::set_crystal_repeater_y(int val) { - crystal_repeater_y = val; + crystal_repeater_y = val; } void InputStreamFromROOTFile::set_crystal_repeater_z(int val) { - crystal_repeater_z = val; + crystal_repeater_z = val; } void diff --git a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx index 8314b7172..233e26230 100644 --- a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx +++ b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx @@ -14,15 +14,12 @@ 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() +InputStreamFromROOTFileForCylindricalPET::InputStreamFromROOTFileForCylindricalPET() + : base_type() { - set_defaults(); + set_defaults(); } #if 0 // not used, so commented out (would need adapting since moving crystal_repeated_*) InputStreamFromROOTFileForCylindricalPET:: @@ -59,69 +56,67 @@ InputStreamFromROOTFileForCylindricalPET(std::string _filename, #endif Succeeded -InputStreamFromROOTFileForCylindricalPET:: -get_next_record(CListRecordROOT& record) +InputStreamFromROOTFileForCylindricalPET::get_next_record(CListRecordROOT& record) { - int ring1, ring2, crystal1, crystal2; - double delta_timing_bin; - bool eof = false; + int ring1, ring2, crystal1, crystal2; + double delta_timing_bin; + bool eof = false; #ifdef STIR_OPENMP -#pragma omp critical(LISTMODEIO) +# pragma omp critical(LISTMODEIO) #endif - { - while(true) - { - if (current_position == nentries) - { - eof = true; - break; - } - - Long64_t brentry = stream_ptr->LoadTree(static_cast(current_position)); - current_position ++ ; + { + while (true) + { + if (current_position == nentries) + { + eof = true; + break; + } - if (!this->check_brentry_randoms_scatter_energy_conditions(brentry)) - continue; + Long64_t brentry = stream_ptr->LoadTree(static_cast(current_position)); + current_position++; + if (!this->check_brentry_randoms_scatter_energy_conditions(brentry)) + continue; - // Get time information - GetEntryCheck(br_time1->GetEntry(brentry)); - GetEntryCheck(br_time2->GetEntry(brentry)); + // Get time information + GetEntryCheck(br_time1->GetEntry(brentry)); + GetEntryCheck(br_time2->GetEntry(brentry)); - // Get positional ID information - GetEntryCheck(br_crystalID1->GetEntry(brentry)); - GetEntryCheck(br_crystalID2->GetEntry(brentry)); + // Get positional ID information + GetEntryCheck(br_crystalID1->GetEntry(brentry)); + GetEntryCheck(br_crystalID2->GetEntry(brentry)); - GetEntryCheck(br_submoduleID1->GetEntry(brentry)); - GetEntryCheck(br_submoduleID2->GetEntry(brentry)); + GetEntryCheck(br_submoduleID1->GetEntry(brentry)); + GetEntryCheck(br_submoduleID2->GetEntry(brentry)); - GetEntryCheck(br_moduleID1->GetEntry(brentry)); - GetEntryCheck(br_moduleID2->GetEntry(brentry)); + GetEntryCheck(br_moduleID1->GetEntry(brentry)); + GetEntryCheck(br_moduleID2->GetEntry(brentry)); - GetEntryCheck(br_rsectorID1->GetEntry(brentry)); - GetEntryCheck(br_rsectorID2->GetEntry(brentry)); + GetEntryCheck(br_rsectorID1->GetEntry(brentry)); + GetEntryCheck(br_rsectorID2->GetEntry(brentry)); - break; - } + break; + } - 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(); + 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(); - 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(); + 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(); - 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); + 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); 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); + + (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 . @@ -135,172 +130,165 @@ get_next_record(CListRecordROOT& record) #endif delta_timing_bin = (time2 - time1) * least_significant_clock_bit; - } + } - if(eof) - return Succeeded::no; + if (eof) + return Succeeded::no; - return - record.init_from_data(ring1, ring2, - crystal1, crystal2, - time1, delta_timing_bin, - eventID1, eventID2); + return record.init_from_data(ring1, ring2, crystal1, crystal2, time1, delta_timing_bin, eventID1, eventID2); } std::string -InputStreamFromROOTFileForCylindricalPET:: -method_info() const +InputStreamFromROOTFileForCylindricalPET::method_info() const { - std::ostringstream s; - s << this->registered_name; - return s.str(); + 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; + 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; #ifdef STIR_ROOT_ROTATION_AS_V4 - half_block = module_repeater_y * submodule_repeater_y * crystal_repeater_y / 2 - 1; - if (half_block < 0 ) - half_block = 0; -#else + half_block = module_repeater_y * submodule_repeater_y * crystal_repeater_y / 2 - 1; + if (half_block < 0) half_block = 0; +#else + half_block = 0; #endif } 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); + 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() +bool +InputStreamFromROOTFileForCylindricalPET::post_processing() { - if (base_type::post_processing()) - return true; - return false; + if (base_type::post_processing()) + return true; + return false; } Succeeded -InputStreamFromROOTFileForCylindricalPET:: -set_up(const std::string & header_path) +InputStreamFromROOTFileForCylindricalPET::set_up(const std::string& header_path) { - if (base_type::set_up(header_path) == Succeeded::no) - return Succeeded::no; + 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)) + std::string missing_keywords; + if (!check_all_required_keywords_are_set(missing_keywords)) { - warning(missing_keywords.c_str()); - return Succeeded::no; + warning(missing_keywords.c_str()); + return Succeeded::no; } - stream_ptr->SetBranchAddress("crystalID1",&crystalID1, &br_crystalID1); - stream_ptr->SetBranchAddress("crystalID2",&crystalID2, &br_crystalID2); - stream_ptr->SetBranchAddress("submoduleID1",&submoduleID1, &br_submoduleID1); - stream_ptr->SetBranchAddress("submoduleID2",&submoduleID2, &br_submoduleID2); - stream_ptr->SetBranchAddress("moduleID1",&moduleID1, &br_moduleID1); - stream_ptr->SetBranchAddress("moduleID2",&moduleID2, &br_moduleID2); - stream_ptr->SetBranchAddress("rsectorID1",&rsectorID1, &br_rsectorID1); - stream_ptr->SetBranchAddress("rsectorID2",&rsectorID2, &br_rsectorID2); + stream_ptr->SetBranchAddress("crystalID1", &crystalID1, &br_crystalID1); + stream_ptr->SetBranchAddress("crystalID2", &crystalID2, &br_crystalID2); + stream_ptr->SetBranchAddress("submoduleID1", &submoduleID1, &br_submoduleID1); + stream_ptr->SetBranchAddress("submoduleID2", &submoduleID2, &br_submoduleID2); + stream_ptr->SetBranchAddress("moduleID1", &moduleID1, &br_moduleID1); + stream_ptr->SetBranchAddress("moduleID2", &moduleID2, &br_moduleID2); + stream_ptr->SetBranchAddress("rsectorID1", &rsectorID1, &br_rsectorID1); + stream_ptr->SetBranchAddress("rsectorID2", &rsectorID2, &br_rsectorID2); - nentries = static_cast(stream_ptr->GetEntries()); - if (nentries == 0) - error("InputStreamFromROOTFileForCylindricalPET: The total number of entries in the ROOT file is zero. Abort."); + 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; + return Succeeded::yes; } -bool InputStreamFromROOTFileForCylindricalPET:: -check_all_required_keywords_are_set(std::string& ret) const +bool +InputStreamFromROOTFileForCylindricalPET::check_all_required_keywords_are_set(std::string& ret) const { - std::ostringstream stream("InputStreamFromROOTFileForCylindricalPET: Required keywords are missing! Check: "); - bool ok = true; + std::ostringstream stream("InputStreamFromROOTFileForCylindricalPET: Required keywords are missing! Check: "); + bool ok = true; - if (crystal_repeater_x == -1) + if (crystal_repeater_x == -1) { - stream << "crystal_repeater_x, "; - ok = false; + stream << "crystal_repeater_x, "; + ok = false; } - if (crystal_repeater_y == -1) + if (crystal_repeater_y == -1) { - stream << "crystal_repeater_x, "; - ok = false; + stream << "crystal_repeater_x, "; + ok = false; } - if (crystal_repeater_z == -1) + if (crystal_repeater_z == -1) { - stream << "crystal_repeater_x, "; - ok = false; + stream << "crystal_repeater_x, "; + ok = false; } - if (submodule_repeater_x == -1) + if (submodule_repeater_x == -1) { - stream << "crystal_repeater_x, "; - ok = false; + stream << "crystal_repeater_x, "; + ok = false; } - if (submodule_repeater_y == -1) + if (submodule_repeater_y == -1) { - stream << "crystal_repeater_x, "; - ok = false; + stream << "crystal_repeater_x, "; + ok = false; } - if (submodule_repeater_z == -1) + if (submodule_repeater_z == -1) { - stream << "crystal_repeater_x, "; - ok = false; + stream << "crystal_repeater_x, "; + ok = false; } - if (module_repeater_x == -1) + if (module_repeater_x == -1) { - stream << "crystal_repeater_x, "; - ok = false; + stream << "crystal_repeater_x, "; + ok = false; } - if (module_repeater_y == -1) + if (module_repeater_y == -1) { - stream << "crystal_repeater_x, "; - ok = false; + stream << "crystal_repeater_x, "; + ok = false; } - if (module_repeater_z == -1) + if (module_repeater_z == -1) { - stream << "crystal_repeater_x, "; - ok = false; + stream << "crystal_repeater_x, "; + ok = false; } - if (rsector_repeater == -1) + if (rsector_repeater == -1) { - stream << "crystal_repeater_x, "; - ok = false; + stream << "crystal_repeater_x, "; + ok = false; } - if (!ok) - ret = stream.str(); + if (!ok) + ret = stream.str(); - return ok; + return ok; } - END_NAMESPACE_STIR diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index 83c9901b6..422694b87 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -15,15 +15,12 @@ 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() +InputStreamFromROOTFileForECATPET::InputStreamFromROOTFileForECATPET() + : base_type() { - set_defaults(); + set_defaults(); } #if 0 // not used, so commented out (would need adapting since moving crystal_repeated_*) @@ -57,53 +54,50 @@ InputStreamFromROOTFileForECATPET(std::string _filename, #endif Succeeded -InputStreamFromROOTFileForECATPET:: -get_next_record(CListRecordROOT& record) +InputStreamFromROOTFileForECATPET::get_next_record(CListRecordROOT& record) { - int ring1, ring2, crystal1, crystal2; - double delta_timing_bin; - bool return_no = false; + int ring1, ring2, crystal1, crystal2; + double delta_timing_bin; + bool return_no = false; #ifdef STIR_OPENMP -#pragma omp critical(LISTMODEIO) +# pragma omp critical(LISTMODEIO) #endif - { - while(true) { - if (current_position == nentries) - return_no = true; + while (true) + { + if (current_position == nentries) + return_no = true; - Long64_t brentry = stream_ptr->LoadTree(static_cast(current_position)); - current_position ++ ; + Long64_t brentry = stream_ptr->LoadTree(static_cast(current_position)); + current_position++; - if (!this->check_brentry_randoms_scatter_energy_conditions(brentry)) - continue; + if (!this->check_brentry_randoms_scatter_energy_conditions(brentry)) + continue; - GetEntryCheck(br_time1->GetEntry(brentry)); - GetEntryCheck(br_time2->GetEntry(brentry)); + GetEntryCheck(br_time1->GetEntry(brentry)); + GetEntryCheck(br_time2->GetEntry(brentry)); - // Get positional ID information - GetEntryCheck(br_crystalID1->GetEntry(brentry)); - GetEntryCheck(br_crystalID2->GetEntry(brentry)); + // Get positional ID information + GetEntryCheck(br_crystalID1->GetEntry(brentry)); + GetEntryCheck(br_crystalID2->GetEntry(brentry)); - GetEntryCheck(br_blockID1->GetEntry(brentry)); - GetEntryCheck(br_blockID2->GetEntry(brentry)); + GetEntryCheck(br_blockID1->GetEntry(brentry)); + GetEntryCheck(br_blockID2->GetEntry(brentry)); - break; - } + break; + } - ring1 = static_cast(crystalID1/crystal_repeater_y) - + static_cast(blockID1/ block_repeater_y)*crystal_repeater_z; + ring1 = static_cast(crystalID1 / crystal_repeater_y) + + static_cast(blockID1 / block_repeater_y) * crystal_repeater_z; - ring2 = static_cast(crystalID2/crystal_repeater_y) - + static_cast(blockID2/block_repeater_y)*crystal_repeater_z; + ring2 = static_cast(crystalID2 / crystal_repeater_y) + + static_cast(blockID2 / block_repeater_y) * crystal_repeater_z; - crystal1 = (blockID1%block_repeater_y) * get_num_transaxial_crystals_per_block_v() - + (crystalID1%crystal_repeater_y); + crystal1 = (blockID1 % block_repeater_y) * get_num_transaxial_crystals_per_block_v() + (crystalID1 % crystal_repeater_y); - crystal2 = (blockID2%block_repeater_y) * get_num_transaxial_crystals_per_block_v() - + (crystalID2%crystal_repeater_y); + 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 . @@ -117,123 +111,118 @@ get_next_record(CListRecordROOT& record) #endif delta_timing_bin = (time2 - time1) * least_significant_clock_bit; - } + } - if(return_no) - return Succeeded::no; + if (return_no) + return Succeeded::no; - return - record.init_from_data(ring1, ring2, - crystal1, crystal2, - time1, delta_timing_bin, - eventID1, eventID2); + return record.init_from_data(ring1, ring2, crystal1, crystal2, time1, delta_timing_bin, eventID1, eventID2); } std::string -InputStreamFromROOTFileForECATPET:: -method_info() const +InputStreamFromROOTFileForECATPET::method_info() const { - std::ostringstream s; - s << this->registered_name; - return s.str(); + 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; + base_type::set_defaults(); + block_repeater_y = -1; + block_repeater_z = -1; #ifdef STIR_ROOT_ROTATION_AS_V4 - half_block = crystal_repeater_y / 2 - 1; - if (half_block < 0 ) - half_block = 0; -#else + half_block = crystal_repeater_y / 2 - 1; + if (half_block < 0) half_block = 0; +#else + half_block = 0; #endif } 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); + 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() +bool +InputStreamFromROOTFileForECATPET::post_processing() { - return false; + return false; } -Succeeded InputStreamFromROOTFileForECATPET:: -set_up(const std::string & header_path ) +Succeeded +InputStreamFromROOTFileForECATPET::set_up(const std::string& header_path) { - if (base_type::set_up(header_path) == Succeeded::no) - return Succeeded::no; + 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)) + std::string missing_keywords; + if (!check_all_required_keywords_are_set(missing_keywords)) { - warning(missing_keywords.c_str()); - return Succeeded::no; + 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); + 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."); + 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; + return Succeeded::yes; } -bool InputStreamFromROOTFileForECATPET:: -check_all_required_keywords_are_set(std::string& ret) const +bool +InputStreamFromROOTFileForECATPET::check_all_required_keywords_are_set(std::string& ret) const { - std::ostringstream stream("InputStreamFromROOTFileForCylindricalPET: Required keywords are missing! Check: "); - bool ok = true; + std::ostringstream stream("InputStreamFromROOTFileForCylindricalPET: Required keywords are missing! Check: "); + bool ok = true; - if (crystal_repeater_x == -1) + if (crystal_repeater_x == -1) { - stream << "crystal_repeater_x, "; - ok = false; + stream << "crystal_repeater_x, "; + ok = false; } - if (crystal_repeater_y == -1) + if (crystal_repeater_y == -1) { - stream << "crystal_repeater_y, "; - ok = false; + stream << "crystal_repeater_y, "; + ok = false; } - if (crystal_repeater_z == -1) + if (crystal_repeater_z == -1) { - stream << "crystal_repeater_z, "; - ok = false; + stream << "crystal_repeater_z, "; + ok = false; } - if (block_repeater_y == -1) + if (block_repeater_y == -1) { - stream << "block_repeater_y, "; - ok = false; + stream << "block_repeater_y, "; + ok = false; } - if (block_repeater_z == -1) + if (block_repeater_z == -1) { - stream << "block_repeater_z, "; - ok = false; + stream << "block_repeater_z, "; + ok = false; } - if (!ok) - ret = stream.str(); + if (!ok) + ret = stream.str(); - return ok; + return ok; } END_NAMESPACE_STIR diff --git a/src/IO/InputStreamWithRecordsFromUPENN.cxx b/src/IO/InputStreamWithRecordsFromUPENN.cxx index 7689776e5..339273368 100644 --- a/src/IO/InputStreamWithRecordsFromUPENN.cxx +++ b/src/IO/InputStreamWithRecordsFromUPENN.cxx @@ -20,72 +20,69 @@ #include "stir/FilePath.h" #include "stir/info.h" - START_NAMESPACE_STIR -InputStreamWithRecordsFromUPENN:: -InputStreamWithRecordsFromUPENN() +InputStreamWithRecordsFromUPENN::InputStreamWithRecordsFromUPENN() { - set_defaults(); + set_defaults(); } unsigned long int InputStreamWithRecordsFromUPENN::get_total_number_of_events(CListRecordPENN& record) { - this->save_get_position(); - this->reset(); - unsigned long int counter = 0; + this->save_get_position(); + this->reset(); + unsigned long int counter = 0; - while(true) + while (true) { - if(this->get_next_record(record) == Succeeded::no) - break; - if (counter > 1 && counter%1000000L==0) - // info( boost::format("Counting records: %1% ") % counter); - std::cout << "\r" << counter << " events counted "<get_next_record(record) == Succeeded::no) + break; + if (counter > 1 && counter % 1000000L == 0) + // info( boost::format("Counting records: %1% ") % counter); + std::cout << "\r" << counter << " events counted " << std::flush; + counter++; } - this->reset(); - this->set_get_position(get_saved_get_positions().back()); - return counter; + this->reset(); + this->set_get_position(get_saved_get_positions().back()); + return counter; } Succeeded -InputStreamWithRecordsFromUPENN:: -set_up() +InputStreamWithRecordsFromUPENN::set_up() { - return Succeeded::yes; + return Succeeded::yes; } void InputStreamWithRecordsFromUPENN::set_defaults() { - starting_stream_position = 0; - N = 0; - abrupt_counter = N; - minE_chan = 0; - maxE_chan = 1000; - keep_prompt = true; - keep_delayed = true; - abrupt_stop = false; + starting_stream_position = 0; + N = 0; + abrupt_counter = N; + minE_chan = 0; + maxE_chan = 1000; + keep_prompt = true; + keep_delayed = true; + abrupt_stop = false; } void InputStreamWithRecordsFromUPENN::initialise_keymap() { - this->parser.add_key("name of data file", &this->filename); - this->parser.add_key("low energy window (chan)", &this->minE_chan); - this->parser.add_key("upper energy window (chan)", &this->maxE_chan); - this->parser.add_key("keep prompts", &this->keep_prompt); - this->parser.add_key("keep delayed", &this->keep_delayed); + this->parser.add_key("name of data file", &this->filename); + this->parser.add_key("low energy window (chan)", &this->minE_chan); + this->parser.add_key("upper energy window (chan)", &this->maxE_chan); + this->parser.add_key("keep prompts", &this->keep_prompt); + this->parser.add_key("keep delayed", &this->keep_delayed); } bool InputStreamWithRecordsFromUPENN::post_processing() { - return false; + return false; } END_NAMESPACE_STIR diff --git a/src/IO/InputStreamWithRecordsFromUPENNbin.cxx b/src/IO/InputStreamWithRecordsFromUPENNbin.cxx index 3e9d99080..3f9b63eab 100644 --- a/src/IO/InputStreamWithRecordsFromUPENNbin.cxx +++ b/src/IO/InputStreamWithRecordsFromUPENNbin.cxx @@ -19,264 +19,259 @@ START_NAMESPACE_STIR -const char * const -InputStreamWithRecordsFromUPENNbin::registered_name = - "UPENN_binary_listmode"; +const char* const InputStreamWithRecordsFromUPENNbin::registered_name = "UPENN_binary_listmode"; -InputStreamWithRecordsFromUPENNbin:: -InputStreamWithRecordsFromUPENNbin(): - base_type() +InputStreamWithRecordsFromUPENNbin::InputStreamWithRecordsFromUPENNbin() + : base_type() { - set_defaults(); + set_defaults(); } Succeeded -InputStreamWithRecordsFromUPENNbin:: -reset() +InputStreamWithRecordsFromUPENNbin::reset() { - inputListFile.pubseekpos(pos); - inputList->pubsync(); + inputListFile.pubseekpos(pos); + inputList->pubsync(); - abrupt_counter = N; - if(!is_null_ptr(in)) + abrupt_counter = N; + if (!is_null_ptr(in)) { - delete in; - in = new list::InputBuffer( *inputList, eventSize ); + delete in; + in = new list::InputBuffer(*inputList, eventSize); } - return Succeeded::yes; + return Succeeded::yes; } Succeeded -InputStreamWithRecordsFromUPENNbin:: -get_next_record(CListRecordPENN& record) +InputStreamWithRecordsFromUPENNbin::get_next_record(CListRecordPENN& record) { - int dt = 0; - int xa = 0; - int xb = 0; - int za = 0; - int zb = 0; - int ea = 0; - int eb = 0; - bool is_delay = false; - bool found = false; + int dt = 0; + int xa = 0; + int xb = 0; + int za = 0; + int zb = 0; + int ea = 0; + int eb = 0; + bool is_delay = false; + bool found = false; #ifdef STIR_OPENMP -#pragma omp critical(LISTMODEIO) +# pragma omp critical(LISTMODEIO) #endif - while (in->next()) + while (in->next()) { - list::Event event( *eventCodec, in->data() ); - if(abrupt_stop) + list::Event event(*eventCodec, in->data()); + if (abrupt_stop) { - abrupt_counter--; - if (abrupt_counter < 0) + abrupt_counter--; + if (abrupt_counter < 0) { - found = false; - break; + found = false; + break; } } - if(!event.isData() || event.isControl()) + if (!event.isData() || event.isControl()) { - timeout = 0; - continue; + timeout = 0; + continue; } - else if(event.ea() up_energy_window || - event.eb() up_energy_window) + else if (event.ea() < low_energy_window || event.ea() > up_energy_window || event.eb() < low_energy_window + || event.eb() > up_energy_window) { - timeout = 0; - continue; + timeout = 0; + continue; } - else if(keep_prompt == true && event.isPrompt()) + else if (keep_prompt == true && event.isPrompt()) { - timeout = 0; - dt = event.dt(); - xa = event.xa(); - xb = event.xb(); - za = event.za(); - zb = event.zb(); - ea = event.ea(); - eb = event.eb(); - is_delay = false; - if (xa != xb) + timeout = 0; + dt = event.dt(); + xa = event.xa(); + xb = event.xb(); + za = event.za(); + zb = event.zb(); + ea = event.ea(); + eb = event.eb(); + is_delay = false; + if (xa != xb) { - found = true; - break; - }else { - continue; + found = true; + break; + } + else + { + continue; } } - else if (keep_delayed == true && event.isDelay()) + else if (keep_delayed == true && event.isDelay()) { - timeout = 0; - - dt = event.dt(); - xa = event.xa(); - xb = event.xb(); - za = event.za(); - zb = event.zb(); - ea = event.ea(); - eb = event.eb(); - is_delay = true; - if (xa != xb) + timeout = 0; + + dt = event.dt(); + xa = event.xa(); + xb = event.xb(); + za = event.za(); + zb = event.zb(); + ea = event.ea(); + eb = event.eb(); + is_delay = true; + if (xa != xb) + { + found = true; + break; + } + else { - found = true; - break; - }else { - continue; + continue; } } - else { - continue; + else + { + continue; } } - if(found) + if (found) { - if(abrupt_stop) - if(abrupt_counter < 0) - return Succeeded::no; - return - record.init_from_data(is_delay, - dt, - xa, xb, - za, zb, - ea, eb - ); + if (abrupt_stop) + if (abrupt_counter < 0) + return Succeeded::no; + return record.init_from_data(is_delay, dt, xa, xb, za, zb, ea, eb); } - else { - return Succeeded::no; + else + { + return Succeeded::no; } - } std::string -InputStreamWithRecordsFromUPENNbin:: -method_info() const +InputStreamWithRecordsFromUPENNbin::method_info() const { - std::ostringstream s; - s << this->registered_name; - return s.str(); + std::ostringstream s; + s << this->registered_name; + return s.str(); } void InputStreamWithRecordsFromUPENNbin::set_record(const uint8_t* e) { #ifdef STIR_OPENMP -#pragma omp critical(LISTMODEIO) +# pragma omp critical(LISTMODEIO) #endif - { - out->put(e); - } + { + out->put(e); + } } void InputStreamWithRecordsFromUPENNbin::set_current_record() { - set_record(current_record); + set_record(current_record); } void InputStreamWithRecordsFromUPENNbin::set_new_record(const bool& d, const short int& _dt, - const unsigned short int& _xa, const unsigned short int& _xb, - const unsigned short int& _za, const unsigned short int& _zb, - const unsigned short int& _ea, const unsigned short int& _eb) + const unsigned short int& _xa, + const unsigned short int& _xb, + const unsigned short int& _za, + const unsigned short int& _zb, + const unsigned short int& _ea, + const unsigned short int& _eb) { - //transformations - list::EventCodec out_event(eventFormat); - - int la = 0, lb = 0; - std::uint8_t e[8]; - out_event.init(e, d, - static_cast(_dt), - la, lb, - static_cast(_xa), static_cast(_xb), - static_cast(_za), static_cast(_zb), - static_cast(_ea), static_cast(_eb)); - - set_record(e); - delete e; + // transformations + list::EventCodec out_event(eventFormat); + + int la = 0, lb = 0; + std::uint8_t e[8]; + out_event.init(e, + d, + static_cast(_dt), + la, + lb, + static_cast(_xa), + static_cast(_xb), + static_cast(_za), + static_cast(_zb), + static_cast(_ea), + static_cast(_eb)); + + set_record(e); + delete e; } Succeeded -InputStreamWithRecordsFromUPENNbin:: -set_up() +InputStreamWithRecordsFromUPENNbin::set_up() { - if ( !this->filename.empty() ) + if (!this->filename.empty()) { - if ( !inputListFile.open( filename.c_str(), std::ios_base::in | std::ios_base::binary ) ) + if (!inputListFile.open(filename.c_str(), std::ios_base::in | std::ios_base::binary)) { - error("cannot open file " + filename); + error("cannot open file " + filename); } - inputList = &inputListFile; + inputList = &inputListFile; } - if ( !list::decodeHeader( *inputList, &listHeader ) - || !list::isCoincListHeader( listHeader ) ) + if (!list::decodeHeader(*inputList, &listHeader) || !list::isCoincListHeader(listHeader)) { - error("cannot read valid header from input list"); + error("cannot read valid header from input list"); } - eventFormat = list::eventFormat( listHeader ); - eventCodec = new list::EventCodec( eventFormat ); - eventSize = list::eventSize( eventFormat ); - in = new list::InputBuffer( *inputList, eventSize ); - pos = inputListFile.pubseekoff(0, std::ios_base::cur); + eventFormat = list::eventFormat(listHeader); + eventCodec = new list::EventCodec(eventFormat); + eventSize = list::eventSize(eventFormat); + in = new list::InputBuffer(*inputList, eventSize); + pos = inputListFile.pubseekoff(0, std::ios_base::cur); - return Succeeded::yes; + return Succeeded::yes; } const PET::ListFileHeader* InputStreamWithRecordsFromUPENNbin::get_file_header() const { - return &listHeader; + return &listHeader; } - void InputStreamWithRecordsFromUPENNbin::set_defaults() { - base_type::set_defaults(); - starting_stream_position = 0; + base_type::set_defaults(); + starting_stream_position = 0; } typename InputStreamWithRecordsFromUPENNbin::SavedPosition -InputStreamWithRecordsFromUPENNbin:: -save_get_position() +InputStreamWithRecordsFromUPENNbin::save_get_position() { - int pos = inputListFile.pubseekoff(0, std::ios_base::cur); - saved_get_positions.push_back(pos); - return saved_get_positions.size()-1; + int pos = inputListFile.pubseekoff(0, std::ios_base::cur); + saved_get_positions.push_back(pos); + return saved_get_positions.size() - 1; } - Succeeded -InputStreamWithRecordsFromUPENNbin:: -set_get_position(const typename InputStreamWithRecordsFromUPENNbin::SavedPosition& pos) +InputStreamWithRecordsFromUPENNbin::set_get_position(const typename InputStreamWithRecordsFromUPENNbin::SavedPosition& pos) { - assert(pos < saved_get_positions.size()); - inputListFile.pubseekoff(saved_get_positions[pos], std::ios_base::beg); + assert(pos < saved_get_positions.size()); + inputListFile.pubseekoff(saved_get_positions[pos], std::ios_base::beg); - return Succeeded::yes; + return Succeeded::yes; } void InputStreamWithRecordsFromUPENNbin::initialise_keymap() { - base_type::initialise_keymap(); - this->parser.add_start_key("UPENN_binary_listmode Parameters"); - this->parser.add_stop_key("End UPENN_binary_listmode Parameters"); + base_type::initialise_keymap(); + this->parser.add_start_key("UPENN_binary_listmode Parameters"); + this->parser.add_stop_key("End UPENN_binary_listmode Parameters"); } bool InputStreamWithRecordsFromUPENNbin::post_processing() { - if (base_type::post_processing()) - return true; - return false; + if (base_type::post_processing()) + return true; + return false; } END_NAMESPACE_STIR diff --git a/src/IO/InputStreamWithRecordsFromUPENNtxt.cxx b/src/IO/InputStreamWithRecordsFromUPENNtxt.cxx index 0f3dc9d25..06ea7aa49 100644 --- a/src/IO/InputStreamWithRecordsFromUPENNtxt.cxx +++ b/src/IO/InputStreamWithRecordsFromUPENNtxt.cxx @@ -20,163 +20,152 @@ START_NAMESPACE_STIR -const char * const -InputStreamWithRecordsFromUPENNtxt::registered_name = - "UPENN_txt_listmode"; +const char* const InputStreamWithRecordsFromUPENNtxt::registered_name = "UPENN_txt_listmode"; -InputStreamWithRecordsFromUPENNtxt:: -InputStreamWithRecordsFromUPENNtxt(): - base_type() +InputStreamWithRecordsFromUPENNtxt::InputStreamWithRecordsFromUPENNtxt() + : base_type() { - error("The text variant of the listmode files has several pending TODOs. Don't use right now."); - set_defaults(); + error("The text variant of the listmode files has several pending TODOs. Don't use right now."); + set_defaults(); } Succeeded -InputStreamWithRecordsFromUPENNtxt:: -reset() +InputStreamWithRecordsFromUPENNtxt::reset() { - if (is_null_ptr(stream_ptr)) - return Succeeded::no; - - // Strangely enough, once you read past EOF, even seekg(0) doesn't reset the eof flag - if (stream_ptr->eof()) - stream_ptr->clear(); - stream_ptr->seekg(starting_stream_position, std::ios::beg); - if (stream_ptr->bad()) - return Succeeded::no; - else - return Succeeded::yes; + if (is_null_ptr(stream_ptr)) + return Succeeded::no; + + // Strangely enough, once you read past EOF, even seekg(0) doesn't reset the eof flag + if (stream_ptr->eof()) + stream_ptr->clear(); + stream_ptr->seekg(starting_stream_position, std::ios::beg); + if (stream_ptr->bad()) + return Succeeded::no; + else + return Succeeded::yes; } Succeeded -InputStreamWithRecordsFromUPENNtxt:: -get_next_record(CListRecordPENN& record) +InputStreamWithRecordsFromUPENNtxt::get_next_record(CListRecordPENN& record) { - int dt = 0; - int xa = 0; - int xb = 0; - int za = 0; - int zb = 0; - int ea = 0; - int eb = 0; - bool is_delay = false; - bool found = false; + int dt = 0; + int xa = 0; + int xb = 0; + int za = 0; + int zb = 0; + int ea = 0; + int eb = 0; + bool is_delay = false; + bool found = false; #ifdef STIR_OPENMP -#pragma omp critical(LISTMODEIO) +# pragma omp critical(LISTMODEIO) #endif - while(true) + while (true) { - std::getline(*stream_ptr, *line); + std::getline(*stream_ptr, *line); - if (stream_ptr->eof()) + if (stream_ptr->eof()) { - found = false; - break; + found = false; + break; } - else if (stream_ptr->bad()) + else if (stream_ptr->bad()) { - warning("InputStreamWithRecordsFromUPENNtxt: Error after reading from list mode stream in get_next_record"); - found = false; - break; + warning("InputStreamWithRecordsFromUPENNtxt: Error after reading from list mode stream in get_next_record"); + found = false; + break; } - else if (keep_prompt == true && line->at(0)=='p') + else if (keep_prompt == true && line->at(0) == 'p') { - is_delay = false; - found = true; - break; + is_delay = false; + found = true; + break; } - else if (keep_delayed == true && line->at(0)=='d') + else if (keep_delayed == true && line->at(0) == 'd') { - is_delay = true; - found = true; - break; + is_delay = true; + found = true; + break; } } - if(!found) - return Succeeded::no; + if (!found) + return Succeeded::no; - std::istringstream iss(*line); - std::vector results((std::istream_iterator(iss)), - std::istream_iterator()); + std::istringstream iss(*line); + std::vector results((std::istream_iterator(iss)), std::istream_iterator()); - dt = stoi(results[1]); + dt = stoi(results[1]); - xa = stoi(results[4]); - xb = stoi(results[5]); + xa = stoi(results[4]); + xb = stoi(results[5]); - za = stoi(results[6]); - zb = stoi(results[7]); + za = stoi(results[6]); + zb = stoi(results[7]); - ea = stoi(results[8]); - eb = stoi(results[9]); + ea = stoi(results[8]); + eb = stoi(results[9]); - return - record.init_from_data(is_delay, - dt, - xa, xb, - za, zb, - ea, eb); + return record.init_from_data(is_delay, dt, xa, xb, za, zb, ea, eb); } void InputStreamWithRecordsFromUPENNtxt::set_current_record() { - //set_record(current_record); - error("InputStreamWithRecordsFromUPENNtxt::set_current_record not implemented, yet."); + // set_record(current_record); + error("InputStreamWithRecordsFromUPENNtxt::set_current_record not implemented, yet."); } void InputStreamWithRecordsFromUPENNtxt::set_new_record(const bool& d, const short int& _dt, - const unsigned short int& _xa, const unsigned short int& _xb, - const unsigned short int& _za, const unsigned short int& _zb, - const unsigned short int& _ea, const unsigned short int& _eb) + const unsigned short int& _xa, + const unsigned short int& _xb, + const unsigned short int& _za, + const unsigned short int& _zb, + const unsigned short int& _ea, + const unsigned short int& _eb) { - // Create a new line and replace the old one - error("InputStreamWithRecordsFromUPENNtxt::set_new_record not implemented, yet."); + // Create a new line and replace the old one + error("InputStreamWithRecordsFromUPENNtxt::set_new_record not implemented, yet."); } Succeeded -InputStreamWithRecordsFromUPENNtxt:: -set_up() +InputStreamWithRecordsFromUPENNtxt::set_up() { - return Succeeded::yes; + return Succeeded::yes; } std::string -InputStreamWithRecordsFromUPENNtxt:: -method_info() const +InputStreamWithRecordsFromUPENNtxt::method_info() const { - return this->registered_name; + return this->registered_name; } void InputStreamWithRecordsFromUPENNtxt::set_defaults() { - starting_stream_position = 0; + starting_stream_position = 0; } void InputStreamWithRecordsFromUPENNtxt::initialise_keymap() { - base_type::initialise_keymap(); - this->parser.add_start_key("UPENN_text_listmode Parameters"); - this->parser.add_stop_key("End UPENN_text_listmode Parameters"); + base_type::initialise_keymap(); + this->parser.add_start_key("UPENN_text_listmode Parameters"); + this->parser.add_stop_key("End UPENN_text_listmode Parameters"); } bool InputStreamWithRecordsFromUPENNtxt::post_processing() { - return false; + return false; } typename InputStreamWithRecordsFromUPENNtxt::SavedPosition -InputStreamWithRecordsFromUPENNtxt:: -save_get_position() +InputStreamWithRecordsFromUPENNtxt::save_get_position() { assert(!is_null_ptr(stream_ptr)); // TODO should somehow check if tellg() worked and return an error if it didn't @@ -185,8 +174,8 @@ save_get_position() { pos = stream_ptr->tellg(); if (!stream_ptr->good()) - error("InputStreamWithRecords::save_get_position\n" - "Error after getting position in file"); + error("InputStreamWithRecords::save_get_position\n" + "Error after getting position in file"); } else { @@ -195,12 +184,11 @@ save_get_position() pos = std::streampos(-1); } saved_get_positions.push_back(pos); - return saved_get_positions.size()-1; + return saved_get_positions.size() - 1; } Succeeded -InputStreamWithRecordsFromUPENNtxt:: -set_get_position(const typename InputStreamWithRecordsFromUPENNtxt::SavedPosition& pos) +InputStreamWithRecordsFromUPENNtxt::set_get_position(const typename InputStreamWithRecordsFromUPENNtxt::SavedPosition& pos) { if (is_null_ptr(stream_ptr)) return Succeeded::no; diff --git a/src/IO/InterfileDynamicDiscretisedDensityOutputFileFormat.cxx b/src/IO/InterfileDynamicDiscretisedDensityOutputFileFormat.cxx index 5c62a302f..222348c5d 100644 --- a/src/IO/InterfileDynamicDiscretisedDensityOutputFileFormat.cxx +++ b/src/IO/InterfileDynamicDiscretisedDensityOutputFileFormat.cxx @@ -21,7 +21,7 @@ */ #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" @@ -29,77 +29,64 @@ 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) +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"); + 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 +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; + // 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 a43af0899..ab1384635 100644 --- a/src/IO/InterfileHeader.cxx +++ b/src/IO/InterfileHeader.cxx @@ -11,8 +11,8 @@ See STIR/LICENSE.txt for details */ /*! - \file - \ingroup InterfileIO + \file + \ingroup InterfileIO \brief implementations for the stir::InterfileHeader class \author Kris Thielemans @@ -47,9 +47,7 @@ using std::string; using std::vector; 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 @@ -64,19 +62,21 @@ MinimalInterfileHeader::get_exam_info() const } MinimalInterfileHeader::MinimalInterfileHeader() - : KeyParser() + : 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); - + KeyArgument::ASCII, + (KeywordProcessor)&MinimalInterfileHeader::set_imaging_modality, + &imaging_modality_as_string); + add_key("version of keys", - KeyArgument::ASCII, (KeywordProcessor)&MinimalInterfileHeader::set_version_specific_keys, + KeyArgument::ASCII, + (KeywordProcessor)&MinimalInterfileHeader::set_version_specific_keys, &version_of_keys); // support for siemens interfile @@ -84,38 +84,38 @@ 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() + : 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"); @@ -123,49 +123,49 @@ 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("calibration factor", &calibration_factor); + + add_key("calibration factor", &calibration_factor); // deprecated, but used by Siemens add_key("isotope name", &isotope_name); ignore_key("number of radionuclides"); // just always use 1. TODO should check really @@ -187,39 +187,28 @@ InterfileHeader::InterfileHeader() add_vectorised_key("radionuclide branching factor", &radionuclide_branching_ratio); add_key("study date", &study_date_time.date); add_key("study_time", &study_date_time.time); - add_key("type of data", + add_key("type of data", KeyArgument::ASCIIlist, (KeywordProcessor)&InterfileHeader::set_type_of_data, - &type_of_data_index, + &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"); @@ -232,7 +221,9 @@ InterfileHeader::InterfileHeader() add_key("quantification units", &lln_quantification_units); add_key("number of energy windows", - KeyArgument::INT, (KeywordProcessor)&InterfileHeader::read_num_energy_windows,&num_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); @@ -242,7 +233,8 @@ 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") @@ -257,9 +249,10 @@ void InterfileHeader::set_version_specific_keys() } // MJ 17/05/2000 made bool -bool InterfileHeader::post_processing() +bool +InterfileHeader::post_processing() { - if(type_of_data_index<0) + if (type_of_data_index < 0) { warning("Interfile Warning: 'type_of_data' keyword required"); return true; @@ -269,163 +262,161 @@ bool InterfileHeader::post_processing() { try { - exam_info_sptr->start_time_in_secs_since_1970 = - Interfile_datetime_to_secs_since_Unix_epoch(study_date_time); + exam_info_sptr->start_time_in_secs_since_1970 = Interfile_datetime_to_secs_since_Unix_epoch(study_date_time); } - catch(...) + catch (...) {} } - + this->exam_info_sptr->set_calibration_factor(calibration_factor); const bool is_spect = this->exam_info_sptr->imaging_modality.get_modality() == ImagingModality::NM; // radionuclide { - RadionuclideDB radionuclide_db; - const std::string rn_name = !this->radionuclide_name[0].empty()? - this->radionuclide_name[0] : this->isotope_name; - auto radionuclide = radionuclide_db.get_radionuclide(exam_info_sptr->imaging_modality, rn_name); - if (radionuclide.get_half_life(false) < 0) - radionuclide = Radionuclide(rn_name.empty() ? "Unknown" : rn_name, - is_spect ? -1.F : 511.F, // TODO handle energy for SPECT - radionuclide_branching_ratio[0], radionuclide_half_life[0], this->exam_info_sptr->imaging_modality); - this->exam_info_sptr->set_radionuclide(radionuclide); + RadionuclideDB radionuclide_db; + const std::string rn_name = !this->radionuclide_name[0].empty() ? this->radionuclide_name[0] : this->isotope_name; + auto radionuclide = radionuclide_db.get_radionuclide(exam_info_sptr->imaging_modality, rn_name); + if (radionuclide.get_half_life(false) < 0) + radionuclide = Radionuclide(rn_name.empty() ? "Unknown" : rn_name, + is_spect ? -1.F : 511.F, // TODO handle energy for SPECT + radionuclide_branching_ratio[0], + radionuclide_half_life[0], + this->exam_info_sptr->imaging_modality); + this->exam_info_sptr->set_radionuclide(radionuclide); } - - 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 (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; - } + 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) - { - warning("Interfile error: 'number of bytes per pixel' keyword should be set\n to a number > 0"); - return true; - } + 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) - { - warning("Interfile error: no matrix size keywords present\n"); - return true; - } - for (unsigned int dim=0; dim != matrix_size.size(); ++dim) - { - if (matrix_size[dim].size()==0) + if (matrix_size.size() == 0) { - warning("Interfile error: dimension (%d) of 'matrix size' not present\n", dim); + warning("Interfile error: no matrix size keywords present\n"); return true; } - for (unsigned int i=0; i != matrix_size[dim].size(); ++i) + for (unsigned int dim = 0; dim != matrix_size.size(); ++dim) { - 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; - } + 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) + { + 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++) { - // 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]) - { - warning("Interfile error: wrong number of image scaling factors\n"); - return true; + 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(); 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++) { - 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; + // 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; + } + // 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 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); - } - } // lln_quantification_units - if (num_energy_windows>0) + 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) + 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 ) + 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"); @@ -436,25 +427,20 @@ void InterfileHeader::set_type_of_data() 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); + 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 + // 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 (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); + add_key("process status", &process_status_index, &process_status_values); #if 0 // overwrite vectored-value, as v3.3 had a scalar @@ -463,12 +449,13 @@ void InterfileHeader::set_type_of_data() } } -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; - + if (PET_data_type_values[PET_data_type_index] != "Image") - { warning("Interfile error: expecting an image\n"); return true; } - + { + warning("Interfile error: expecting an image\n"); + return true; + } + if (num_dimensions != 3) - { warning("Interfile error: expecting 3D image\n"); return true; } + { + 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 ((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")) + 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; + return true; } - std::vector first_pixel_offsets; + std::vector first_pixel_offsets; return false; } /**********************************************************************/ -//KT 26/10/98 -// KT 13/11/98 moved stream arg from constructor to parse() +// KT 26/10/98 +// KT 13/11/98 moved stream arg from constructor to parse() InterfilePDFSHeader::InterfilePDFSHeader() - : InterfileHeader() + : InterfileHeader() { num_segments = -1; add_key("minimum ring difference per segment", - KeyArgument::LIST_OF_INTS, - (KeywordProcessor)&InterfilePDFSHeader::resize_segments_and_set, - &min_ring_difference); + 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); - + KeyArgument::LIST_OF_INTS, + (KeywordProcessor)&InterfilePDFSHeader::resize_segments_and_set, + &max_ring_difference); + tof_mash_factor = 1; - add_key("TOF mashing factor", - &tof_mash_factor); + add_key("TOF mashing factor", &tof_mash_factor); #if STIR_VERSION < 070000 add_alias_key("TOF mashing factor", "%TOF mashing factor"); #endif @@ -578,153 +571,124 @@ 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); max_num_timing_poss = -1; - add_key("Maximum number of (unmashed) TOF time bins", - &max_num_timing_poss); + add_key("Maximum number of (unmashed) TOF time bins", &max_num_timing_poss); #if STIR_VERSION < 070000 add_alias_key("Maximum number of (unmashed) TOF time bins", "Number of TOF time bins"); #endif size_of_timing_pos = -1.f; - add_key("Size of unmashed TOF time bins (ps)", - &size_of_timing_pos); + add_key("Size of unmashed TOF time bins (ps)", &size_of_timing_pos); #if STIR_VERSION < 070000 add_alias_key("Size of unmashed TOF time bins (ps)", "Size of timing bin (ps)"); #endif timing_resolution = -1.f; - add_key("TOF timing resolution (ps)", - &timing_resolution); + add_key("TOF timing resolution (ps)", &timing_resolution); #if STIR_VERSION < 070000 add_alias_key("TOF timing resolution (ps)", "timing resolution (ps)"); #endif // new keys for block geometry scanner_geometry = "Cylindrical"; - add_key("Scanner geometry (BlocksOnCylindrical/Cylindrical/Generic)", - KeyArgument::ASCII, &scanner_geometry); + add_key("Scanner geometry (BlocksOnCylindrical/Cylindrical/Generic)", KeyArgument::ASCII, &scanner_geometry); axial_distance_between_crystals_in_cm = -0.1; - add_key("distance between crystals in axial direction (cm)", - &axial_distance_between_crystals_in_cm); + add_key("distance between crystals in axial direction (cm)", &axial_distance_between_crystals_in_cm); transaxial_distance_between_crystals_in_cm = -0.1; - add_key("distance between crystals in transaxial direction (cm)", - &transaxial_distance_between_crystals_in_cm); + add_key("distance between crystals in transaxial direction (cm)", &transaxial_distance_between_crystals_in_cm); axial_distance_between_blocks_in_cm = -0.1; - add_key("distance between blocks in axial direction (cm)", - &axial_distance_between_blocks_in_cm); + add_key("distance between blocks in axial direction (cm)", &axial_distance_between_blocks_in_cm); transaxial_distance_between_blocks_in_cm = -0.1; - add_key("distance between blocks in transaxial direction (cm)", - &transaxial_distance_between_blocks_in_cm); + add_key("distance between blocks in transaxial direction (cm)", &transaxial_distance_between_blocks_in_cm); // end of new keys for block geometry - //new keys for generic geometry + // new keys for generic geometry crystal_map = ""; add_key("Name of crystal map", &crystal_map); - //end of new keys for generic geometry + // end of new keys for generic geometry 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()) - { - min_ring_difference.resize(num_segments); - max_ring_difference.resize(num_segments); - - } - + { + 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 && - num_dimensions != 5) - { - warning("Interfile error: expecting 4D structure or 5D in case of TOF information "); - stop_parsing(); - return true; - } + if (num_dimensions != 4 && num_dimensions != 5) + { + warning("Interfile error: expecting 4D structure or 5D in case of TOF information "); + stop_parsing(); + return true; + } if (num_dimensions == 4) { @@ -734,64 +698,63 @@ int InterfilePDFSHeader::find_storage_order() } 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"); - stop_parsing(); - return true; - } + { + // use error message with index [1] as that is what the user sees. + warning("Interfile error: expecting 'matrix axis label[1] := tangential coordinate'\n"); + stop_parsing(); + return true; + } num_bins = matrix_size[0][0]; - - if (matrix_labels[3] == "segment") - { - num_segments = matrix_size[3][0]; - if (matrix_labels[1] == "axial coordinate" && matrix_labels[2] == "view") + if (matrix_labels[3] == "segment") { - // If TOF information is in there - if (matrix_labels.size() > 4) + num_segments = matrix_size[3][0]; + + if (matrix_labels[1] == "axial coordinate" && matrix_labels[2] == "view") { - if (matrix_labels[4] == "timing positions") + // If TOF information is in there + if (matrix_labels.size() > 4) { - num_timing_poss = matrix_size[4][0]; - storage_order = ProjDataFromStream::Timing_Segment_View_AxialPos_TangPos; - num_views = matrix_size[2][0]; + 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]; + num_rings_per_segment.assign(matrix_size[1].begin(), matrix_size[1].end()); +#else + num_rings_per_segment = matrix_size[1]; #endif + } + else + error("Interfile header parsing: currently need 'matrix axis label [5] := timing positions' for TOF data"); } - else - error("Interfile header parsing: currently need 'matrix axis label [5] := timing positions' for TOF data"); - } - else - { - storage_order = ProjDataFromStream::Segment_View_AxialPos_TangPos; - num_views = matrix_size[2][0]; + 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()); + 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 = matrix_size[1]; #endif + } } - } - else if (matrix_labels[1] == "view" && matrix_labels[2] == "axial coordinate") - { - storage_order = ProjDataFromStream::Segment_AxialPos_View_TangPos; - num_views = matrix_size[1][0]; + 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()); - + + num_rings_per_segment.assign(matrix_size[2].begin(), matrix_size[2].end()); + #else - num_rings_per_segment = matrix_size[2]; + 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; @@ -802,56 +765,50 @@ 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"); - stop_parsing(); - return true; - } - + { + warning("Interfile error: matrix labels not in expected (or supported) format\n"); + stop_parsing(); + 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: - 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) + 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(min_ring_difference[i] + max_ring_difference[i]); - sum_and_location[i].second = i; - } + assert(num_segments % 2 == 1); + + vector> 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; + } #if 0 cerr<< "DISPLAY SUM and LOCATION\n"<& 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."); - } - - vector< pair > location_and_segment_num(num_segments); - for (int i=0; i 1E-3) + { + error("This data does not seem to contain segment 0. \n" + "We can't handle this at the moment. Sorry."); + } + + vector> 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; + } #if 0 cerr<< "display location segment\n"<& 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 cerr<< "sorted_min_ring_diff\n"<& 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"); - return true; - } + { + warning("Interfile error: expecting emission data\n"); + return true; + } + + if (min_ring_difference.size() != static_cast(num_segments)) + { + warning("Interfile error: per-segment information is inconsistent: min_ring_difference\n"); + return true; + } 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; - } - + { + 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) - { - warning("\nParsing Interfile header for projection data: \n" - "\t'applied corrections' keyword not found. Assuming arc-corrected data\n"); - is_arccorrected = true; - } + { + warning("\nParsing Interfile header for projection data: \n" + "\t'applied corrections' keyword not found. Assuming arc-corrected data\n"); + is_arccorrected = true; + } else - { - is_arccorrected = false; - for ( - auto iter = applied_corrections.begin(); - iter != applied_corrections.end(); - ++iter) { - const string correction = standardise_keyword(*iter); - 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()); - + is_arccorrected = false; + for (auto iter = applied_corrections.begin(); iter != applied_corrections.end(); ++iter) + { + const string correction = standardise_keyword(*iter); + 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()); + } } - - } - + 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 :"; @@ -1079,472 +1023,432 @@ bool InterfilePDFSHeader::post_processing() << std::accumulate(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; + bool originating_system_was_recognised = guessed_scanner_ptr->get_type() != Scanner::Unknown_scanner; if (!originating_system_was_recognised) - { - warning("Interfile warning: I did not recognise the scanner from 'originating_system' (" - + get_exam_info().originating_system + ")"); - } + { + warning("Interfile warning: I did not recognise the scanner from 'originating_system' (" + + get_exam_info().originating_system + ")"); + } bool mismatch_between_header_and_guess = false; // check if STIR info matches the one in the header, and fill in missing details - 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 - - 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; + 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 + + 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; #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.; - if (average_depth_of_interaction_in_cm < 0) - 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; - if (default_bin_size_in_cm < 0) - 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) - num_axial_blocks_per_bucket = guessed_scanner_ptr->get_num_axial_blocks_per_bucket(); - 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) - num_axial_crystals_per_block = guessed_scanner_ptr->get_num_axial_crystals_per_block(); - 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) - num_detector_layers = guessed_scanner_ptr->get_num_detector_layers(); - if (energy_resolution < 0) + if (inner_ring_diameter_in_cm < 0) + 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; + if (distance_between_rings_in_cm < 0) + 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; + 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) + num_axial_blocks_per_bucket = guessed_scanner_ptr->get_num_axial_blocks_per_bucket(); + 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) + num_axial_crystals_per_block = guessed_scanner_ptr->get_num_axial_crystals_per_block(); + 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) + num_detector_layers = guessed_scanner_ptr->get_num_detector_layers(); + if (energy_resolution < 0) energy_resolution = guessed_scanner_ptr->get_energy_resolution(); - if (reference_energy < 0) + if (reference_energy < 0) reference_energy = guessed_scanner_ptr->get_reference_energy(); - - // new variables for block geometry - if (axial_distance_between_crystals_in_cm < 0) - axial_distance_between_crystals_in_cm = guessed_scanner_ptr->get_transaxial_crystal_spacing()/10; - if (transaxial_distance_between_crystals_in_cm < 0) - transaxial_distance_between_crystals_in_cm = guessed_scanner_ptr->get_transaxial_crystal_spacing()/10; - if (axial_distance_between_blocks_in_cm < 0) - axial_distance_between_blocks_in_cm = guessed_scanner_ptr->get_axial_block_spacing()/10; - if (transaxial_distance_between_blocks_in_cm < 0) - transaxial_distance_between_blocks_in_cm = guessed_scanner_ptr->get_transaxial_block_spacing()/10; - // end of new variables for block geometry - - if (guessed_scanner_ptr->is_tof_ready()) - { - if (max_num_timing_poss < 0) - max_num_timing_poss = guessed_scanner_ptr->get_max_num_timing_poss(); - if (size_of_timing_pos < 0) - size_of_timing_pos = guessed_scanner_ptr->get_size_of_timing_pos(); - if (timing_resolution < 0) - timing_resolution = guessed_scanner_ptr->get_timing_resolution(); - } - - - // consistency check with values of the guessed_scanner_ptr we guessed above - - if (num_rings != guessed_scanner_ptr->get_num_rings()) - { - warning(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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; - } - } - - // new variables for block geometry - if (fabs(axial_distance_between_crystals_in_cm - -guessed_scanner_ptr->get_axial_crystal_spacing()/10) > .001) - { - warning(boost::format("Interfile warning: 'distance between crystals in axial direction (cm)' (%f) is expected to be %f.\n") % - axial_distance_between_crystals_in_cm % (guessed_scanner_ptr->get_axial_crystal_spacing()/10)); - mismatch_between_header_and_guess = true; - } - if (fabs(transaxial_distance_between_crystals_in_cm - -guessed_scanner_ptr->get_transaxial_crystal_spacing()/10) > .001) - { - warning(boost::format("Interfile warning: 'distance between crystals in transaxial direction (cm)' (%f) is expected to be %f.\n") % - transaxial_distance_between_crystals_in_cm % (guessed_scanner_ptr->get_transaxial_crystal_spacing()/10)); - mismatch_between_header_and_guess = true; - } - if (fabs(axial_distance_between_blocks_in_cm - -guessed_scanner_ptr->get_axial_block_spacing()/10) > .001) - { - warning(boost::format("Interfile warning: 'distance between crystals in axial direction (cm)' (%f) is expected to be %f.\n") % - axial_distance_between_blocks_in_cm % (guessed_scanner_ptr->get_axial_block_spacing()/10)); - mismatch_between_header_and_guess = true; - } - if (fabs(transaxial_distance_between_blocks_in_cm - -guessed_scanner_ptr->get_transaxial_block_spacing()/10) > .001) - { - warning(boost::format("Interfile warning: 'distance between crystals in axial direction (cm)' (%f) is expected to be %f.\n") % - transaxial_distance_between_blocks_in_cm % (guessed_scanner_ptr->get_transaxial_block_spacing()/10)); - mismatch_between_header_and_guess = true; - } - // end of new variables for block geometry - - if (guessed_scanner_ptr->is_tof_ready()) - { - if (max_num_timing_poss != guessed_scanner_ptr->get_max_num_timing_poss()) - { - warning(boost::format("Interfile warning: 'Maximum number of (unmashed) 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 (abs(size_of_timing_pos - guessed_scanner_ptr->get_size_of_timing_pos()) > 0.001F) - { - warning(boost::format("Interfile warning: 'Size of unmashed TOF 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 (abs(timing_resolution - guessed_scanner_ptr->get_timing_resolution()) > 0.01F) - { - warning(boost::format("Interfile warning: 'TOF 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(boost::format("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)); - } + // new variables for block geometry + if (axial_distance_between_crystals_in_cm < 0) + axial_distance_between_crystals_in_cm = guessed_scanner_ptr->get_transaxial_crystal_spacing() / 10; + if (transaxial_distance_between_crystals_in_cm < 0) + transaxial_distance_between_crystals_in_cm = guessed_scanner_ptr->get_transaxial_crystal_spacing() / 10; + if (axial_distance_between_blocks_in_cm < 0) + axial_distance_between_blocks_in_cm = guessed_scanner_ptr->get_axial_block_spacing() / 10; + if (transaxial_distance_between_blocks_in_cm < 0) + transaxial_distance_between_blocks_in_cm = guessed_scanner_ptr->get_transaxial_block_spacing() / 10; + // end of new variables for block geometry + + if (guessed_scanner_ptr->is_tof_ready()) + { + if (max_num_timing_poss < 0) + max_num_timing_poss = guessed_scanner_ptr->get_max_num_timing_poss(); + if (size_of_timing_pos < 0) + size_of_timing_pos = guessed_scanner_ptr->get_size_of_timing_pos(); + if (timing_resolution < 0) + timing_resolution = guessed_scanner_ptr->get_timing_resolution(); + } + + // consistency check with values of the guessed_scanner_ptr we guessed above + + if (num_rings != guessed_scanner_ptr->get_num_rings()) + { + warning(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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(boost::format("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; + } + } + + // new variables for block geometry + if (fabs(axial_distance_between_crystals_in_cm - guessed_scanner_ptr->get_axial_crystal_spacing() / 10) > .001) + { + warning( + boost::format("Interfile warning: 'distance between crystals in axial direction (cm)' (%f) is expected to be %f.\n") + % axial_distance_between_crystals_in_cm % (guessed_scanner_ptr->get_axial_crystal_spacing() / 10)); + mismatch_between_header_and_guess = true; + } + if (fabs(transaxial_distance_between_crystals_in_cm - guessed_scanner_ptr->get_transaxial_crystal_spacing() / 10) > .001) + { + warning(boost::format( + "Interfile warning: 'distance between crystals in transaxial direction (cm)' (%f) is expected to be %f.\n") + % transaxial_distance_between_crystals_in_cm % (guessed_scanner_ptr->get_transaxial_crystal_spacing() / 10)); + mismatch_between_header_and_guess = true; + } + if (fabs(axial_distance_between_blocks_in_cm - guessed_scanner_ptr->get_axial_block_spacing() / 10) > .001) + { + warning( + boost::format("Interfile warning: 'distance between crystals in axial direction (cm)' (%f) is expected to be %f.\n") + % axial_distance_between_blocks_in_cm % (guessed_scanner_ptr->get_axial_block_spacing() / 10)); + mismatch_between_header_and_guess = true; + } + if (fabs(transaxial_distance_between_blocks_in_cm - guessed_scanner_ptr->get_transaxial_block_spacing() / 10) > .001) + { + warning( + boost::format("Interfile warning: 'distance between crystals in axial direction (cm)' (%f) is expected to be %f.\n") + % transaxial_distance_between_blocks_in_cm % (guessed_scanner_ptr->get_transaxial_block_spacing() / 10)); + mismatch_between_header_and_guess = true; + } + // end of new variables for block geometry + + if (guessed_scanner_ptr->is_tof_ready()) + { + if (max_num_timing_poss != guessed_scanner_ptr->get_max_num_timing_poss()) + { + warning(boost::format("Interfile warning: 'Maximum number of (unmashed) 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 (abs(size_of_timing_pos - guessed_scanner_ptr->get_size_of_timing_pos()) > 0.001F) + { + warning(boost::format("Interfile warning: 'Size of unmashed TOF 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 (abs(timing_resolution - guessed_scanner_ptr->get_timing_resolution()) > 0.01F) + { + warning(boost::format("Interfile warning: 'TOF 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(boost::format("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) - { - // warn if the Interfile header does not provide enough info + if (guessed_scanner_ptr->get_type() == Scanner::Unknown_scanner + || guessed_scanner_ptr->get_type() == Scanner::User_defined_scanner) + { + // warn if the Interfile header does not provide enough info - if (num_rings < 1) - warning("Interfile warning: 'number of rings' invalid.\n"); - if (num_detectors_per_ring < 1) - warning("Interfile warning: 'num_detectors_per_ring' invalid.\n"); + if (num_rings < 1) + warning("Interfile warning: 'number of rings' invalid.\n"); + if (num_detectors_per_ring < 1) + warning("Interfile warning: 'num_detectors_per_ring' invalid.\n"); #if 0 if (transaxial_FOV_diameter_in_cm < 0) warning("Interfile warning: 'transaxial FOV diameter (cm)' invalid.\n"); #endif - if (inner_ring_diameter_in_cm <= 0) - warning("Interfile warning: 'inner ring diameter (cm)' invalid. This might disastrous\n"); - if (average_depth_of_interaction_in_cm <= 0) - warning("Interfile warning: 'average depth of interaction (cm)' invalid. This might be disastrous.\n"); - if (distance_between_rings_in_cm <= 0) - warning("Interfile warning: 'distance between rings (cm)' invalid.\n"); - if (default_bin_size_in_cm <= 0) - warning("Interfile warning: 'default_bin size (cm)' invalid.\n"); - if (num_axial_crystals_per_singles_unit <= 0) - 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"); - // new variables for block geometry - if (axial_distance_between_crystals_in_cm <= 0) - warning("Interfile warning: 'distance between crystals in axial direction (cm)' invalid.\n"); - if (transaxial_distance_between_crystals_in_cm <= 0) - warning("Interfile warning: 'distance between crystals in transaxial direction (cm)' invalid.\n"); - if (axial_distance_between_blocks_in_cm <= 0) - warning("Interfile warning: 'distance between blocks in axial direction (cm)' invalid.\n"); - if (transaxial_distance_between_blocks_in_cm <= 0) - warning("Interfile warning: 'distance between blocks in transaxial direction (cm)' invalid.\n"); - // end of new variables for block geometry - } + if (inner_ring_diameter_in_cm <= 0) + warning("Interfile warning: 'inner ring diameter (cm)' invalid. This might disastrous\n"); + if (average_depth_of_interaction_in_cm <= 0) + warning("Interfile warning: 'average depth of interaction (cm)' invalid. This might be disastrous.\n"); + if (distance_between_rings_in_cm <= 0) + warning("Interfile warning: 'distance between rings (cm)' invalid.\n"); + if (default_bin_size_in_cm <= 0) + warning("Interfile warning: 'default_bin size (cm)' invalid.\n"); + if (num_axial_crystals_per_singles_unit <= 0) + 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"); + // new variables for block geometry + if (axial_distance_between_crystals_in_cm <= 0) + warning("Interfile warning: 'distance between crystals in axial direction (cm)' invalid.\n"); + if (transaxial_distance_between_crystals_in_cm <= 0) + warning("Interfile warning: 'distance between crystals in transaxial direction (cm)' invalid.\n"); + if (axial_distance_between_blocks_in_cm <= 0) + warning("Interfile warning: 'distance between blocks in axial direction (cm)' invalid.\n"); + if (transaxial_distance_between_blocks_in_cm <= 0) + warning("Interfile warning: 'distance between blocks in transaxial direction (cm)' invalid.\n"); + // end of new variables for block geometry + } // finally, we construct a new scanner object with // data from the Interfile header (or the guessed scanner). - shared_ptr scanner_sptr_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(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, - scanner_geometry, - static_cast(axial_distance_between_crystals_in_cm*10.), - static_cast(transaxial_distance_between_crystals_in_cm*10.), - static_cast(axial_distance_between_blocks_in_cm*10.), - static_cast(transaxial_distance_between_blocks_in_cm*10.), - crystal_map - )); - - 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) + shared_ptr scanner_sptr_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(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, + scanner_geometry, + static_cast(axial_distance_between_crystals_in_cm * 10.), + static_cast(transaxial_distance_between_crystals_in_cm * 10.), + static_cast(axial_distance_between_blocks_in_cm * 10.), + static_cast(transaxial_distance_between_blocks_in_cm * 10.), + crystal_map)); + + 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(boost::format("Interfile parsing ended up with the following scanner:\n%s\n") % - scanner_sptr_from_file->parameter_info()); + warning(boost::format("Interfile parsing ended up with the following scanner:\n%s\n") + % scanner_sptr_from_file->parameter_info()); } - - + // float azimuthal_angle_sampling =_PI/num_views; - + if (scanner_geometry == "Cylindrical") { - 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(boost::format("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(boost::format("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.)); - } - } - } - else if(scanner_geometry == "BlocksOnCylindrical")// if block geometry - { - data_info_sptr.reset( - new ProjDataInfoBlocksOnCylindricalNoArcCorr ( - scanner_sptr_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) + if (is_arccorrected) { - warning(boost::format("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.)); - } - } - else // if generic geometry + 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(boost::format("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 ProjDataInfoGenericNoArcCorr ( - scanner_sptr_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) + 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(boost::format("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.)); + warning(boost::format("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.)); } } + } + else if (scanner_geometry == "BlocksOnCylindrical") // if block geometry + { + data_info_sptr.reset(new ProjDataInfoBlocksOnCylindricalNoArcCorr( + scanner_sptr_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(boost::format("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.)); + } + } + else // if generic geometry + { + data_info_sptr.reset(new ProjDataInfoGenericNoArcCorr( + scanner_sptr_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(boost::format("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 (data_info_sptr->get_num_tof_poss() != num_timing_poss) error(boost::format("Interfile header parsing with TOF: inconsistency between number of TOF bins in data (%d), " "TOF mashing factor (%d) and max number of TOF bins in scanner info (%d)") % num_timing_poss % tof_mash_factor % scanner_sptr_from_file->get_max_num_timing_poss()); - //cerr << data_info_sptr->parameter_info() << endl; - + // cerr << data_info_sptr->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 28dd03cc2..0af8607f6 100644 --- a/src/IO/InterfileHeaderSiemens.cxx +++ b/src/IO/InterfileHeaderSiemens.cxx @@ -8,8 +8,8 @@ See STIR/LICENSE.txt for details */ /*! - \file - \ingroup InterfileIO + \file + \ingroup InterfileIO \brief implementations for the stir::InterfileHeaderSiemens classes \author Kris Thielemans @@ -40,7 +40,7 @@ using std::vector; START_NAMESPACE_STIR InterfileHeaderSiemens::InterfileHeaderSiemens() - : InterfileHeader() + : InterfileHeader() { // always PET exam_info_sptr->imaging_modality = ImagingModality::PT; @@ -56,18 +56,18 @@ InterfileHeaderSiemens::InterfileHeaderSiemens() PET_data_type_values.push_back("AttenuationCorrection"); PET_data_type_values.push_back("Normalization"); 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; + 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) @@ -79,23 +79,18 @@ 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_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("%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 @@ -110,7 +105,8 @@ InterfileHeaderSiemens::InterfileHeaderSiemens() add_key("image duration (sec)", &image_durations[0]); } -bool InterfileHeaderSiemens::post_processing() +bool +InterfileHeaderSiemens::post_processing() { if (InterfileHeader::post_processing() == true) @@ -122,19 +118,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(); @@ -160,7 +156,6 @@ void InterfileHeaderSiemens::set_type_of_data() } } - void InterfileHeaderSiemens::ignore_Siemens_date_and_time_keys(const std::string& keyword) { @@ -190,11 +185,10 @@ InterfileHeaderSiemens::ignore_Siemens_date_and_time_keys(const std::string& key ignore_key(keyword + " time (hh:mm:ss GMT-11:00)"); } - /**********************************************************************/ InterfileRawDataHeaderSiemens::InterfileRawDataHeaderSiemens() - : InterfileHeaderSiemens() + : InterfileHeaderSiemens() { // first set to some crazy values num_segments = 0; @@ -206,19 +200,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); add_key("%tof mashing factor", &tof_mash_factor); // TODO should add data format:=CoincidenceList|sinogram and then check its value @@ -265,18 +257,19 @@ 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" && PET_data_type != "normalization") - { error("Interfile error: expecting 'emission' or 'transmission' or 'normalization' 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" && PET_data_type != "normalization") + { + error("Interfile error: expecting 'emission' or 'transmission' or 'normalization' for 'PET data type'"); + } // handle scanner @@ -288,8 +281,7 @@ bool InterfileRawDataHeaderSiemens::post_processing() // 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()); + error("Interfile warning: 'number of rings' (%d) is expected to be %d.\n", num_rings, scanner_sptr->get_num_rings()); } if (tof_mash_factor < 0) // check if it was not set yet @@ -305,11 +297,8 @@ bool InterfileRawDataHeaderSiemens::post_processing() warning("TOF mashing factor was not set. Using " + std::to_string(tof_mash_factor)); } - data_info_ptr = - ProjDataInfo::construct_proj_data_info(scanner_sptr, - axial_compression, maximum_ring_difference, - num_views, num_bins, - is_arccorrected, tof_mash_factor); + data_info_ptr = ProjDataInfo::construct_proj_data_info( + scanner_sptr, axial_compression, maximum_ring_difference, num_views, num_bins, is_arccorrected, tof_mash_factor); // handle segments { @@ -318,7 +307,7 @@ bool InterfileRawDataHeaderSiemens::post_processing() error("Interfile warning: 'number of segments' and length of 'segment table' are not consistent"); } segment_sequence = ecat::find_segment_sequence(*data_info_ptr); - //TODO check if order here and segment_table are consistent + // TODO check if order here and segment_table are consistent } // Set the bed position @@ -328,16 +317,16 @@ bool InterfileRawDataHeaderSiemens::post_processing() return false; } - - /**********************************************************************/ InterfilePDFSHeaderSiemens::InterfilePDFSHeaderSiemens() - : InterfileRawDataHeaderSiemens() + : 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); + 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 @@ -356,68 +345,66 @@ InterfilePDFSHeaderSiemens::InterfilePDFSHeaderSiemens() ignore_key("total number of data sets"); add_key("%number of buckets", - KeyArgument::INT, (KeywordProcessor)&InterfilePDFSHeaderSiemens::read_bucket_singles_rates, &num_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 && num_dimensions != 4) { - warning("Interfile error: expecting 3D or 4D data "); - stop_parsing(); - return true; + warning("Interfile error: expecting 3D or 4D data "); + stop_parsing(); + return true; } - if ((matrix_size[0].size() != 1) || - (matrix_size[1].size() != 1) || - (matrix_size[2].size() != 1) || - (matrix_size[num_dimensions-1].size() != 1)) + if ((matrix_size[0].size() != 1) || (matrix_size[1].size() != 1) || (matrix_size[2].size() != 1) + || (matrix_size[num_dimensions - 1].size() != 1)) { - error("Siemens Interfile error: strange values for the matrix_size keyword(s)"); + error("Siemens Interfile error: strange values for the matrix_size keyword(s)"); } - if (matrix_labels[0] != "bin" && matrix_labels[0] != "x" && matrix_labels[0] != "sinogram projections") // x is used for arccorrected data (ACF) + if (matrix_labels[0] != "bin" && matrix_labels[0] != "x" + && matrix_labels[0] != "sinogram projections") // x is used for arccorrected data (ACF) { - // use error message with index [1] as that is what the user sees. - error("Siemens Interfile error: expecting 'matrix axis label[1] := bin' or 'x' or 'sinogram projections'"); + // use error message with index [1] as that is what the user sees. + error("Siemens Interfile error: expecting 'matrix axis label[1] := bin' or 'x' or 'sinogram projections'"); } num_bins = matrix_size[0][0]; - if (num_dimensions == 3 && - ((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 - ) - ) + if (num_dimensions == 3 + && ((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 + )) { - if (num_tof_bins>1) + if (num_tof_bins > 1) storage_order = ProjDataFromStream::Timing_Segment_AxialPos_View_TangPos; else storage_order = ProjDataFromStream::Segment_AxialPos_View_TangPos; num_views = matrix_size[1][0]; } - else if (num_dimensions == 4 && - matrix_labels[1] == "sinogram views" && matrix_labels[2] == "number of sinograms" && - matrix_labels[3] == "TOF bin") // used for TOF + else if (num_dimensions == 4 && matrix_labels[1] == "sinogram views" && matrix_labels[2] == "number of sinograms" + && matrix_labels[3] == "TOF bin") // used for TOF { storage_order = ProjDataFromStream::Timing_Segment_AxialPos_View_TangPos; num_views = matrix_size[1][0]; @@ -425,42 +412,38 @@ int InterfilePDFSHeaderSiemens::find_storage_order() } else { - error("Interfile error: matrix labels not in expected (or supported) format"); + 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) { - warning("Parsing Interfile header for projection data: \n" - "\t'applied corrections' keyword not found or empty. Assuming non-arc-corrected data"); - is_arccorrected = false; + warning("Parsing Interfile header for projection data: \n" + "\t'applied corrections' keyword not found or empty. Assuming non-arc-corrected data"); + is_arccorrected = false; } 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()); - } + 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()); + } } if (find_storage_order()) @@ -486,7 +469,7 @@ bool InterfilePDFSHeaderSiemens::post_processing() /**********************************************************************/ InterfileListmodeHeaderSiemens::InterfileListmodeHeaderSiemens() - : InterfileRawDataHeaderSiemens() + : InterfileRawDataHeaderSiemens() { // need to set this to construct the correct proj_data_info is_arccorrected = false; @@ -497,37 +480,37 @@ InterfileListmodeHeaderSiemens::InterfileListmodeHeaderSiemens() { 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 -*/ + /* + 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); @@ -554,29 +537,42 @@ InterfileListmodeHeaderSiemens::InterfileListmodeHeaderSiemens() ignore_key("%singles scale factor"); ignore_key("%total number of singles blocks"); ignore_key("%time sync"); - } +} -int InterfileListmodeHeaderSiemens::find_storage_order() +int +InterfileListmodeHeaderSiemens::find_storage_order() { - if (num_tof_bins>1) + if (num_tof_bins > 1) storage_order = ProjDataFromStream::Timing_Segment_AxialPos_View_TangPos; else 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() +bool +InterfileListmodeHeaderSiemens::post_processing() { if (find_storage_order()) { @@ -591,13 +587,13 @@ bool InterfileListmodeHeaderSiemens::post_processing() } InterfileNormHeaderSiemens::InterfileNormHeaderSiemens() - : InterfileRawDataHeaderSiemens() + : InterfileRawDataHeaderSiemens() { // some defaults calib_factor = 1.F; cross_calib_factor = 1.F; - num_buckets = 0; // should be set normally - num_components = 0; // should be set to 8 normally + num_buckets = 0; // should be set normally + num_components = 0; // should be set to 8 normally axial_compression = 11; // should be set normally but seems to be this always is_arccorrected = false; // norm data is never arc-corrected @@ -612,7 +608,9 @@ InterfileNormHeaderSiemens::InterfileNormHeaderSiemens() // keywords for the components add_key("%number of normalization components", - KeyArgument::INT, (KeywordProcessor)&InterfileNormHeaderSiemens::read_num_components, &num_components); + KeyArgument::INT, + (KeywordProcessor)&InterfileNormHeaderSiemens::read_num_components, + &num_components); add_vectorised_key("%matrix size", &matrix_size); add_vectorised_key("%matrix axis label", &matrix_labels); ignore_key("%matrix axis unit"); @@ -627,8 +625,8 @@ InterfileNormHeaderSiemens::InterfileNormHeaderSiemens() add_key("%number of buckets", &num_buckets); ignore_key("%global scanner calibration factor"); - add_key("%scanner quantification factor (Bq*s/ECAT counts)",& calib_factor); - add_key("%cross calibration factor",& cross_calib_factor); + add_key("%scanner quantification factor (Bq*s/ECAT counts)", &calib_factor); + add_key("%cross calibration factor", &cross_calib_factor); ignore_Siemens_date_and_time_keys("%calibration"); // isotope things are vectorised in norm files and not in other raw data, so we could @@ -651,7 +649,8 @@ InterfileNormHeaderSiemens::InterfileNormHeaderSiemens() ignore_key("%data set"); } -void InterfileNormHeaderSiemens::read_num_components() +void +InterfileNormHeaderSiemens::read_num_components() { set_variable(); @@ -665,12 +664,12 @@ void InterfileNormHeaderSiemens::read_num_components() number_of_dimensions.resize(num_components); } -bool InterfileNormHeaderSiemens::post_processing() +bool +InterfileNormHeaderSiemens::post_processing() { if (matrix_size.size() < 4) - error("Error parsing ECAT8 norm file header: '%number of normalization components='" + - std::to_string(matrix_size.size())+ - "' but should be at least 4"); + error("Error parsing ECAT8 norm file header: '%number of normalization components='" + std::to_string(matrix_size.size()) + + "' but should be at least 4"); // %normalization component [1]:=geometric effects if (matrix_size[0].size() != 2) error("Error parsing ECAT8 norm file header: '%matrix size[1]' should have length 2"); @@ -681,17 +680,17 @@ bool InterfileNormHeaderSiemens::post_processing() // TODO should do far more checks... // remove trailing \r (or other white space) occuring in mMR norm files (they sometimes have \r\r at end of line) - std::string s=exam_info_sptr->originating_system; - s.erase( std::remove_if( s.begin(), s.end(), isspace ), s.end() ); - exam_info_sptr->originating_system=s; - s=data_file_name; - s.erase( std::remove_if( s.begin(), s.end(), isspace ), s.end() ); - data_file_name=s; + std::string s = exam_info_sptr->originating_system; + s.erase(std::remove_if(s.begin(), s.end(), isspace), s.end()); + exam_info_sptr->originating_system = s; + s = data_file_name; + s.erase(std::remove_if(s.begin(), s.end(), isspace), s.end()); + data_file_name = s; // norm headers don't seem to have "number of views". We need to get it from elsewhere... // The crystal efficiencies have as first dimension the number of crystals, so let's use that. const int num_detectors_per_ring = matrix_size[2][0]; - this->num_views = num_detectors_per_ring/2; + this->num_views = num_detectors_per_ring / 2; // find num_bins from geometric effects this->num_bins = matrix_size[0][0]; diff --git a/src/IO/InterfileOutputFileFormat.cxx b/src/IO/InterfileOutputFileFormat.cxx index be194570b..6bd0620e2 100644 --- a/src/IO/InterfileOutputFileFormat.cxx +++ b/src/IO/InterfileOutputFileFormat.cxx @@ -23,38 +23,31 @@ 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; @@ -62,32 +55,23 @@ post_processing() } // 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); + + 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; }; END_NAMESPACE_STIR - - diff --git a/src/IO/InterfilePDFSHeaderSPECT.cxx b/src/IO/InterfilePDFSHeaderSPECT.cxx index 17109f401..8ea555306 100644 --- a/src/IO/InterfilePDFSHeaderSPECT.cxx +++ b/src/IO/InterfilePDFSHeaderSPECT.cxx @@ -7,7 +7,7 @@ See STIR/LICENSE.txt for details */ -/*! +/*! \file \ingroup InterfileIO \brief This file implements the classes stir::InterfilePDFSHeaderSPECT @@ -30,37 +30,32 @@ using std::endl; START_NAMESPACE_STIR -//KT 26/10/98 -// KT 13/11/98 moved stream arg from constructor to parse() +// KT 26/10/98 +// KT 13/11/98 moved stream arg from constructor to parse() InterfilePDFSHeaderSPECT::InterfilePDFSHeaderSPECT() -: InterfileHeader() + : 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) @@ -70,17 +65,17 @@ 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") - { + 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; + warning("Interfile error: expecting 'matrix axis label[1] := bin coordinate'"); + return true; } - if (matrix_labels[1].size()>0 && matrix_labels[1] != "axial coordinate" ) - { + 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; + warning("Interfile error: expecting 'matrix axis label[2] := axial coordinate'"); + return true; } if (extent_of_rotation == double_value_not_set) @@ -90,59 +85,60 @@ bool InterfilePDFSHeaderSPECT::post_processing() } 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) - // will be in mm (SPECT Interfile uses mm) - VectorWithOffset radii(0, num_views-1); - orbit=standardise_keyword(orbit); + // 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); + 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)) + + if (radii_of_rotation.size() != static_cast(num_views)) { warning("Interfile error: number of projections must be consistent with radius vector length"); - return true; + return true; } - for ( int i = 0 ; i < num_views ; i++ ) radii[ i ] = static_cast(radii_of_rotation[i]); + 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; + 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; @@ -158,32 +154,31 @@ bool InterfilePDFSHeaderSPECT::post_processing() 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_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)); + 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,24 +189,23 @@ 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") + 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") + else if (direction_of_rotation == "ccw") { my_data_info_ptr->set_azimuthal_angle_sampling(angle_sampling); } @@ -222,10 +216,9 @@ bool InterfilePDFSHeaderSPECT::post_processing() } 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 c7f213324..f6843f778 100644 --- a/src/IO/InterfileParametricDiscretisedDensityOutputFileFormat.cxx +++ b/src/IO/InterfileParametricDiscretisedDensityOutputFileFormat.cxx @@ -35,15 +35,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); @@ -52,64 +49,54 @@ 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) +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; - } + { + 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 = 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); + 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"); + replace_extension(filename, ".hv"); return success; } @@ -118,5 +105,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 cbd80d6e9..4542fcabd 100644 --- a/src/IO/MultiDynamicDiscretisedDensityOutputFileFormat.cxx +++ b/src/IO/MultiDynamicDiscretisedDensityOutputFileFormat.cxx @@ -21,7 +21,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" @@ -31,92 +31,84 @@ 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) +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"); + 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 +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++) { - 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"); + 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; + // Write some multi header info + filename = filename + ".txt"; + MultipleDataSetHeader::write_header(filename, individual_filenames); + return Succeeded::yes; +} +// class MultiDynamicDiscretisedDensityOutputFileFormat; END_NAMESPACE_STIR diff --git a/src/IO/MultiParametricDiscretisedDensityOutputFileFormat.cxx b/src/IO/MultiParametricDiscretisedDensityOutputFileFormat.cxx index b8bbf0038..126c5bd5f 100644 --- a/src/IO/MultiParametricDiscretisedDensityOutputFileFormat.cxx +++ b/src/IO/MultiParametricDiscretisedDensityOutputFileFormat.cxx @@ -23,7 +23,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" @@ -38,13 +38,11 @@ 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); @@ -52,9 +50,8 @@ MultiParametricDiscretisedDensityOutputFileFormat(const NumericType& type, } TEMPLATE -void -ParamDiscDensityOutputFileFormat:: -set_defaults() +void +ParamDiscDensityOutputFileFormat::set_defaults() { base_type::set_defaults(); this->set_type_of_numbers(NumericType::FLOAT); @@ -63,20 +60,18 @@ 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; @@ -84,48 +79,48 @@ post_processing() } TEMPLATE -ByteOrder -ParamDiscDensityOutputFileFormat:: -set_byte_order(const ByteOrder& new_byte_order, const bool warn) +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"); + 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 +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++) { - 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"); + 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"); } - // 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; + + // Write some multi header info + filename = filename + ".txt"; + MultipleDataSetHeader::write_header(filename, individual_filenames); + return Succeeded::yes; } #undef ParamDiscDensity @@ -133,5 +128,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 7cc4d765c..9b6d80212 100644 --- a/src/IO/OutputFileFormat.cxx +++ b/src/IO/OutputFileFormat.cxx @@ -10,27 +10,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 b49af261c..e877b0d1c 100644 --- a/src/IO/OutputFileFormat_default.cxx +++ b/src/IO/OutputFileFormat_default.cxx @@ -13,30 +13,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 <> @@ -44,31 +43,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/ecat6_utils.cxx b/src/IO/ecat6_utils.cxx index c1cc56248..2798ca0ce 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. */ @@ -35,14 +34,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 @@ -51,15 +50,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" @@ -77,510 +76,554 @@ 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 +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); + 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); #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; + 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; + // 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; + 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 +get_scandata(FILE* fptr, char* scan, ScanInfoRec* scanParams) { - int status; + 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 +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); + 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); #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; + 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; + // 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; + 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; + 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; + // 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; + 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) +cti_create(const char* const fname, const Main_header* mhead) { - return mat_create(const_cast(fname), const_cast(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) +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; + 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) +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; + 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) +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; + 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) +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; + 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) +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; + 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) +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; + 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) +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; + 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) +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; + 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) +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); - } + 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) + 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 + { + 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); + 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 + // 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); + 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) + 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) + + 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) { + 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("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); @@ -214,64 +184,53 @@ 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) + 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]); + 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)) + 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 (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]); // Set the time frame of the individual frame - _exam_info.time_frame_definitions = - TimeFrameDefinitions(hdr.get_exam_info().time_frame_definitions,frame_num); + _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); - + 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)); + ParametricVoxelsOnCartesianGrid* parametric_dens_ptr + = 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); @@ -279,61 +238,62 @@ 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++) { + 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]); + 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) + 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]); + 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) + 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 = - image_sptr->begin_all(); - 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(); - - while (single_density_iter!=end_single_density_iter) + ParametricVoxelsOnCartesianGrid::SingleDiscretisedDensityType::const_full_iterator single_density_iter + = image_sptr->begin_all(); + 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(); + + while (single_density_iter != end_single_density_iter) { (*parametric_density_iter)[kin_param] = *single_density_iter; - ++single_density_iter; ++parametric_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()); } 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) @@ -382,27 +342,20 @@ 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) +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); + 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); + 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); + return string(data_file_name, find_pos_of_filename(data_file_name), string::npos); } else { @@ -413,48 +366,64 @@ interfile_get_data_file_name_in_header(const string& header_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; + 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::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; + rotation = "other"; + break; + default: + rotation = "unknown"; + break; } - if (orientation!="unknown") + 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) + 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) + for (unsigned int frame_num = 1; frame_num <= frame_defs.get_num_time_frames(); ++frame_num) { - if (frame_defs.get_duration(frame_num)>0) + 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'; + 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'; } } } @@ -466,31 +435,32 @@ static void write_interfile_time_frame_definitions(std::ostream& output_header, } // 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) +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) + 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'; + 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) +static void +write_interfile_image_data_descriptions(std::ostream& output_header, const std::vector& data_type_descriptions) { - if (data_type_descriptions.size() == 0) return; + 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 (unsigned int i=0; iimaging_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 write_interfile_radionuclide_info(std::ostream& output_header, const ExamInfo& exam_info) +static void +write_interfile_radionuclide_info(std::ostream& output_header, const ExamInfo& exam_info) { const auto radionuclide = exam_info.get_radionuclide(); - //const bool is_spect = exam_info.imaging_modality.get_modality() == ImagingModality::NM; + // const bool is_spect = exam_info.imaging_modality.get_modality() == ImagingModality::NM; // TODO we only support one output_header << "number of radionuclides := 1\n"; - if (!radionuclide.get_name().empty() && radionuclide.get_name()!="Unknown") - output_header << "radionuclide name[1] := " << radionuclide.get_name() << '\n'; + if (!radionuclide.get_name().empty() && radionuclide.get_name() != "Unknown") + output_header << "radionuclide name[1] := " << radionuclide.get_name() << '\n'; if (radionuclide.get_half_life(false) > 0) { - output_header << "radionuclide halflife (sec)[1] := " << radionuclide.get_half_life() << '\n'; + output_header << "radionuclide halflife (sec)[1] := " << radionuclide.get_half_life() << '\n'; } if (radionuclide.get_branching_ratio(false) > 0) { - output_header << "radionuclide branching factor[1] := " - << radionuclide.get_branching_ratio() << '\n'; + output_header << "radionuclide branching factor[1] := " << radionuclide.get_branching_ratio() << '\n'; } } -static void interfile_create_filenames(const std::string& filename, std::string& data_name, std::string& header_name) +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") + 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 +Succeeded write_basic_interfile_image_header(const string& header_file_name, - const string& image_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) + 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)) - { - warning("write_basic_interfile: can handle only regular index ranges\n. No output\n"); - return Succeeded::no; - } + { + warning("write_basic_interfile: can handle only regular index ranges\n. No output\n"); + return Succeeded::no; + } CartesianCoordinate3D dimensions = max_indices - min_indices + 1; 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()); + 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 @@ -597,23 +565,17 @@ 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) + 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); + 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; write_interfile_radionuclide_info(output_header, exam_info); @@ -631,88 +593,76 @@ write_basic_interfile_image_header(const string& header_file_name, } output_header << "process status := Reconstructed\n"; - output_header << "!number format := "; - if (output_type.integer_type() ) - output_header << (output_type.signed_type() - ? "signed integer\n" : "unsigned integer\n"); + output_header << "!number format := "; + if (output_type.integer_type()) + output_header << (output_type.signed_type() ? "signed integer\n" : "unsigned integer\n"); else output_header << "float\n"; - output_header << "!number of bytes per pixel := " - << output_type.size_in_bytes() << endl; - + output_header << "!number of bytes per pixel := " << output_type.size_in_bytes() << endl; + output_header << "number of dimensions := 3\n"; output_header << "matrix axis label [1] := x\n"; - output_header << "!matrix size [1] := " - << dimensions.x() << endl; - output_header << "scaling factor (mm/pixel) [1] := " - << voxel_size.x() << endl; + output_header << "!matrix size [1] := " << dimensions.x() << endl; + output_header << "scaling factor (mm/pixel) [1] := " << voxel_size.x() << endl; output_header << "matrix axis label [2] := y\n"; - output_header << "!matrix size [2] := " - << dimensions.y() << endl; - output_header << "scaling factor (mm/pixel) [2] := " - << voxel_size.y() << endl; + output_header << "!matrix size [2] := " << dimensions.y() << endl; + output_header << "scaling factor (mm/pixel) [2] := " << voxel_size.y() << endl; output_header << "matrix axis label [3] := z\n"; - output_header << "!matrix size [3] := " - << dimensions.z()<< endl; - output_header << "scaling factor (mm/pixel) [3] := " - << voxel_size.z() << endl; + output_header << "!matrix size [3] := " << dimensions.z() << endl; + output_header << "scaling factor (mm/pixel) [3] := " << voxel_size.z() << endl; if (origin.z() != InterfileHeader::double_value_not_set) { - const CartesianCoordinate3D first_pixel_offsets = - voxel_size * BasicCoordinate<3,float>(min_indices) + origin; - output_header << "first pixel offset (mm) [1] := " - << first_pixel_offsets.x() << '\n'; - output_header << "first pixel offset (mm) [2] := " - << first_pixel_offsets.y() << '\n'; - output_header << "first pixel offset (mm) [3] := " - << first_pixel_offsets.z() << '\n'; + const CartesianCoordinate3D first_pixel_offsets = voxel_size * BasicCoordinate<3, float>(min_indices) + origin; + output_header << "first pixel offset (mm) [1] := " << first_pixel_offsets.x() << '\n'; + output_header << "first pixel offset (mm) [2] := " << first_pixel_offsets.y() << '\n'; + output_header << "first pixel offset (mm) [3] := " << first_pixel_offsets.z() << '\n'; } - write_interfile_time_frame_definitions(output_header, exam_info); write_interfile_energy_windows(output_header, exam_info); write_interfile_image_data_descriptions(output_header, data_type_descriptions); - for (int i=1; i<=scaling_factors.get_length();i++) + for (int i = 1; i <= scaling_factors.get_length(); i++) { // only write scaling factors and offset if more than 1 frame or they are not default values - if (scaling_factors[i-1]!=1. || scaling_factors.get_length()>1) - output_header << "image scaling factor"<<"["< -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); } 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) +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 + 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); +} + +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, - ExamInfo(), - image, - voxel_size, - origin, + 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 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) +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) + 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<=static_cast(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 <= static_cast(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"); - - 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 + // 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 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) + 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<=static_cast(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 <= static_cast(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) +static ProjDataFromStream* +read_interfile_PDFS_SPECT(istream& input, const string& directory_for_data, const ios::openmode open_mode) { - - InterfilePDFSHeaderSPECT hdr; - if (!hdr.parse(input)) + + 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 segment_sequence(1); + segment_sequence[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."); + { + 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])); + 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)) @@ -1063,36 +969,34 @@ read_interfile_PDFS_Siemens(istream& input, 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; + 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."); auto pdfs_ptr = 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.); + 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.); if (hdr.timing_poss_sequence.size() > 1) pdfs_ptr->set_timing_poss_sequence_in_stream(hdr.timing_poss_sequence); return pdfs_ptr; } -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 { @@ -1101,21 +1005,20 @@ read_interfile_PDFS(istream& input, } input.clear(); // clear EOF or other flags before we proceed input.seekg(offset); - if (hdr.get_exam_info().imaging_modality.get_modality() == - ImagingModality::NM) + if (hdr.get_exam_info().imaging_modality.get_modality() == ImagingModality::NM) { // spect data - return read_interfile_PDFS_SPECT(input, directory_for_data, open_mode); + 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); + return read_interfile_PDFS_Siemens(input, directory_for_data, open_mode); } } - + // if we get here, it's PET - InterfilePDFSHeader hdr; + InterfilePDFSHeader hdr; if (!hdr.parse(input)) { warning("Interfile parsing of PET projection data failed"); @@ -1127,61 +1030,57 @@ read_interfile_PDFS(istream& input, 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; - } + assert(!is_null_ptr(hdr.data_info_sptr)); - auto pdfs_ptr = 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])); - - if (hdr.timing_poss_sequence.size() > 1) - pdfs_ptr->set_timing_poss_sequence_in_stream(hdr.timing_poss_sequence); - return pdfs_ptr; -} + 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; + } + + auto pdfs_ptr = 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])); + if (hdr.timing_poss_sequence.size() > 1) + pdfs_ptr->set_timing_poss_sequence_in_stream(hdr.timing_poss_sequence); + return pdfs_ptr; +} 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()); } - + 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; @@ -1189,22 +1088,20 @@ write_basic_interfile_PDFS_header(const string& header_file_name, 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()); + 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(); - const float angle_first_view = - pdfs.get_proj_data_info_sptr()->get_scanner_ptr()->get_intrinsic_azimuthal_tilt() * 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); + const float angle_first_view + = pdfs.get_proj_data_info_sptr()->get_scanner_ptr()->get_intrinsic_azimuthal_tilt() * 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"; @@ -1215,7 +1112,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"; @@ -1227,15 +1124,12 @@ 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; write_interfile_radionuclide_info(output_header, pdfs.get_exam_info()); @@ -1250,7 +1144,7 @@ write_basic_interfile_PDFS_header(const string& header_file_name, 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()))) + 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"; @@ -1270,21 +1164,18 @@ write_basic_interfile_PDFS_header(const string& header_file_name, 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 << "!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 << "!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 = - dynamic_pointer_cast(pdfs.get_proj_data_info_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())) + 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'; @@ -1295,18 +1186,14 @@ write_basic_interfile_PDFS_header(const string& header_file_name, 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'; + 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 := " - <get_num_tof_poss()>1; - output_header << "number of dimensions := " + std::to_string(is_TOF ? 5: 4) + "\n"; + const bool is_TOF = pdfs.get_proj_data_info_sptr()->get_num_tof_poss() > 1; + output_header << "number of dimensions := " + std::to_string(is_TOF ? 5 : 4) + "\n"; // TODO support more ? { @@ -1325,162 +1212,151 @@ write_basic_interfile_PDFS_header(const string& header_file_name, int order_of_z = 2; int order_of_bin = 1; int order_of_timing_poss = 0; - switch(pdfs.get_storage_order()) - /* + switch (pdfs.get_storage_order()) + /* + { + case ProjDataFromStream::ViewSegmentRingBin: + { + order_of_segment = 2; + order_of_view = 1; + order_of_z = 3; + break; + } + */ { - 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; - } - 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, " + 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_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_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 (is_TOF) - { - output_header << "TOF mashing factor := " << - pdfs.get_proj_data_info_sptr()->get_tof_mash_factor() << "\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()); + const shared_ptr 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)) { - // !author Parisa Khateri - const shared_ptr proj_data_info_sptr = - dynamic_pointer_cast(pdfs.get_proj_data_info_sptr()); - - if (proj_data_info_sptr!=NULL) + // cylindrical scanners + + output_header << "minimum ring difference per segment := "; { - // BlocksOncylindrical 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 << "," << proj_data_info_sptr->get_min_ring_difference(*seg); output_header << "}\n"; - } + } - output_header << "maximum ring difference per segment := "; - { + output_header << "maximum ring difference per segment := "; + { std::vector::const_iterator seg = segment_sequence.begin(); - output_header << "{ " <get_max_ring_difference(*seg); + output_header << "{ " << proj_data_info_sptr->get_max_ring_difference(*seg); for (seg++; seg != segment_sequence.end(); seg++) - output_header << "," <get_max_ring_difference(*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(); + 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 + { + // !author Parisa Khateri + const shared_ptr proj_data_info_sptr + = dynamic_pointer_cast(pdfs.get_proj_data_info_sptr()); + + if (proj_data_info_sptr != NULL) + { + // BlocksOncylindrical 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 := "; + { + 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 0 // KT commented out. currently no get_ring_radius() anymore if (fabs(proj_data_info_sptr->get_ring_radius()- scanner.get_effective_ring_radius()) > .1) @@ -1491,44 +1367,43 @@ write_basic_interfile_PDFS_header(const string& header_file_name, proj_data_info_sptr->get_ring_radius(), scanner.get_effective_ring_radius()); #endif - 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()); + 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; + output_header << "effective central bin size (cm) := " << proj_data_info_sptr->get_sampling_in_s(Bin(0, 0, 0, 0)) / 10. + << endl; - }// end of BlocksOnCylindrical scanner - else // generic scanner - { - const shared_ptr proj_data_info_sptr = - dynamic_pointer_cast(pdfs.get_proj_data_info_sptr()); + } // end of BlocksOnCylindrical scanner + else // generic scanner + { + const shared_ptr proj_data_info_sptr + = dynamic_pointer_cast(pdfs.get_proj_data_info_sptr()); - if (proj_data_info_sptr!=NULL) - { + if (proj_data_info_sptr != NULL) + { 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"; + 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 := "; { - 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"; + 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(); @@ -1536,7 +1411,7 @@ write_basic_interfile_PDFS_header(const string& header_file_name, 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; + << proj_data_info_sptr->get_sampling_in_s(Bin(0, 0, 0, 0)) / 10. << endl; } // end generic scanner else if (!dynamic_pointer_cast(pdfs.get_proj_data_info_sptr())) @@ -1545,38 +1420,34 @@ write_basic_interfile_PDFS_header(const string& header_file_name, } else { - error("write_basic_interfile_PDFS_header: Error casting the projdata to one of its geometries: Cylindrical/BlocksOnCylindrical/Generic"); + error("write_basic_interfile_PDFS_header: Error casting the projdata to one of its geometries: " + "Cylindrical/BlocksOnCylindrical/Generic"); } - } + } } + // 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,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,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>&, + 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, 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); END_NAMESPACE_STIR diff --git a/src/IO/stir_ecat6.cxx b/src/IO/stir_ecat6.cxx index be50f1aab..98893ebf7 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 @@ -19,7 +19,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/IO/interfile.h" #include "stir/ExamInfo.h" #include "stir/Sinogram.h" @@ -37,17 +36,17 @@ #include "stir/warning.h" #include "stir/error.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 @@ -62,9 +61,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 @@ -74,50 +71,48 @@ 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 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) +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"); + // check if it's ECAT 6 + FILE* cti_fptr = fopen(filename.c_str(), "rb"); - if(!cti_fptr) + 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); + 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; + // not enough bytes, so not ECAT6 + fclose(cti_fptr); + return false; } - + char buffer[512]; - ret=fread(buffer,1, 512, cti_fptr); + ret = fread(buffer, 1, 512, cti_fptr); if (ret != 512) { - // failure to read - fclose(cti_fptr); - return false; + // 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) + 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); @@ -127,152 +122,140 @@ static bool is_ECAT6_file(ECAT6_Main_header& mhead, const std::string& filename) { 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 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_intrinsic_azimuthal_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_intrinsic_azimuthal_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); - } - if(cti_read_image_subheader(cti_fptr, &mhead, entry.strtblk, &ihead)!=EXIT_SUCCESS) - { - error("\nUnable to look up image subheader\n"); + 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"); } } - + #ifndef STIR_ORIGINAL_ECAT6 const int x_size = ihead.x_dimension; const int y_size = ihead.y_dimension; @@ -281,71 +264,68 @@ 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]; + // 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) + 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); + 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; #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) + 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); + cti_data_to_float_Array((*image_ptr)[z + min_z], cti_data, scale_factor, ihead.data_type); #if 0 NumericType type; ByteOrder byte_order; @@ -358,133 +338,131 @@ ECAT6_to_VoxelsOnCartesianGrid(const int frame_num, const int gate_num, const in } #endif } // 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) - { - 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); - scanner_ptr.reset(new Scanner(Scanner::E953)); - } + 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); + 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); + 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); - // 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; - } + { + // 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); + // 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; + } int span = 1; 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; - max_ring_diff = 1; - } - else if (mhead.num_planes == num_rings) { - span=1; - max_ring_diff = 0; + warning("I'm guessing this is a stack of 2D sinograms\n"); + if (mhead.num_planes == 2 * num_rings - 1) + { + span = 3; + max_ring_diff = 1; + } + else if (mhead.num_planes == num_rings) + { + span = 1; + max_ring_diff = 0; + } + else + { + error("Impossible num_planes: %d\n", mhead.num_planes); + } } - else + else { - error("Impossible num_planes: %d\n", mhead.num_planes); + 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); } - } - 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); - } - + // 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: + long matnum = cti_numcod(frame_num, 1, gate_num, data_num, bed_num); + switch (mhead.file_type) { - 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; + 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); } - - default: - 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 @@ -492,585 +470,571 @@ 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)); - + 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()); - } - + { + 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:"; - + 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); - } - - // 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); - } - } - } // end of loop on segment number - } // end of 3D case + { + for (int w = 0; w <= max_ring_diff; w++) + { // loop on segment number + + // positive ring difference + 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; 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 - { - // 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); - } - - } // end of 2D case - - cout<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 << endl; } // end of write } - // takes a pre-allocated buffer (which will be modified) -void read_sinogram(Sinogram& 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: - { + switch (mhead.file_type) + { + case matScanFile: { Scan_subheader shead; - - if(get_scanheaders (fptr, matnum, &mhead, - &shead, &scanParams)!= EXIT_SUCCESS) + + 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) + 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: - { + case matAttenFile: { Attn_subheader shead; - - if(get_attnheaders (fptr, matnum, &mhead, - &shead, &scanParams)!= EXIT_SUCCESS) + + 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: - { + case matNormFile: { Norm_subheader shead; - - if(get_normheaders (fptr, matnum, &mhead, - &shead, &scanParams)!= EXIT_SUCCESS) + + 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); + } + if (get_scandata(fptr, buffer, &scanParams) != EXIT_SUCCESS) + error("Error reading matnum %d\n", matnum); cti_data_to_float_Array(sino_2D, buffer, scale_factor, scanParams.data_type); - } - -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) +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) { - - DiscretisedDensityOnCartesianGrid<3,float> const & image = - dynamic_cast const&>(density); + 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()) + { + 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()); + 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) + { + 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); + 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; - - 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()) - { - 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()); - 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) - { - 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); - 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; - // 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) + 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."); + "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; + 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(); + const float depth_of_interaction_factor + = 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(); #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) +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; - } + 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) + 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) - { - warning("This is not arc-corrected data. Filling in default_bin_size from scanner \n"); + 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; - } + 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) + 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; - } - } + // 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()) -{ - 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<get_scanner_sptr()->get_num_rings(), + num_rings); } - - for(int z=0; z 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); - delete[] cti_data; - return Succeeded::no; - } - } // end of loop on planes - } // end of loop on segments - 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)); + delete[] cti_data; + return Succeeded::no; + } + + 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 < num_view; y++) + { + for (int x = 0; x < num_bin; x++) + cti_data[y * num_bin + x] = short_sinogram[y + min_view][x + min_bin]; + } + + // write data + int 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 << endl; delete[] cti_data; - + return Succeeded::yes; } - -Succeeded -ProjData_to_ECAT6(ProjData const& proj_data, std::string const & cti_name, std::string const & orig_name, - const int frame_num, const int gate_num, const int data_num, const int bed_num, - const bool write_2D_sinograms) -{ +Succeeded +ProjData_to_ECAT6(ProjData const& proj_data, + std::string const& cti_name, + std::string const& orig_name, + const int frame_num, + const int gate_num, + const int data_num, + const int bed_num, + const bool write_2D_sinograms) +{ ECAT6_Main_header mhead; make_ECAT6_Main_header(mhead, orig_name, *proj_data.get_proj_data_info_sptr()); - - - FILE *fptr= cti_create(cti_name.c_str(), &mhead); - Succeeded result = - ProjData_to_ECAT6(fptr, proj_data, mhead, - frame_num, gate_num,data_num, bed_num, write_2D_sinograms); - - fclose(fptr); + + FILE* fptr = cti_create(cti_name.c_str(), &mhead); + Succeeded result = ProjData_to_ECAT6(fptr, proj_data, mhead, frame_num, gate_num, data_num, bed_num, write_2D_sinograms); + + fclose(fptr); return result; } -void cti_data_to_float_Array(Array<2,float>&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++); - 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++); - 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++); - 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++); - break; - } - } + 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++); + 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++); + 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++); + break; + } + } } END_NAMESPACE_ECAT6 diff --git a/src/IO/stir_ecat7.cxx b/src/IO/stir_ecat7.cxx index 74328e66b..1f0e1727d 100644 --- a/src/IO/stir_ecat7.cxx +++ b/src/IO/stir_ecat7.cxx @@ -11,20 +11,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" @@ -44,9 +43,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" @@ -83,53 +82,50 @@ START_NAMESPACE_ECAT7 /* ------------------------------------ * print_debug * ------------------------------------*/ -static int print_debug (char const * const fname, char const * const format, ...) +static int +print_debug(char const* const fname, char const* const format, ...) { - va_list ap; - char *fmt; - int len; - + 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); + 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); + va_start(ap, format); + vfprintf(stderr, fmt, ap); - free (fmt); - va_end (ap); - + free(fmt); + va_end(ap); } - return (0); - + return (0); } - -Succeeded read_ECAT7_main_header(Main_header& mhead, const string& filename) +Succeeded +read_ECAT7_main_header(Main_header& mhead, const string& filename) { - FILE * cti_fptr=fopen(filename.c_str(), "rb"); + 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) + if (fread(magic, 1, 7, cti_fptr) != 7 || strncmp(magic, "MATRIX7", 7) != 0) { - fclose(cti_fptr); - return Succeeded::no; + fclose(cti_fptr); + return Succeeded::no; } } - if(mat_read_main_header(cti_fptr, &mhead)!=0) + 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 @@ -139,324 +135,291 @@ Succeeded read_ECAT7_main_header(Main_header& mhead, const string& filename) { // 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; + 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; + 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); + return is_ECAT7_file(mhead, filename) + && (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()) { - case 1: - return ByteData; - case 2: - 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 - } + switch (type.size_in_bytes()) + { + case 1: + return ByteData; + case 2: + 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 + } + } } - } else - { - switch(type.size_in_bytes()) { - case 4: - return byte_order==ByteOrder::big_endian ? IeeeFloat : VAX_Rx4; - default: - { - // write error message below - } + switch (type.size_in_bytes()) + { + case 4: + 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) - { - case ::Sinogram: + switch (mptr->mhptr->file_type) { - // KT 14/05/2002 added error check. - if (mat_read_scan_subheader (mptr->fptr, mptr->mhptr, strtblk, &scansub)) + case ::Sinogram: + { - 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_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; } - 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; + 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; } - - 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; + + 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; + } + } + 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; - } - + + 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; + case ByteProjection: + case PetProjection: + case PolarMap: { + fprintf(stderr, "Not implemented for this file type\n"); + off = -1; + break; } - 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 Byte3dSinogram: - case Short3dSinogram: - case Float3dSinogram : - { - off = (strtblk+1) * MatBLKSIZE; - print_debug (prog, "off = %d\n", off); + case Byte3dSinogram: + case Short3dSinogram: + 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; - } - - 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++) + // KT 14/05/2002 added error check. + if (mat_read_Scan3D_subheader(mptr->fptr, mptr->mhptr, strtblk, &scan3dsub)) { - plane_size = scan3dsub.num_r_elements * - scan3dsub.num_z_elements[i] * - el_size[scan3dsub.data_type]; - off += plane_size * scan3dsub.num_angles; + if (ferror(mptr->fptr)) + perror("offset_in_ECAT_file: error in reading subheader"); + return -1; } - 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) { @@ -469,114 +432,108 @@ 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; + } + 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) +static void +fill_string(char* str, int len) { - for (int i=0; i -read_ECAT7_exam_info(MatrixFile *mptr) +read_ECAT7_exam_info(MatrixFile* mptr) { - - 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_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) + 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); + 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); @@ -585,27 +542,36 @@ 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) + switch (mptr->mhptr->patient_orientation) { case FeetFirstProne: - exam_info.patient_position = PatientPosition(PatientPosition::FFP); break; + exam_info.patient_position = PatientPosition(PatientPosition::FFP); + break; case HeadFirstProne: - exam_info.patient_position = PatientPosition(PatientPosition::HFP); break; + exam_info.patient_position = PatientPosition(PatientPosition::HFP); + break; case FeetFirstSupine: - exam_info.patient_position = PatientPosition(PatientPosition::FFS); break; + exam_info.patient_position = PatientPosition(PatientPosition::FFS); + break; case HeadFirstSupine: - exam_info.patient_position = PatientPosition(PatientPosition::HFS); break; + exam_info.patient_position = PatientPosition(PatientPosition::HFS); + break; case FeetFirstRight: - exam_info.patient_position = PatientPosition(PatientPosition::FFDR); break; + exam_info.patient_position = PatientPosition(PatientPosition::FFDR); + break; case HeadFirstRight: - exam_info.patient_position = PatientPosition(PatientPosition::HFDR); break; + exam_info.patient_position = PatientPosition(PatientPosition::HFDR); + break; case FeetFirstLeft: - exam_info.patient_position = PatientPosition(PatientPosition::FFDL); break; + exam_info.patient_position = PatientPosition(PatientPosition::FFDL); + break; case HeadFirstLeft: - exam_info.patient_position = PatientPosition(PatientPosition::HFDL); break; + exam_info.patient_position = PatientPosition(PatientPosition::HFDL); + break; case UnknownOrientation: default: - exam_info.patient_position = PatientPosition(PatientPosition::unknown_position); break; + exam_info.patient_position = PatientPosition(PatientPosition::unknown_position); + break; } shared_ptr exam_info_sptr(new ExamInfo(exam_info)); @@ -615,11 +581,10 @@ read_ECAT7_exam_info(MatrixFile *mptr) shared_ptr read_ECAT7_exam_info(const string& filename) { - MatrixFile * const mptr = - matrix_open( filename.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); + MatrixFile* const mptr = matrix_open(filename.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); if (!mptr) { - matrix_perror( filename.c_str()); + matrix_perror(filename.c_str()); error("Error reading ECAT7 file"); } shared_ptr exam_info_sptr(read_ECAT7_exam_info(mptr)); @@ -627,33 +592,30 @@ read_ECAT7_exam_info(const string& filename) 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; @@ -665,253 +627,247 @@ 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_intrinsic_azimuthal_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_intrinsic_azimuthal_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()) + switch (exam_info.patient_position.get_position()) { case PatientPosition::FFP: - mhead.patient_orientation = FeetFirstProne; break; + mhead.patient_orientation = FeetFirstProne; + break; case PatientPosition::HFP: - mhead.patient_orientation = HeadFirstProne; break; + mhead.patient_orientation = HeadFirstProne; + break; case PatientPosition::FFS: - mhead.patient_orientation = FeetFirstSupine; break; + mhead.patient_orientation = FeetFirstSupine; + break; case PatientPosition::HFS: - mhead.patient_orientation = HeadFirstSupine; break; + mhead.patient_orientation = HeadFirstSupine; + break; case PatientPosition::FFDR: - mhead.patient_orientation = FeetFirstRight; break; + mhead.patient_orientation = FeetFirstRight; + break; case PatientPosition::HFDR: - mhead.patient_orientation = HeadFirstRight; break; + mhead.patient_orientation = HeadFirstRight; + break; case PatientPosition::FFDL: - mhead.patient_orientation = FeetFirstLeft; break; + mhead.patient_orientation = FeetFirstLeft; + break; case PatientPosition::HFDL: - mhead.patient_orientation = HeadFirstLeft; break; + mhead.patient_orientation = HeadFirstLeft; + break; default: - mhead.patient_orientation = UnknownOrientation; break; + 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); - } + 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"); + "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) - { - 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) + ProjDataInfoCylindrical const* const proj_data_info_cyl_ptr = dynamic_cast(&proj_data_info); + if (proj_data_info_cyl_ptr != 0) { - 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); + 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; + 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 - { - 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?"); - } + { + 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?"); + } return static_cast(axial_compression); } - -NumericType +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 - ) + 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; + + 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); - + 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(); + 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) + 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); + "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.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()) + switch (proj_data_info.get_scanner_ptr()->get_type()) { case Scanner::E966: case Scanner::E925: case Scanner::RATPET: - mhead.septa_state= NoSeptaInstalled; + mhead.septa_state = NoSeptaInstalled; break; default: - mhead.septa_state= - proj_data_info.get_num_segments()==1 - ? SeptaExtended - : SeptaRetracted; + 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; - } - + { + 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; - } + { + 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; @@ -919,9 +875,9 @@ make_ECAT7_main_header(Main_header& mhead, // 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 @@ -930,9 +886,10 @@ 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; @@ -941,42 +898,46 @@ 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; @@ -988,29 +949,31 @@ 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) +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.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; @@ -1018,8 +981,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; @@ -1052,12 +1015,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 @@ -1069,26 +1032,21 @@ 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) +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.)); + 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 @@ -1099,142 +1057,114 @@ 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 i=proj_data_info.get_max_segment_num()+1; i<64; ++i) + 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) 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; - } - + { + 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 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; + 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 + { + 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(); + x_resolution = scanner.get_default_bin_size(); } else { - x_resolution = - proj_data_info.get_sampling_in_s(Bin(0,0,0,0)); + 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()); - } + { + 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(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"); - } + 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(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_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)) - { - shead.corrections_applied = static_cast(ArcPrc); - } - else if (dynamic_cast(&proj_data_info)) - { - shead.corrections_applied = 0; - } - 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); - } - + if (dynamic_cast(&proj_data_info)) + { + shead.corrections_applied = static_cast(ArcPrc); + } + else if (dynamic_cast(&proj_data_info)) + { + shead.corrections_applied = 0; + } + 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 @@ -1244,265 +1174,260 @@ 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)); + 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); - scanner_ptr.reset(new Scanner(Scanner::E962)); - } + { + 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); + 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) - { - 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()); - } + 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()); + } #endif shared_ptr exam_info_sptr(new ExamInfo(exam_info_whole_file)); - if (frame_duration>0) + 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.)); + 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) - { - case ElVwAxRd: - storage_order = ProjDataFromStream::Segment_AxialPos_View_TangPos; - break; - - case ElAxVwRd: - storage_order = ProjDataFromStream::Segment_View_AxialPos_TangPos; - break; - default: - warning("ECAT7 IO: Funny value for subheader.storage_order. Assuming ElVwAxRd"); - storage_order = ProjDataFromStream::Segment_AxialPos_View_TangPos; - } + { + case ElVwAxRd: + storage_order = ProjDataFromStream::Segment_AxialPos_View_TangPos; + break; + + case ElAxVwRd: + storage_order = ProjDataFromStream::Segment_View_AxialPos_TangPos; + break; + default: + warning("ECAT7 IO: Funny value for subheader.storage_order. Assuming ElVwAxRd"); + storage_order = ProjDataFromStream::Segment_AxialPos_View_TangPos; + } NumericType data_type; 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) - { - 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()); - scanner_ptr->set_default_bin_size(bin_size); - } + 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()); + 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; - } + { + 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()); - } + { + 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 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); + 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; + default: { + warning("make_pdfs_from_matrix: unsupported file_type %d\n", mptr->mhptr->file_type); + return NULL; } } } -static -Succeeded +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) + 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()); - return Succeeded::no; - } + MatrixFile* const mptr = matrix_open(ECAT7_filename.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); + if (!mptr) + { + 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); + "%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) + // 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); + "%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) - { + + 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); + "%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); { @@ -1510,61 +1435,59 @@ 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) - { + + 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); + "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) +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"; + 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; @@ -1575,32 +1498,44 @@ ECAT7_to_VoxelsOnCartesianGrid(const string& ECAT7_filename, 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) - { + 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); + "%s", + warning_prefix, + ECAT7_filename.c_str(), + warning_suffix); delete image_ptr; return 0; } @@ -1609,287 +1544,323 @@ ECAT7_to_VoxelsOnCartesianGrid(const string& ECAT7_filename, 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); + "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 in reading data with convertion to floats.\n", - "%s", - warning_prefix, ECAT7_filename.c_str(), warning_suffix); - delete image_ptr; - return 0; + 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); - if (!mptr) { - 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"; +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()); + return 0; + } + 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; + "%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) - { + 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); + "%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); + + 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 +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) + 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()); - 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"; + + MatrixFile* const mptr = matrix_open(ECAT7_filename.c_str(), MAT_READ_ONLY, MAT_UNKNOWN_FTYPE); + if (!mptr) + { + 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"; 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; - } - + { + warning("%s: '%s' seems to be an ECAT 6 file. " + "%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? - 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 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 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); + + break; + } + + default: + matrix_close(mptr); + warning("%s: File type not handled for file '%s'.\n" + "%s", + warning_prefix, + ECAT7_filename.c_str(), + warning_suffix); + return Succeeded::no; } - - 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); - break; - } - - default: - matrix_close(mptr); - warning("%s: File type not handled for file '%s'.\n" - "%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) + { + 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()) + { + 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()); + 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) + { + 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); + return Succeeded::no; + } - - 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()) - { - 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()); - 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) - { - 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); - 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(); + const float depth_of_interaction_factor + = 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); @@ -1925,333 +1896,310 @@ 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) { - copy(density[z].begin_all(), density[z].end_all(), current_buffer_pos); - current_buffer_pos += plane_size; + 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); + return Succeeded::no; } - } - 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); - return Succeeded::no; - } else - { - return Succeeded::yes; - } + { + 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) +update_ECAT7_subheader(MatrixFile* mptr, Scan_subheader& shead, const MatDir& matdir) { - const int ERROR=-1; + const int ERROR = -1; if (mptr->mhptr->file_type != ::Sinogram) 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) +update_ECAT7_subheader(MatrixFile* mptr, Norm_subheader& shead, const MatDir& matdir) { - const int ERROR=-1; + 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) +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)) + 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) +update_ECAT7_subheader(MatrixFile* mptr, Attn_subheader& shead, const MatDir& matdir) { - const int ERROR=-1; + 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) +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)) + 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) +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); + 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 { 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 - { - 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); - return Succeeded::no; - } - } - + 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 scale_factor is not set (=0) then calculate the scale factor to apply. - 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()) + if (mhead.num_planes != num_planes) // TODO check if this is the usual convention { - 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()); - } + 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); + return Succeeded::no; } } - + + // If scale_factor is not set (=0) then calculate the scale factor to apply. + 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()); + } + } + } + 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) - { - 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.storage_order = ElAxVwRd; - } + { + 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.storage_order = ElAxVwRd; + } 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.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); - } - } + { + 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.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); + } + } // 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) ; - } - + { + 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 (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; - } - + { + 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 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) - { - 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; - } + cout << "\nProcessing segment number:"; - if (fseek(mptr->fptr, offset_in_file, SEEK_SET)) + for (int segment_num = proj_data.get_min_segment_num(); segment_num <= proj_data.get_max_segment_num(); ++segment_num) { - 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); - 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 << " " << segment_num; + + // read the segment + 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); + + 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; + } + + 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); + 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; return Succeeded::yes; @@ -2259,64 +2207,62 @@ 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, +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); + 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); + 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); + 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); + 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); + 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, +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 4f21b7e68..0fa9df608 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 @@ -23,7 +23,7 @@ #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" #include "stir/warning.h" @@ -32,185 +32,184 @@ START_NAMESPACE_STIR START_NAMESPACE_ECAT - -void find_type_from_ECAT_data_type(NumericType& type, ByteOrder& byte_order, const short 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; - return; - case ECAT_I2_little_endian_data_type: - type = NumericType("signed integer", 2); - byte_order=ByteOrder::little_endian; - return; - case ECAT_I2_big_endian_data_type: - type = NumericType("signed integer", 2); - byte_order = ByteOrder::big_endian; - return; - case ECAT_R4_VAX_data_type: - type = NumericType("float", 4); - byte_order=ByteOrder::little_endian; - return; - case ECAT_R4_IEEE_big_endian_data_type: - type = NumericType("float", 4); - byte_order=ByteOrder::big_endian; - return; - case ECAT_I4_little_endian_data_type: - type = NumericType("signed integer", 4); - byte_order=ByteOrder::little_endian; - return; - case ECAT_I4_big_endian_data_type: - type = NumericType("signed integer", 4); - 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 - return; - } + switch (data_type) + { + case ECAT_Byte_data_type: + type = NumericType("signed integer", 1); + byte_order = ByteOrder::little_endian; + return; + case ECAT_I2_little_endian_data_type: + type = NumericType("signed integer", 2); + byte_order = ByteOrder::little_endian; + return; + case ECAT_I2_big_endian_data_type: + type = NumericType("signed integer", 2); + byte_order = ByteOrder::big_endian; + return; + case ECAT_R4_VAX_data_type: + type = NumericType("float", 4); + byte_order = ByteOrder::little_endian; + return; + case ECAT_R4_IEEE_big_endian_data_type: + type = NumericType("float", 4); + byte_order = ByteOrder::big_endian; + return; + case ECAT_I4_little_endian_data_type: + type = NumericType("signed integer", 4); + byte_order = ByteOrder::little_endian; + return; + case ECAT_I4_big_endian_data_type: + type = NumericType("signed integer", 4); + 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 + return; + } } -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()) { - 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; - 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 - } + 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; + 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 + } + } } - } 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 - } + 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 + } + } } - } 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) +short +find_ECAT_system_type(const Scanner& scanner) { - switch(scanner.get_type()) - { - case Scanner::E921: - return 921; - case Scanner::E925: - return 925; - - case Scanner::E931: - return 931; - - case Scanner::E951: - return 951; - - case Scanner::E953: - return 953; - - case Scanner::E961: - return 961; - - case Scanner::E962: - return 962; - - case Scanner::E966: - return 966; - - case Scanner::RPT: - return 128; - - case Scanner::RATPET: - return 42; - - default: - warning("\nfind_ecat_system_type: scanner \"%s\" currently unsupported. Returning 0.\n", - scanner.get_name().c_str()); - return 0; - } + switch (scanner.get_type()) + { + case Scanner::E921: + return 921; + case Scanner::E925: + return 925; + + case Scanner::E931: + return 931; + + case Scanner::E951: + return 951; + + case Scanner::E953: + return 953; + + case Scanner::E961: + return 961; + + case Scanner::E962: + return 962; + + case Scanner::E966: + return 966; + + case Scanner::RPT: + return 128; + + case Scanner::RATPET: + return 42; + + default: + 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) +Scanner* +find_scanner_from_ECAT_system_type(const short system_type) { - switch(system_type) - { - case 128 : - return new Scanner(Scanner::RPT); - case 921 : - return new Scanner(Scanner::E921); - case 925 : - return new Scanner(Scanner::E925); - case 931 : - case 12 : - return new Scanner(Scanner::E931); - case 951 : - return new Scanner(Scanner::E951); - case 953 : - return new Scanner(Scanner::E953); - case 961 : - return new Scanner(Scanner::E961); - case 962 : - return new Scanner(Scanner::E962); - case 966 : - return new Scanner(Scanner::E966); - case 42: - return new Scanner(Scanner::RATPET); - default : - return new Scanner(Scanner::Unknown_scanner); - } + switch (system_type) + { + case 128: + return new Scanner(Scanner::RPT); + case 921: + return new Scanner(Scanner::E921); + case 925: + return new Scanner(Scanner::E925); + case 931: + case 12: + return new Scanner(Scanner::E931); + case 951: + return new Scanner(Scanner::E951); + case 953: + return new Scanner(Scanner::E953); + case 961: + return new Scanner(Scanner::E961); + case 962: + return new Scanner(Scanner::E962); + case 966: + return new Scanner(Scanner::E966); + case 42: + return new Scanner(Scanner::RATPET); + default: + return new Scanner(Scanner::Unknown_scanner); + } } std::vector 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; } std::vector find_timing_poss_sequence(const ProjDataInfo& pdi) { - const int max_timing_pos_num = pdi.get_num_tof_poss()/2; - std::vector timing_pos_sequence(2*max_timing_pos_num+1); + const int max_timing_pos_num = pdi.get_num_tof_poss() / 2; + std::vector timing_pos_sequence(2 * max_timing_pos_num + 1); // Siemens always stores timing_poss as 0, -1, +1, ... timing_pos_sequence[0] = 0; - for (int timing_pos_num = 1; timing_pos_num<=max_timing_pos_num; ++timing_pos_num) - { - timing_pos_sequence[2*timing_pos_num-1] = timing_pos_num; - timing_pos_sequence[2*timing_pos_num] = -timing_pos_num; - } + for (int timing_pos_num = 1; timing_pos_num <= max_timing_pos_num; ++timing_pos_num) + { + timing_pos_sequence[2 * timing_pos_num - 1] = timing_pos_num; + timing_pos_sequence[2 * timing_pos_num] = -timing_pos_num; + } return timing_pos_sequence; } diff --git a/src/Shape_buildblock/Box3D.cxx b/src/Shape_buildblock/Box3D.cxx index d95346481..665c19fa6 100644 --- a/src/Shape_buildblock/Box3D.cxx +++ b/src/Shape_buildblock/Box3D.cxx @@ -24,10 +24,9 @@ START_NAMESPACE_STIR -const char * const -Box3D::registered_name = "Box3D"; +const char* const Box3D::registered_name = "Box3D"; -void +void Box3D::initialise_keymap() { parser.add_start_key("box parameters"); @@ -40,18 +39,17 @@ Box3D::initialise_keymap() void 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() +Box3D::post_processing() { - if (Shape3DWithOrientation::post_processing()==true) + if (Shape3DWithOrientation::post_processing() == true) return true; if (length_x <= 0) @@ -74,23 +72,22 @@ post_processing() Box3D::Box3D() { - set_defaults(); + 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, @@ -111,29 +108,25 @@ Box3D::Box3D(const float length_xv, #endif -bool Box3D::is_inside_shape(const CartesianCoordinate3D& coord) const +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) 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) < 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 +float +Box3D::get_geometric_volume() const { - return static_cast(length_x*length_y*length_z) / this->get_volume_of_unit_cell(); + return static_cast(length_x * length_y * length_z) / this->get_volume_of_unit_cell(); } - #if 0 // doesn't take scaling into account float @@ -145,34 +138,25 @@ get_geometric_area()const } #endif -Shape3D* -Box3D:: -clone() const +Shape3D* +Box3D::clone() const { - return static_cast(new Box3D(*this)); + return static_cast(new Box3D(*this)); } bool -Box3D:: -operator==(const Box3D& box) const +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); + 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::operator==(const Shape3D& shape) const { - Box3D const * box_ptr = - dynamic_cast(&shape); - return - box_ptr != 0 && (*this == *box_ptr); + 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 32668dd00..080f32fa7 100644 --- a/src/Shape_buildblock/DiscretisedShape3D.cxx +++ b/src/Shape_buildblock/DiscretisedShape3D.cxx @@ -26,35 +26,31 @@ 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); + 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()) { @@ -67,20 +63,15 @@ get_voxel_weight( 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 { if (this->_label_index >= 0) { @@ -99,31 +90,28 @@ construct_volume(VoxelsOnCartesianGrid &new_image, const CartesianCoordin 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; } int -DiscretisedShape3D::get_label_index() const +DiscretisedShape3D::get_label_index() const { return this->_label_index; } @@ -134,36 +122,32 @@ DiscretisedShape3D::set_label_index(int label) this->_label_index = label; } -DiscretisedShape3D:: -DiscretisedShape3D() +DiscretisedShape3D::DiscretisedShape3D() { set_defaults(); } -DiscretisedShape3D:: -DiscretisedShape3D(const VoxelsOnCartesianGrid& image_v) - : _label_index(-1), density_sptr(image_v.clone()) +DiscretisedShape3D::DiscretisedShape3D(const VoxelsOnCartesianGrid& image_v) + : _label_index(-1), + density_sptr(image_v.clone()) { this->set_origin(image_v.get_origin()); this->filename = "FROM MEMORY"; } - - -DiscretisedShape3D:: -DiscretisedShape3D(const shared_ptr >& density_sptr_v) - : _label_index(-1), density_sptr(density_sptr_v->clone()) +DiscretisedShape3D::DiscretisedShape3D(const shared_ptr>& density_sptr_v) + : _label_index(-1), + density_sptr(density_sptr_v->clone()) { - if(dynamic_cast *>(density_sptr.get()) == NULL) - { - error("DiscretisedShape3D can currently only handle images of type VoxelsOnCartesianGrid.\n"); - } + 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 +void DiscretisedShape3D::initialise_keymap() { Shape3D::initialise_keymap(); @@ -173,36 +157,32 @@ DiscretisedShape3D::initialise_keymap() parser.add_stop_key("END"); } - - void DiscretisedShape3D::set_defaults() -{ +{ Shape3D::set_defaults(); this->density_sptr.reset(); this->_label_index = -1; } bool -DiscretisedShape3D:: -post_processing() +DiscretisedShape3D::post_processing() { - if (Shape3D::post_processing()==true) + if (Shape3D::post_processing() == true) return true; - density_sptr = read_from_file >(filename); + 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()); - } + { + 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 674a65d13..7064044ce 100644 --- a/src/Shape_buildblock/Ellipsoid.cxx +++ b/src/Shape_buildblock/Ellipsoid.cxx @@ -25,11 +25,9 @@ START_NAMESPACE_STIR -const char * const -Ellipsoid::registered_name = "Ellipsoid"; +const char* const Ellipsoid::registered_name = "Ellipsoid"; - -void +void Ellipsoid::initialise_keymap() { parser.add_start_key("Ellipsoid Parameters"); @@ -40,21 +38,17 @@ Ellipsoid::initialise_keymap() Shape3DWithOrientation::initialise_keymap(); } - - void Ellipsoid::set_defaults() -{ +{ Shape3DWithOrientation::set_defaults(); radii.fill(0); } - bool -Ellipsoid:: -post_processing() +Ellipsoid::post_processing() { - if (Shape3DWithOrientation::post_processing()==true) + if (Shape3DWithOrientation::post_processing() == true) return true; if (radii.x() <= 0) @@ -80,11 +74,10 @@ Ellipsoid::Ellipsoid() set_defaults(); } -Ellipsoid::Ellipsoid(const CartesianCoordinate3D& radii_v, +Ellipsoid::Ellipsoid(const CartesianCoordinate3D& radii_v, const CartesianCoordinate3D& centre_v, - const Array<2,float>& direction_vectors) - : - radii(radii_v) + const Array<2, float>& direction_vectors) + : radii(radii_v) { assert(radii.x() > 0); assert(radii.y() > 0); @@ -92,22 +85,22 @@ Ellipsoid::Ellipsoid(const CartesianCoordinate3D& radii_v, 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) +Ellipsoid::set_radii(const CartesianCoordinate3D& new_radii) { - radii = 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 @@ -120,47 +113,39 @@ 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 +Shape3D* +Ellipsoid::clone() const { - return static_cast(new Ellipsoid(*this)); + return static_cast(new Ellipsoid(*this)); } bool -Ellipsoid:: -operator==(const Ellipsoid& cylinder) const +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); -; + 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::operator==(const Shape3D& shape) const { - Ellipsoid const * cylinder_ptr = - dynamic_cast(&shape); - return - cylinder_ptr != 0 && (*this == *cylinder_ptr); + 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 b9fd25603..c0a6d4b2d 100644 --- a/src/Shape_buildblock/EllipsoidalCylinder.cxx +++ b/src/Shape_buildblock/EllipsoidalCylinder.cxx @@ -16,8 +16,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.)_ */ @@ -31,10 +31,9 @@ START_NAMESPACE_STIR -const char * const -EllipsoidalCylinder::registered_name = "Ellipsoidal Cylinder"; +const char* const EllipsoidalCylinder::registered_name = "Ellipsoidal Cylinder"; -void +void EllipsoidalCylinder::initialise_keymap() { parser.add_start_key("Ellipsoidal Cylinder Parameters"); @@ -49,20 +48,19 @@ EllipsoidalCylinder::initialise_keymap() void 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() +EllipsoidalCylinder::post_processing() { - if (Shape3DWithOrientation::post_processing()==true) + if (Shape3DWithOrientation::post_processing() == true) return true; if (radius_x <= 0) @@ -80,12 +78,12 @@ post_processing() warning("length-z should be positive, but is %g\n", length); return true; } - if ((theta_1 < 0)||(theta_1>=360)) + 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)) + 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; @@ -93,174 +91,157 @@ post_processing() return false; } - - EllipsoidalCylinder::EllipsoidalCylinder() { - set_defaults(); + 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(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) +EllipsoidalCylinder::set_length(const float new_length) { - assert(new_length>0); + assert(new_length > 0); length = new_length; } void -EllipsoidalCylinder:: -set_radius_x(const float new_radius_x) +EllipsoidalCylinder::set_radius_x(const float new_radius_x) { - assert(new_radius_x>0); + assert(new_radius_x > 0); radius_x = new_radius_x; } void -EllipsoidalCylinder:: -set_radius_y(const float new_radius_y) +EllipsoidalCylinder::set_radius_y(const float new_radius_y) { - assert(new_radius_y>0); + assert(new_radius_y > 0); radius_y = new_radius_y; } +bool +EllipsoidalCylinder::is_inside_shape(const CartesianCoordinate3D& coord) const +{ + const CartesianCoordinate3D r = this->transform_to_shape_coords(coord); -bool EllipsoidalCylinder::is_inside_shape(const CartesianCoordinate3D& coord) const + const float distance_along_axis = r.z(); -{ - 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 - return false; - } - else return false; + 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; } -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 @@ -334,38 +315,28 @@ get_geometric_area()const } #endif -Shape3D* -EllipsoidalCylinder:: -clone() const +Shape3D* +EllipsoidalCylinder::clone() const { - return static_cast(new EllipsoidalCylinder(*this)); + return static_cast(new EllipsoidalCylinder(*this)); } bool -EllipsoidalCylinder:: -operator==(const EllipsoidalCylinder& cylinder) const +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); - -; + 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::operator==(const Shape3D& shape) const { - EllipsoidalCylinder const * cylinder_ptr = - dynamic_cast(&shape); - return - cylinder_ptr != 0 && (*this == *cylinder_ptr); + EllipsoidalCylinder const* cylinder_ptr = dynamic_cast(&shape); + return cylinder_ptr != 0 && (*this == *cylinder_ptr); } END_NAMESPACE_STIR diff --git a/src/Shape_buildblock/GenerateImage.cxx b/src/Shape_buildblock/GenerateImage.cxx index a1272f17d..c4b0719a7 100644 --- a/src/Shape_buildblock/GenerateImage.cxx +++ b/src/Shape_buildblock/GenerateImage.cxx @@ -20,7 +20,6 @@ \author Robert Twyman */ - #include "stir/Shape/GenerateImage.h" #include "stir/Shape/Shape3D.h" #include "stir/PatientPosition.h" @@ -36,87 +35,81 @@ #include "stir/error.h" #include - START_NAMESPACE_STIR -void GenerateImage:: -increment_current_shape_num() +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(); - } + 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() +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() +GenerateImage::initialise_keymap() { add_start_key("generate_image Parameters"); // copy of InterfileHeader (TODO) add_key("imaging modality", - KeyArgument::ASCII, (KeywordProcessor)&GenerateImage::set_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 + 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("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()); @@ -127,85 +120,81 @@ 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(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; - } + { + 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; } @@ -213,16 +202,15 @@ post_processing() /*! \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) - error("Failed to parse par_filename"); - } + if (par_filename != 0) + { + if (parse(par_filename) == false) + error("Failed to parse par_filename"); + } else ask_parameters(); @@ -235,13 +223,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( @@ -254,55 +239,50 @@ 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); - } + 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)); + { + 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)); this->out_density_ptr.reset(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) - { - info("Processing next shape...", 2); - current_image.fill(0); - (**iter).construct_volume(current_image, num_samples); - current_image *= *value_iter; - *out_density_ptr += current_image; - } + std::vector::const_iterator value_iter = values.begin(); + for (std::vector>::const_iterator iter = shape_ptrs.begin(); iter != shape_ptrs.end(); ++iter, ++value_iter) + { + info("Processing next shape...", 2); + current_image.fill(0); + (**iter).construct_volume(current_image, num_samples); + current_image *= *value_iter; + *out_density_ptr += current_image; + } return Succeeded::yes; } Succeeded -GenerateImage:: -save_image() +GenerateImage::save_image() { output_file_format_sptr->write_to_file(output_filename, *out_density_ptr); return Succeeded::yes; } shared_ptr> -GenerateImage:: -get_output_sptr() +GenerateImage::get_output_sptr() { return out_density_ptr; } diff --git a/src/Shape_buildblock/Shape3D.cxx b/src/Shape_buildblock/Shape3D.cxx index f596ef5eb..f9435fda2 100644 --- a/src/Shape_buildblock/Shape3D.cxx +++ b/src/Shape_buildblock/Shape3D.cxx @@ -26,7 +26,6 @@ using std::cerr; using std::endl; - // Check the sampled elements of the voxel START_NAMESPACE_STIR @@ -34,29 +33,25 @@ 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; } @@ -70,37 +65,29 @@ 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()) +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 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; - } - } + 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 @@ -109,14 +96,13 @@ 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) - // error("Shape3D::construct_volume currently ignores image origin (not shape origin)\n"); +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(); const int min_x = image.get_min_x(); @@ -124,67 +110,58 @@ 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); - - 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; - } - } - - if (num_samples.x() == 1 && num_samples.y() == 1 && num_samples.z() == 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++) + + { + 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) 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 @@ -212,28 +189,25 @@ void Shape3D::construct_slice(PixelsOnCartesianGrid &plane, plane[y][x]= get_voxel_weight(current_point,voxel_size, num_samples); } } - + #endif -void -Shape3D:: -set_defaults() +void +Shape3D::set_defaults() { - origin[3] = origin[2] = origin[1] =0; + 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 +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 340587851..2aae9d310 100644 --- a/src/Shape_buildblock/Shape3DWithOrientation.cxx +++ b/src/Shape_buildblock/Shape3DWithOrientation.cxx @@ -27,7 +27,6 @@ START_NAMESPACE_STIR - #if 0 void Shape3DWithOrientation:: @@ -63,23 +62,19 @@ set_directions_from_Euler_angles( } #endif - - 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) @@ -87,44 +82,38 @@ set_direction_vectors(const Array<2,float>& directions) // 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) + 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; + 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 +Shape3DWithOrientation::transform_to_shape_coords(const CartesianCoordinate3D& coord) const { - return - matrix_multiply(this->get_direction_vectors(), coord - this->get_origin()); + 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]; @@ -149,13 +138,12 @@ 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 @@ -165,9 +153,8 @@ set_defaults() #endif } -void -Shape3DWithOrientation:: -initialise_keymap() +void +Shape3DWithOrientation::initialise_keymap() { Shape3D::initialise_keymap(); #if 0 @@ -179,8 +166,7 @@ initialise_keymap() } bool -Shape3DWithOrientation:: -post_processing() +Shape3DWithOrientation::post_processing() { #if 0 if (alpha_in_degrees != 10000000.F @@ -216,8 +202,7 @@ post_processing() } void -Shape3DWithOrientation:: -set_key_values() +Shape3DWithOrientation::set_key_values() { base_type::set_key_values(); #if 0 diff --git a/src/Shape_buildblock/Shape_buildblock_registries.cxx b/src/Shape_buildblock/Shape_buildblock_registries.cxx index 7d278a3e7..cfb411d70 100644 --- a/src/Shape_buildblock/Shape_buildblock_registries.cxx +++ b/src/Shape_buildblock/Shape_buildblock_registries.cxx @@ -17,7 +17,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 06c513144..2c0dfa716 100644 --- a/src/SimSET/conv_SimSET_projdata_to_STIR.cxx +++ b/src/SimSET/conv_SimSET_projdata_to_STIR.cxx @@ -7,8 +7,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. @@ -16,7 +16,7 @@ \author Pablo Aguiar \author Charalampos Tsoumpas - \author Kris Thielemans + \author Kris Thielemans */ #include "stir/ProjDataInterfile.h" @@ -36,151 +36,135 @@ #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){ - 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){ - error("Cannot open the simset file %s", simset_filename); - } + "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)); if (is_null_ptr(scanner_sptr)) 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) + 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); + 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); - + ProjDataInterfile proj_data(exam_info_sptr, proj_data_info_sptr, stir_filename, std::ios::out); - if(strncmp(input_data_type,"fl",2)==0) - { - } - else + 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 !!! - { - - 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 d1d03115f..5f8c48900 100644 --- a/src/SimSET/conv_to_SimSET_att_image.cxx +++ b/src/SimSET/conv_to_SimSET_att_image.cxx @@ -6,7 +6,7 @@ This file is part of STIR. SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details */ /*! @@ -16,16 +16,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 @@ -34,8 +34,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 @@ -55,16 +55,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. */ @@ -73,60 +73,56 @@ #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) + if (argc != 3) { - std::cerr << "Usage:" << argv[0] - << " SimSET_image_filename original_image\n"; + 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])); + 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()) + 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; + 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; + { + 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 d6d252ab3..513964c5e 100644 --- a/src/SimSET/write_phg_image_info.c +++ b/src/SimSET/write_phg_image_info.c @@ -8,7 +8,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup simset \brief Write object-spec for PHG parameter file for SimSET \author Pablo Aguiar @@ -16,81 +16,98 @@ */ #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 + 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]:""); - - return reconstruction_object.reconstruct() == Succeeded::yes ? - EXIT_SUCCESS : EXIT_FAILURE; -} - +int +Main(int argc, char** argv) +{ + FBP2DReconstruction reconstruction_object(argc > 1 ? argv[1] : ""); + 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 f8369d57a..e5a74359b 100644 --- a/src/analytic/FBP2D/FBP2DReconstruction.cxx +++ b/src/analytic/FBP2D/FBP2DReconstruction.cxx @@ -41,34 +41,30 @@ #include "stir/error.h" #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 +void FBP2DReconstruction::initialise_keymap() { base_type::initialise_keymap(); @@ -76,26 +72,25 @@ FBP2DReconstruction::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 @@ -106,54 +101,51 @@ 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) + 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()); + 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 + 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 - num_segments_to_combine = 3; - } + { + 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; + } } if (is_null_ptr(back_projector_sptr)) @@ -162,14 +154,14 @@ 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()); } @@ -179,13 +171,11 @@ 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(); @@ -196,28 +186,22 @@ 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)); + 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; } @@ -228,11 +212,11 @@ actual_reconstruct(shared_ptr > const & density_ptr) // 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) + 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; + warning("FBP2D: segment 0 has non-zero tan(theta) %g", tan_theta); + return Succeeded::no; } } @@ -244,57 +228,48 @@ 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()))) + 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(); + 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; + 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(); + 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); + // 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()); - - const std::vector vs_nums_to_process = detail::find_basic_vs_nums_in_subset( - *proj_data_ptr->get_proj_data_info_sptr(), *symmetries_sptr, 0, 0, // only segment zero - 0, 1); // project everything, therefore subset 0 of 1 subsets + shared_ptr symmetries_sptr(back_projector_sptr->get_symmetries_used()->clone()); + + const std::vector vs_nums_to_process + = detail::find_basic_vs_nums_in_subset(*proj_data_ptr->get_proj_data_info_sptr(), + *symmetries_sptr, + 0, + 0, // only segment zero + 0, + 1); // project everything, therefore subset 0 of 1 subsets #ifdef STIR_OPENMP # pragma omp parallel @@ -334,43 +309,39 @@ actual_reconstruct(shared_ptr > const & density_ptr) } } 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()); + const ProjDataInfoCylindrical& proj_data_info_cyl + = dynamic_cast(*proj_data_ptr->get_proj_data_info_sptr()); float magic_number = 1.F; - if (dynamic_cast(back_projector_sptr.get()) != 0) + 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(); + // 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)) + if (proj_data_info_cyl.get_min_ring_difference(0) != proj_data_info_cyl.get_max_ring_difference(0)) { - magic_number=.5F; + 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 fc46191ca..3e9f973ee 100644 --- a/src/analytic/FBP2D/RampFilter.cxx +++ b/src/analytic/FBP2D/RampFilter.cxx @@ -41,77 +41,66 @@ 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) +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; + 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; - - for (Int i = 1; i <= length - 1; i += 2) { - 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 */ - } - if (0.5 <= fc) /* see realft for an explanation:data[2]=last real */ + /* 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; + 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 */ + } + 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.; @@ -121,65 +110,59 @@ 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) - { - filter[n] = ramp_filter_in_space(n, sampledist, length, alpha, fc); - 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 @@ -43,384 +43,379 @@ START_NAMESPACE_STIR -std::string ColsherFilter::parameter_info() const +std::string +ColsherFilter::parameter_info() const { std::ostringstream s; - s << "\nColsherFilter Parameters :=" + 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 := "< > 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 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; - } + 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) + if (stretch_factor_planar > 1 || stretch_factor_axial > 1) { - Array<2,float > colsher_real= - inverse_fourier_for_real_data_corrupting_input(filter); + 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); + 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) + +#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) + + 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; - } + 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; - 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; + // 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; - + + 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 (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 (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); + // 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 +# 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++) - { - 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]; + + 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++) + + for (int j = rmin; j <= rmax; j++) { - 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]; + 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]; + } } - } - + // stop_timers(); - } -#endif //NRFFT +#endif // NRFFT END_NAMESPACE_STIR diff --git a/src/analytic/FBP3DRP/FBP3DRP.cxx b/src/analytic/FBP3DRP/FBP3DRP.cxx index b3bd0007f..5a1073195 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 */ @@ -21,24 +21,20 @@ #include "stir/analytic/FBP3DRP/FBP3DRPReconstruction.h" #ifndef PARALLEL -#define Main main +# define Main main #else -#define Main master_main +# define Main master_main #endif using std::endl; using std::cerr; 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 2d6b4a332..f306d517e 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 @@ -25,9 +25,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 @@ -38,11 +38,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 @@ -56,20 +56,20 @@ - approximate analytic integral over delta by having a 1/2 in the backprojection of the last segment */ -//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: -// 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 -// by setting the number of bins of the segment and not of the scanner -// 4. The axial uniformity for data with span >1, seems to be OK except on the 3 fisrt and last planes -// 5. Drastic chnages in filtColsher.cxx as the definition of the -// Colsher filter is done out of the view loop. This will speed up the -// FBP3DRP implementation +// 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: +// 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 +// by setting the number of bins of the segment and not of the scanner +// 4. The axial uniformity for data with span >1, seems to be OK except on the 3 fisrt and last planes +// 5. Drastic chnages in filtColsher.cxx as the definition of the +// Colsher filter is done out of the view loop. This will speed up the +// FBP3DRP implementation #include "stir/RelatedViewgrams.h" #include "stir/VoxelsOnCartesianGrid.h" @@ -80,7 +80,7 @@ #include "stir/warning.h" #include "stir/error.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" @@ -98,7 +98,7 @@ #include #include #include -#include +#include // for asctime() #include @@ -112,76 +112,67 @@ 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) +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)); + + 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; - 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; - - + 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; + 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; + // 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(); @@ -191,27 +182,25 @@ 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 +void FBP3DRPReconstruction::initialise_keymap() { base_type::initialise_keymap(); @@ -225,81 +214,71 @@ 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 +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 + + // PARAMETERS => DISPLAY_LEVEL - save_intermediate_files =ask_num("Would you like to save all the intermediate images ? ",0,1,0 ); + 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); - image_for_reprojection_filename = - ask_string("filename of image to be reprojected (empty for using FBP):"); + save_intermediate_files = ask_num("Would you like to save all the intermediate images ? ", 0, 1, 0); -// PARAMETERS => ZEROES-PADDING IN FFT (PADS, PADZ) - cerr << "\nFilter parameters for 2D and 3D reconstruction"; + 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.); - 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); + 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) : "; - - 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); + // PARAMETERS => 3D RECONSTRUCTION COLSHER FILTER (ALPHA, FC) + cerr << "\nFor 3D reconstruction filtering (Colsher filter) : "; - - 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_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); + + 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 @@ -319,36 +298,34 @@ FBP3DRPReconstruction::ask_parameters() } std::string -FBP3DRPReconstruction:: -method_info() const -{ return("FBP3DRP"); } +FBP3DRPReconstruction::method_info() const +{ + return ("FBP3DRP"); +} FBP3DRPReconstruction::~FBP3DRPReconstruction() {} -VoxelsOnCartesianGrid& +VoxelsOnCartesianGrid& FBP3DRPReconstruction::estimated_image() { return static_cast&>(*image_estimate_density_ptr); } -const VoxelsOnCartesianGrid& +const VoxelsOnCartesianGrid& FBP3DRPReconstruction::estimated_image() const { return static_cast&>(*image_estimate_density_ptr); } -const ProjDataInfoCylindrical& +const ProjDataInfoCylindrical& FBP3DRPReconstruction::input_proj_data_info_cyl() const { - return - static_cast - (*proj_data_ptr->get_proj_data_info_sptr()); + return static_cast(*proj_data_ptr->get_proj_data_info_sptr()); } -FBP3DRPReconstruction:: -FBP3DRPReconstruction(const std::string& parameter_filename) -{ +FBP3DRPReconstruction::FBP3DRPReconstruction(const std::string& parameter_filename) +{ initialise(parameter_filename); } @@ -358,19 +335,18 @@ FBP3DRPReconstruction::FBP3DRPReconstruction() } 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!"); @@ -383,20 +359,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; { - //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); @@ -406,39 +380,38 @@ 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()) + 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()); 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 == "") - { - do_2D_reconstruction(); - + + 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 @@ -479,69 +452,59 @@ actual_reconstruct(shared_ptr > const& target_image_ }else{ alpha_fit = 1.F; beta_fit = 0.F; - } + } #endif - } + } else - { - do_read_image2D(); - // TODO set fit parameters - } + { + do_read_image2D(); + // TODO set fit parameters + } // 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()))) + 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(); + // 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(); + 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) + 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); + // 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, @@ -550,233 +513,216 @@ actual_reconstruct(shared_ptr > const& target_image_ #endif } - if(max_segment_num_to_process!=0) - do_3D_Reconstruction(image ); + if (max_segment_num_to_process != 0) + do_3D_Reconstruction(image); else { - // TODO + // TODO warning("\nOutput image will NOT be zoomed.\n"); image = estimated_image(); } - if(display_level>0) + if (display_level > 0) display(image, image.find_max(), "Final image"); 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() +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 << " - Displaying estimated image" << endl; - display(estimated_image(),estimated_image().find_max(), "Image estimate"); - } - + 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"); + } + 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() ); + 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) { - 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 < 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; + // 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) + { + 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 << 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); + } + // 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; #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; - } - } -#endif - } + 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 + } back_projector_sptr->get_output(image); // Normalise the image - if (dynamic_cast(back_projector_sptr.get()) == 0) + 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(); + 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); + full_log << " - Forward projection of missing data first from ring No " << new_min_axial_pos_num << " to " + << orig_min_axial_pos_num - 1 << endl; + 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) + 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); - + 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); } #if 0 if (fit_projections) @@ -844,194 +785,180 @@ 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) - { - prev_seg_num = seg_num; - full_log << " - Constructing Colsher filter for this segment\n"; - 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; - - + { + prev_seg_num = seg_num; + full_log << " - Constructing Colsher filter for this segment\n"; + 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; + #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) { - 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); - } - + viewgrams *= static_cast(num_ring_differences); } - if(display_level>2) { - display( viewgrams,viewgrams.find_max(), "Colsher filtered"); + } + 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) +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; + 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; - 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) +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_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_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 5f8734437..9c2f3e09f 100644 --- a/src/buildblock/ArcCorrection.cxx +++ b/src/buildblock/ArcCorrection.cxx @@ -33,262 +33,201 @@ #include "stir/warning.h" 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) +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) + 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"); + 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()); + 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) + 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); + 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)); + _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(); + 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] = 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 + 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) + 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; } - _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) +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) + 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)); + 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); + "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); + 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) +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) + 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)); + 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); + "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); + 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); - - overlap_interpolate(out.begin(), out.end(), - _arccorr_coords.begin(), _arccorr_coords.end(), - in.begin(), in.end(), - _noarccorr_coords.begin(), _noarccorr_coords.end()); + 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()); 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()); 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 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 +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()); + 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()); 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 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 +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()); + 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(); @@ -297,85 +236,72 @@ do_arc_correction(RelatedViewgrams& out, const RelatedViewgrams& i } RelatedViewgrams -ArcCorrection:: -do_arc_correction(const RelatedViewgrams& in) const +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()); + 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()); 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) + 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 +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()); + 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()); 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) + 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 +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()); + 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(),in.get_min_tof_pos_num()); + 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; - } + 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 4c6eda117..51a0efaee 100644 --- a/src/buildblock/Array.cxx +++ b/src/buildblock/Array.cxx @@ -8,17 +8,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. */ @@ -27,29 +27,28 @@ START_NAMESPACE_STIR - /************************************************** instantiations **************************************************/ // 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>; -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 a9dc4424e..ea0295365 100644 --- a/src/buildblock/ArrayFilter1DUsingConvolution.cxx +++ b/src/buildblock/ArrayFilter1DUsingConvolution.cxx @@ -32,66 +32,55 @@ 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 +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); + 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 +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()); + 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 +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()); + 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(); @@ -99,112 +88,98 @@ do_it(Array<1,elemT>& out_array, const Array<1,elemT>& in_array) const const int out_max = out_array.get_max_index(); if (is_trivial()) - { - int i=out_min; + { + 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: + switch (this->_bc) { - error("ArrayFilter1DUsingConvolution: cannot handle this boundary condition yet. sorry"); + 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]; + } } - { - for (; i<=min(in_max,out_max); ++i) + switch (this->_bc) { - out_array[i] = in_array[i]; + 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; } - 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++) - { - out_array[i] = 0; - 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"); - } - // region unaffected by boundary + for (int i = out_min; i <= out_max; i++) { - 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: + out_array[i] = 0; + int j = j_min; + // first do right edge + switch (this->_bc) { - //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; + 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"); } - default: + // region unaffected by boundary + { + for (; j <= min(j_max, i - in_min); ++j) + out_array[i] += filter_coefficients[j] * in_array[i - j]; + } + // left edge + switch (this->_bc) { - // should never get here, but without default: the compiler might issue a warning + 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 151efdcc8..d1039cde0 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 @@ -28,72 +28,64 @@ 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 +bool +ArrayFilter1DUsingConvolutionSymmetricKernel::is_trivial() const { - return - filter_coefficients.get_length() == 0 || - (filter_coefficients.get_length()==1 && - filter_coefficients[0] == 1); + 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()) - { - out_array = in_array; - return; - } + { + out_array = in_array; + return; + } const int in_min = in_array.get_min_index(); 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; - // 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; - - // now do rest of i+j separate - // next conditional is not necessary - //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]); - } - // now do rest of i-j separate - // next conditional is not necessary - //else + for (int i = in_array.get_min_index(); i <= in_array.get_max_index(); i++) { - for (; j<=min(j_max,i-in_min); j++) - out_array[i] += filter_coefficients[j]*(in_array[i-j]); + 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; + + // now do rest of i+j separate + // next conditional is not necessary + // 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]); + } + // now do rest of i-j separate + // next conditional is not necessary + // else + { + for (; j <= min(j_max, i - in_min); j++) + out_array[i] += filter_coefficients[j] * (in_array[i - j]); + } } - } #if 0 // untested implementation using padding VectorWithOffset in_array_padded = in_array; @@ -153,7 +145,6 @@ do_it(Array<1,elemT>& out_array, const Array<1,elemT>& in_array) const #endif } - #if 0 template static void @@ -171,4 +162,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 8c15a8f22..cab49a2b0 100644 --- a/src/buildblock/ArrayFilter2DUsingConvolution.cxx +++ b/src/buildblock/ArrayFilter2DUsingConvolution.cxx @@ -28,119 +28,93 @@ 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 +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); + 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 +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()); + 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 +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()); + 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; - } - + { + 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++) + 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]; + 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 7a5a00759..6f79d75d7 100644 --- a/src/buildblock/ArrayFilter3DUsingConvolution.cxx +++ b/src/buildblock/ArrayFilter3DUsingConvolution.cxx @@ -36,71 +36,57 @@ using std::fstream; using std::cerr; using std::endl; - 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 +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); + 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 +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()); + 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 +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()); + 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(); @@ -109,69 +95,65 @@ 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; + { + 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]; + + 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 (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)); - 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]; - - } - + { + 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)); + 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]; + } } #endif - #if 0 template void @@ -233,65 +215,52 @@ 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++) - - { - 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); - } + { + 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 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++) - { - 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 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]; + } +} // instantiation template class ArrayFilter3DUsingConvolution; END_NAMESPACE_STIR - diff --git a/src/buildblock/ArrayFilterUsingRealDFTWithPadding.cxx b/src/buildblock/ArrayFilterUsingRealDFTWithPadding.cxx index 23a911a37..b46a84b3b 100644 --- a/src/buildblock/ArrayFilterUsingRealDFTWithPadding.cxx +++ b/src/buildblock/ArrayFilterUsingRealDFTWithPadding.cxx @@ -27,35 +27,31 @@ #include #include "stir/error.h" - 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"); } 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"); } template Succeeded -ArrayFilterUsingRealDFTWithPadding:: -set_padding_range() +ArrayFilterUsingRealDFTWithPadding::set_padding_range() { BasicCoordinate min_indices, max_indices; @@ -63,44 +59,39 @@ set_padding_range() 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) + for (int d = 1; d <= num_dimensions; ++d) { - if (min_indices[d]!=0) - return Succeeded::no; + 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; + 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 + if (norm(min_indices) < .01) // i.e. min_indices==0 { - kernel_in_frequency_space = - fourier_for_real_data(real_filter_kernel); - }\ + 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 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); + 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); + kernel_in_frequency_space = fourier_for_real_data(real_filter_kernel_from_0); } return this->set_padding_range(); @@ -108,41 +99,36 @@ set_kernel(const Array& real_filter_kernel) 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 +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)); + 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 +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) + 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); + Array> tmp = fourier_for_real_data(in_array); + tmp *= kernel_in_frequency_space; + out_array = inverse_fourier_for_real_data_corrupting_input(tmp); } } - else + else { // copy input into padded_array using wrap-around @@ -155,11 +141,8 @@ do_it(Array& out_array, const Array; -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 bb9e1cb97..6673ffce8 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. @@ -29,7 +29,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). @@ -37,22 +36,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; - +const ByteOrder::Order ByteOrder::native_order + = *(reinterpret_cast(&magic)) == 1 ? little_endian : big_endian; END_NAMESPACE_STIR diff --git a/src/buildblock/ChainedDataProcessor.cxx b/src/buildblock/ChainedDataProcessor.cxx index 1cd35464d..4319e147d 100644 --- a/src/buildblock/ChainedDataProcessor.cxx +++ b/src/buildblock/ChainedDataProcessor.cxx @@ -18,92 +18,79 @@ */ #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) +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 + // 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 +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); - } + { + // 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); + this->apply_first->apply(out_data, in_data); } - else - if (!is_null_ptr(this->apply_second)) - this->apply_second->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"); @@ -112,29 +99,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 58af099f5..8010d965a 100644 --- a/src/buildblock/DataSymmetriesForViewSegmentNumbers.cxx +++ b/src/buildblock/DataSymmetriesForViewSegmentNumbers.cxx @@ -9,7 +9,7 @@ */ /*! \file - \ingroup projdata + \ingroup projdata \brief Implementations for class stir::DataSymmetriesForViewSegmentNumbers \author Kris Thielemans @@ -24,38 +24,29 @@ 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 { @@ -65,8 +56,7 @@ DataSymmetriesForViewSegmentNumbers::num_related_view_segment_numbers(const View } 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/DetectorCoordinateMap.cxx b/src/buildblock/DetectorCoordinateMap.cxx index 74cd5f5b4..30df16462 100644 --- a/src/buildblock/DetectorCoordinateMap.cxx +++ b/src/buildblock/DetectorCoordinateMap.cxx @@ -1,5 +1,5 @@ -/* - Copyright 2015, 2017 ETH Zurich, Institute of Particle Physics +/* + Copyright 2015, 2017 ETH Zurich, Institute of Particle Physics Copyright (C) 2021 University College London This file is part of STIR. @@ -26,185 +26,195 @@ #include "stir/warning.h" START_NAMESPACE_STIR - -DetectorCoordinateMap::det_pos_to_coord_type DetectorCoordinateMap::read_detectormap_from_file_help( const std::string& filename ) + +DetectorCoordinateMap::det_pos_to_coord_type +DetectorCoordinateMap::read_detectormap_from_file_help(const std::string& filename) { - std::ifstream myfile(filename.c_str()); - if( !myfile ) - { - error("Error opening file '" + filename + "'"); - } - - det_pos_to_coord_type coord_map; - 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; - } - return coord_map; -} + std::ifstream myfile(filename.c_str()); + if (!myfile) + { + error("Error opening file '" + filename + "'"); + } + det_pos_to_coord_type coord_map; + 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; + } + return coord_map; +} -void DetectorCoordinateMap::set_detector_map( const DetectorCoordinateMap::det_pos_to_coord_type& coord_map ) +void +DetectorCoordinateMap::set_detector_map(const DetectorCoordinateMap::det_pos_to_coord_type& coord_map) { - // The detector crystal coordinates are saved in coord_map the following way: - // (detector#, ring#, 1)[(x,y,z)] - // the detector# and ring# are determined outside of STIR (later given in input) - // In order to fulfill the STIR convention we have to give the coordinates - // detector# and ring# defined by ourself so that the start (0,0) goes to the - // coordinate with the smallest z and smallest y and the detector# is - // counterclockwise rising. - // To achieve this, we assign each coordinate the value 'coord_sorter' which - // is the assigned value of the criteria mentioned above. With it we sort the - // coordinates and fill the to maps 'input_index_to_det_pos' and - // 'det_pos_to_coord'. - std::vector coords_to_be_sorted; - boost::unordered_map > map_for_sorting_coordinates; - coords_to_be_sorted.reserve(coord_map.size()); - - unsigned min_tangential_coord = 1000000U; - unsigned min_axial_coord = 1000000U; - unsigned min_radial_coord = 1000000U; - num_tangential_coords = 0U; - num_axial_coords = 0U; - num_radial_coords = 0U; - for(auto it : coord_map) + // The detector crystal coordinates are saved in coord_map the following way: + // (detector#, ring#, 1)[(x,y,z)] + // the detector# and ring# are determined outside of STIR (later given in input) + // In order to fulfill the STIR convention we have to give the coordinates + // detector# and ring# defined by ourself so that the start (0,0) goes to the + // coordinate with the smallest z and smallest y and the detector# is + // counterclockwise rising. + // To achieve this, we assign each coordinate the value 'coord_sorter' which + // is the assigned value of the criteria mentioned above. With it we sort the + // coordinates and fill the to maps 'input_index_to_det_pos' and + // 'det_pos_to_coord'. + std::vector coords_to_be_sorted; + boost::unordered_map> map_for_sorting_coordinates; + coords_to_be_sorted.reserve(coord_map.size()); + + unsigned min_tangential_coord = 1000000U; + unsigned min_axial_coord = 1000000U; + unsigned min_radial_coord = 1000000U; + num_tangential_coords = 0U; + num_axial_coords = 0U; + num_radial_coords = 0U; + for (auto it : coord_map) { - double coord_sorter = it.second[1] * 100 + from_min_pi_plus_pi_to_0_2pi(std::atan2(it.second[3], -it.second[2])); - coords_to_be_sorted.push_back(coord_sorter); - map_for_sorting_coordinates[coord_sorter] = it.first; - - const auto detpos = it.first; - if (num_tangential_coords <= detpos.tangential_coord()) - num_tangential_coords = detpos.tangential_coord()+1; - if (min_tangential_coord > detpos.tangential_coord()) - min_tangential_coord = detpos.tangential_coord(); - if (num_axial_coords <= detpos.axial_coord()) - num_axial_coords = detpos.axial_coord()+1; - if (min_axial_coord > detpos.axial_coord()) - min_axial_coord = detpos.axial_coord(); - if (num_radial_coords <= detpos.radial_coord()) - num_radial_coords = detpos.radial_coord()+1; - if (min_radial_coord > detpos.radial_coord()) - min_radial_coord = detpos.radial_coord(); + double coord_sorter = it.second[1] * 100 + from_min_pi_plus_pi_to_0_2pi(std::atan2(it.second[3], -it.second[2])); + coords_to_be_sorted.push_back(coord_sorter); + map_for_sorting_coordinates[coord_sorter] = it.first; + + const auto detpos = it.first; + if (num_tangential_coords <= detpos.tangential_coord()) + num_tangential_coords = detpos.tangential_coord() + 1; + if (min_tangential_coord > detpos.tangential_coord()) + min_tangential_coord = detpos.tangential_coord(); + if (num_axial_coords <= detpos.axial_coord()) + num_axial_coords = detpos.axial_coord() + 1; + if (min_axial_coord > detpos.axial_coord()) + min_axial_coord = detpos.axial_coord(); + if (num_radial_coords <= detpos.radial_coord()) + num_radial_coords = detpos.radial_coord() + 1; + if (min_radial_coord > detpos.radial_coord()) + min_radial_coord = detpos.radial_coord(); } - if ((min_tangential_coord != 0) || (min_axial_coord != 0) || (min_radial_coord != 0)) - error("DetectorCoordinateMap::set_detector_map: minimum indices have to be zero."); - if ((num_tangential_coords * num_axial_coords * num_radial_coords) != coord_map.size()) - error("DetectorCoordinateMap::set_detector_map: maximum indices inconsistent with a regular 3D array.\n" - "Sizes derived from indices: tangential " + std::to_string(num_tangential_coords) + - ", axial " +std::to_string(num_axial_coords) + ", radial " + std::to_string(num_radial_coords) + - "\nOveral size: " + std::to_string(coord_map.size())); - -// std::sort(coords_to_be_sorted.begin(), coords_to_be_sorted.end()); - stir::DetectionPosition<> detpos(0,0,0); - for(std::vector::iterator it = coords_to_be_sorted.begin(); it != coords_to_be_sorted.end();++it) - { + if ((min_tangential_coord != 0) || (min_axial_coord != 0) || (min_radial_coord != 0)) + error("DetectorCoordinateMap::set_detector_map: minimum indices have to be zero."); + if ((num_tangential_coords * num_axial_coords * num_radial_coords) != coord_map.size()) + error("DetectorCoordinateMap::set_detector_map: maximum indices inconsistent with a regular 3D array.\n" + "Sizes derived from indices: tangential " + + std::to_string(num_tangential_coords) + ", axial " + std::to_string(num_axial_coords) + ", radial " + + std::to_string(num_radial_coords) + "\nOveral size: " + std::to_string(coord_map.size())); + + // std::sort(coords_to_be_sorted.begin(), coords_to_be_sorted.end()); + stir::DetectionPosition<> detpos(0, 0, 0); + for (std::vector::iterator it = coords_to_be_sorted.begin(); it != coords_to_be_sorted.end(); ++it) + { #if 0 input_index_to_det_pos[map_for_sorting_coordinates[*it]] = detpos; auto cart_coord = coord_map.at(map_for_sorting_coordinates[*it]); #else - input_index_to_det_pos[detpos] = detpos; - auto cart_coord = coord_map.at(detpos); + input_index_to_det_pos[detpos] = detpos; + auto cart_coord = coord_map.at(detpos); #endif - // rounding cart_coord to 3 and 2 decimal points then filling maps - cart_coord.z() = (round(cart_coord.z()*1000.0F))/1000.0F; - cart_coord.y() = (round(cart_coord.y()*1000.0F))/1000.0F; - cart_coord.x() = (round(cart_coord.x()*1000.0F))/1000.0F; - det_pos_to_coord[detpos] = cart_coord; - detection_position_map_given_cartesian_coord_keys_3_decimal[cart_coord] = detpos; //used to find bin from listmode data - cart_coord.z() = (round(cart_coord.z()*100.0F))/100.0F; - cart_coord.y() = (round(cart_coord.y()*100.0F))/100.0F; - cart_coord.x() = (round(cart_coord.x()*100.0F))/100.0F; - detection_position_map_given_cartesian_coord_keys_2_decimal[cart_coord] = detpos; - - ++detpos.tangential_coord(); - if (detpos.tangential_coord() == num_tangential_coords) - { - ++detpos.axial_coord(); - detpos.tangential_coord() = 0; - if (detpos.axial_coord() == num_axial_coords) - { - ++detpos.radial_coord(); - detpos.axial_coord() = 0; - } - } - } + // rounding cart_coord to 3 and 2 decimal points then filling maps + cart_coord.z() = (round(cart_coord.z() * 1000.0F)) / 1000.0F; + cart_coord.y() = (round(cart_coord.y() * 1000.0F)) / 1000.0F; + cart_coord.x() = (round(cart_coord.x() * 1000.0F)) / 1000.0F; + det_pos_to_coord[detpos] = cart_coord; + detection_position_map_given_cartesian_coord_keys_3_decimal[cart_coord] = detpos; // used to find bin from listmode data + cart_coord.z() = (round(cart_coord.z() * 100.0F)) / 100.0F; + cart_coord.y() = (round(cart_coord.y() * 100.0F)) / 100.0F; + cart_coord.x() = (round(cart_coord.x() * 100.0F)) / 100.0F; + detection_position_map_given_cartesian_coord_keys_2_decimal[cart_coord] = detpos; + + ++detpos.tangential_coord(); + if (detpos.tangential_coord() == num_tangential_coords) + { + ++detpos.axial_coord(); + detpos.tangential_coord() = 0; + if (detpos.axial_coord() == num_axial_coords) + { + ++detpos.radial_coord(); + detpos.axial_coord() = 0; + } + } + } } // creates maps to convert between stir and 3d coordinates -void DetectorCoordinateMap::read_detectormap_from_file( const std::string& filename ) +void +DetectorCoordinateMap::read_detectormap_from_file(const std::string& filename) { - det_pos_to_coord_type coord_map = - read_detectormap_from_file_help(filename); + det_pos_to_coord_type coord_map = read_detectormap_from_file_help(filename); set_detector_map(coord_map); } Succeeded -DetectorCoordinateMap:: -find_detection_position_given_cartesian_coordinate(DetectionPosition<>& det_pos, - const CartesianCoordinate3D& cart_coord) const +DetectorCoordinateMap::find_detection_position_given_cartesian_coordinate(DetectionPosition<>& det_pos, + const CartesianCoordinate3D& cart_coord) const { /*! first round the cartesian coordinates, it might happen that the cart_coord is not precisely pointing to the center of the crystal and then the det_pos cannot be found using the map */ - //rounding cart_coord to 3 decimal place and find det_pos + // rounding cart_coord to 3 decimal place and find det_pos CartesianCoordinate3D rounded_cart_coord; - rounded_cart_coord.z() = round(cart_coord.z()*1000.0F)/1000.0F; - rounded_cart_coord.y() = round(cart_coord.y()*1000.0F)/1000.0F; - rounded_cart_coord.x() = round(cart_coord.x()*1000.0F)/1000.0F; - if (detection_position_map_given_cartesian_coord_keys_3_decimal.count(rounded_cart_coord)) - { - det_pos = detection_position_map_given_cartesian_coord_keys_3_decimal.at(rounded_cart_coord); + rounded_cart_coord.z() = round(cart_coord.z() * 1000.0F) / 1000.0F; + rounded_cart_coord.y() = round(cart_coord.y() * 1000.0F) / 1000.0F; + rounded_cart_coord.x() = round(cart_coord.x() * 1000.0F) / 1000.0F; + if (detection_position_map_given_cartesian_coord_keys_3_decimal.count(rounded_cart_coord)) + { + det_pos = detection_position_map_given_cartesian_coord_keys_3_decimal.at(rounded_cart_coord); + return Succeeded::yes; + } + else + { + // rounding cart_coord to 2 decimal place and find det_pos + rounded_cart_coord.z() = round(cart_coord.z() * 100.0F) / 100.0F; + rounded_cart_coord.y() = round(cart_coord.y() * 100.0f) / 100.0F; + rounded_cart_coord.x() = round(cart_coord.x() * 100.0F) / 100.0F; + if (detection_position_map_given_cartesian_coord_keys_2_decimal.count(rounded_cart_coord)) + { + det_pos = detection_position_map_given_cartesian_coord_keys_2_decimal.at(rounded_cart_coord); return Succeeded::yes; - } - else - { - //rounding cart_coord to 2 decimal place and find det_pos - rounded_cart_coord.z() = round(cart_coord.z()*100.0F)/100.0F; - rounded_cart_coord.y() = round(cart_coord.y()*100.0f)/100.0F; - rounded_cart_coord.x() = round(cart_coord.x()*100.0F)/100.0F; - if (detection_position_map_given_cartesian_coord_keys_2_decimal.count(rounded_cart_coord)) - { - det_pos = detection_position_map_given_cartesian_coord_keys_2_decimal.at(rounded_cart_coord); - return Succeeded::yes; - } - else - { - rounded_cart_coord.z() = round(cart_coord.z()*10.0F)/10.0F; - rounded_cart_coord.y() = round(cart_coord.y()*10.0f)/10.0F; - rounded_cart_coord.x() = round(cart_coord.x()*10.0F)/10.0F; - if (detection_position_map_given_cartesian_coord_keys_2_decimal.count(rounded_cart_coord)) - { - det_pos = detection_position_map_given_cartesian_coord_keys_2_decimal.at(rounded_cart_coord); - return Succeeded::yes; - }else{ - warning("cartesian coordinate (x, y, z)=(%f, %f, %f) does not exist in the inner map", - cart_coord.x(), cart_coord.y(), cart_coord.z()); - return Succeeded::no; - } - } - } + } + else + { + rounded_cart_coord.z() = round(cart_coord.z() * 10.0F) / 10.0F; + rounded_cart_coord.y() = round(cart_coord.y() * 10.0f) / 10.0F; + rounded_cart_coord.x() = round(cart_coord.x() * 10.0F) / 10.0F; + if (detection_position_map_given_cartesian_coord_keys_2_decimal.count(rounded_cart_coord)) + { + det_pos = detection_position_map_given_cartesian_coord_keys_2_decimal.at(rounded_cart_coord); + return Succeeded::yes; + } + else + { + warning("cartesian coordinate (x, y, z)=(%f, %f, %f) does not exist in the inner map", + cart_coord.x(), + cart_coord.y(), + cart_coord.z()); + return Succeeded::no; + } + } + } } END_NAMESPACE_STIR diff --git a/src/buildblock/DiscretisedDensity.cxx b/src/buildblock/DiscretisedDensity.cxx index d908bef10..461fee1b0 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 @@ -25,16 +25,16 @@ */ #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" +# 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" #endif #include @@ -53,25 +53,24 @@ USING_NAMESPACE_ECAT7 USING_NAMESPACE_ECAT6 #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 @@ -79,102 +78,92 @@ 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_null_ptr(density_ptr)) - return density_ptr; - } - - - -#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 - 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); +# 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; + return density_ptr; } - else + +# ifdef HAVE_LLN_MATRIX + if (strncmp(signature, "MATRIX", 6) == 0) { - if (is_ECAT7_file(filename)) - warning("DiscretisedDensity::read_from_file ECAT7 file %s is of unsupported file type\n", filename.c_str()); +# ifndef NDEBUG + warning("DiscretisedDensity::read_from_file trying to read %s as ECAT7\n", filename.c_str()); +# 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_null_ptr(density_ptr)) + 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()); + } } +# endif // HAVE_LLN_MATRIX - } -#endif // HAVE_LLN_MATRIX - - -#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)) + 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; + 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; } } -#endif // HAVE_LLN_MATRIX +# 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 93f4b2839..c201d6173 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 @@ -36,19 +36,17 @@ using std::string; START_NAMESPACE_STIR -DynamicDiscretisedDensity:: -DynamicDiscretisedDensity(const DynamicDiscretisedDensity& 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; @@ -56,164 +54,164 @@ operator=(const DynamicDiscretisedDensity& argument) return *this; } -void -DynamicDiscretisedDensity:: -set_density(const DiscretisedDensity<3,float>& density, - const unsigned int frame_num) +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()); + // 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 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) ; } +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) ; } +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->exam_info_sptr->get_radionuclide().get_half_life(); } +const float +DynamicDiscretisedDensity::get_isotope_halflife() const +{ + return this->exam_info_sptr->get_radionuclide().get_half_life(); +} -const float -DynamicDiscretisedDensity:: -get_scanner_default_bin_size() const +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); + 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 ) + 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; - } + 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 +void +DynamicDiscretisedDensity::calibrate_frames() const { - for ( unsigned int frame_num = 1 ; frame_num<=get_time_frame_definitions().get_num_frames() ; ++frame_num ) + 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(); + *(_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:: - decay_correct_frames() +void +DynamicDiscretisedDensity::decay_correct_frames() { - if (_is_decay_corrected==true) + 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(get_isotope_halflife(),get_time_frame_definitions().get_start_time(frame_num),get_time_frame_definitions().get_end_time(frame_num))); + 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(get_isotope_halflife(), + get_time_frame_definitions().get_start_time(frame_num), + get_time_frame_definitions().get_end_time(frame_num))); } - _is_decay_corrected=true; + _is_decay_corrected = true; } } diff --git a/src/buildblock/DynamicProjData.cxx b/src/buildblock/DynamicProjData.cxx index 48369801f..4a62c68fa 100644 --- a/src/buildblock/DynamicProjData.cxx +++ b/src/buildblock/DynamicProjData.cxx @@ -47,162 +47,155 @@ 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)) - { + { #ifndef NDEBUG - info(boost::format("DynamicProjData::read_from_file trying to read %s as Interfile") % filename); + info(boost::format("DynamicProjData::read_from_file trying to read %s as Interfile") % filename); #endif - unique_ptr ptr(read_interfile_DPDFS(filename, std::ios::in)); - if (!is_null_ptr(ptr)) - return ptr; - else - error(boost::format("DynamicProjData::read_from_file failed to read %s as Interfile") % filename); - } + unique_ptr ptr(read_interfile_DPDFS(filename, std::ios::in)); + if (!is_null_ptr(ptr)) + return ptr; + else + error(boost::format("DynamicProjData::read_from_file failed to read %s as Interfile") % filename); + } #ifdef HAVE_LLN_MATRIX if (strncmp(signature, "MATRIX", 6) == 0) - { -#ifndef NDEBUG - warning("DynamicProjData::read_from_file trying to read '%s' as ECAT7", filename.c_str()); -#endif - USING_NAMESPACE_ECAT - USING_NAMESPACE_ECAT7 - - 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(); - } - 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( - // 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); +# ifndef NDEBUG + warning("DynamicProjData::read_from_file trying to read '%s' as ECAT7", filename.c_str()); +# endif + USING_NAMESPACE_ECAT + USING_NAMESPACE_ECAT7 - for (unsigned int frame_num=1; frame_num <= num_frames; ++ frame_num) + if (is_ECAT7_emission_file(filename)) { - dynamic_proj_data_ptr->_proj_datas[frame_num-1].reset( - ECAT7_to_PDFS(filename, - frame_num, - /*gate*/1, - /* data_num, bed_num, */ 0,0)); + 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(); + } + 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( + // 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)); + } + if (is_null_ptr(dynamic_proj_data_ptr->_proj_datas[0])) + error("DynamicProjData: No frame available\n"); + + return dynamic_proj_data_ptr; } - if (is_null_ptr(dynamic_proj_data_ptr->_proj_datas[0])) - error("DynamicProjData: No frame available\n"); - - return dynamic_proj_data_ptr; - } - else - { - if (is_ECAT7_file(filename)) + else { - warning("DynamicProjData::read_from_file ECAT7 file '%s' should be projection data.", filename.c_str()); - return unique_ptr(); + if (is_ECAT7_file(filename)) + { + warning("DynamicProjData::read_from_file ECAT7 file '%s' should be projection data.", filename.c_str()); + return unique_ptr(); + } } } - } - else + else { - warning("DynamicProjData::read_from_file '%s' seems to correspond to ECAT projection data, but not ECAT7. I cannot read this.", filename.c_str()); + 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) { + 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)); 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); + 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 ) + 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; - } + 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; @@ -212,16 +205,13 @@ 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) +static DynamicProjData* +read_interfile_DPDFS(istream& input, const string& directory_for_data, const std::ios::openmode open_mode) { - - InterfilePDFSHeader hdr; - if (!hdr.parse(input)) + InterfilePDFSHeader hdr; + + if (!hdr.parse(input)) { return 0; // KT 10122001 do not call ask_parameters anymore } @@ -231,113 +221,105 @@ read_interfile_DPDFS(istream& input, 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); - } - 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; + + 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; } -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); } - + 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 5387f081b..b32db22ef 100644 --- a/src/buildblock/ExamData.cxx +++ b/src/buildblock/ExamData.cxx @@ -15,21 +15,17 @@ */ #include "stir/ExamData.h" - #include START_NAMESPACE_STIR -ExamData:: -ExamData(): - exam_info_sptr(new ExamInfo()) +ExamData::ExamData() + : exam_info_sptr(new ExamInfo()) {} - -ExamData::ExamData(const shared_ptr &_this_exam) : - exam_info_sptr(_this_exam) +ExamData::ExamData(const shared_ptr& _this_exam) + : exam_info_sptr(_this_exam) {} - ExamData::~ExamData() {} @@ -40,9 +36,9 @@ ExamData::set_exam_info(ExamInfo const& new_exam_info) } void -ExamData::set_exam_info_sptr(shared_ptr new_exam_info_sptr) +ExamData::set_exam_info_sptr(shared_ptr new_exam_info_sptr) { - this->exam_info_sptr=new_exam_info_sptr; + this->exam_info_sptr = new_exam_info_sptr; } const ExamInfo& diff --git a/src/buildblock/ExamInfo.cxx b/src/buildblock/ExamInfo.cxx index 1769f8dbf..3eef284db 100644 --- a/src/buildblock/ExamInfo.cxx +++ b/src/buildblock/ExamInfo.cxx @@ -32,44 +32,37 @@ ExamInfo::parameter_info() const s << "Calibration Factor: " << std::fixed << std::setprecision(12) << this->calibration_factor << std::setprecision(5) << '\n'; s << "Radionuclide Parameters:\n" << this->radionuclide.parameter_info() << '\n'; s << "Patient position: " << this->patient_position.get_position_as_string() << '\n'; - s << "Scan start time: " << std::fixed << std::setprecision(1) <start_time_in_secs_since_1970 <<'\n'; // reset for further floats - - if (this->start_time_in_secs_since_1970>0) + s << "Scan start time: " << std::fixed << std::setprecision(1) << this->start_time_in_secs_since_1970 + << '\n'; // reset for further floats + + 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 << "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(); } -bool -ExamInfo::operator == (const ExamInfo &p1) const { - return abs(this->up_energy_thres - p1.up_energy_thres )<=1 && // keV - abs(this->low_energy_thres - p1.low_energy_thres) <=1 &&// keV - this->radionuclide==p1.radionuclide && - this->time_frame_definitions==p1.time_frame_definitions && -// this->branching_ratio==p1.branching_ratio && - ((this->calibration_factor<=0 && p1.calibration_factor<=0) || - abs(this->calibration_factor/p1.calibration_factor -1.)<=1E-3) && - this->imaging_modality==p1.imaging_modality && - this->patient_position==p1.patient_position && - abs(this->start_time_in_secs_since_1970 - p1.start_time_in_secs_since_1970)<=.5;// sec +bool +ExamInfo::operator==(const ExamInfo& p1) const +{ + return abs(this->up_energy_thres - p1.up_energy_thres) <= 1 && // keV + abs(this->low_energy_thres - p1.low_energy_thres) <= 1 && // keV + this->radionuclide == p1.radionuclide && this->time_frame_definitions == p1.time_frame_definitions && + // this->branching_ratio==p1.branching_ratio && + ((this->calibration_factor <= 0 && p1.calibration_factor <= 0) + || abs(this->calibration_factor / p1.calibration_factor - 1.) <= 1E-3) + && this->imaging_modality == p1.imaging_modality && this->patient_position == p1.patient_position + && abs(this->start_time_in_secs_since_1970 - p1.start_time_in_secs_since_1970) <= .5; // sec } END_NAMESPACE_STIR diff --git a/src/buildblock/FilePath.cxx b/src/buildblock/FilePath.cxx index 249b63145..598e6dcda 100644 --- a/src/buildblock/FilePath.cxx +++ b/src/buildblock/FilePath.cxx @@ -30,359 +30,365 @@ #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) +FilePath::FilePath(const std::string& __str, bool _run_checks) { - if(__str.size() == 0) - error(boost::format("FilePath: Cannot initialise empty path.")); + 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) +FilePath +FilePath::append(const FilePath& p) { - return append(p.get_path()); + return append(p.get_path()); } -FilePath FilePath::append(const std::string &p) +FilePath +FilePath::append(const std::string& p) { - // Check permissions - if (!is_writable()) - error(boost::format("FilePath: %1% is not writable.")%my_string); + // Check permissions + if (!is_writable()) + error(boost::format("FilePath: %1% is not writable.") % my_string); - std::string new_path = my_string; + std::string new_path = my_string; - //Check if this a directory or it contains a filename, too - if(!is_directory()) + // Check if this a directory or it contains a filename, too + if (!is_directory()) { - if(!is_regular_file()) + if (!is_regular_file()) { - error(boost::format("FilePath: Cannot find a directory in %1%.")%my_string); + error(boost::format("FilePath: Cannot find a directory in %1%.") % my_string); } - else + else { - new_path = get_path(); + 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()); + // 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++) + // 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); + 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) + // 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; + warning(boost::format("FilePath: Path %1% already exists.") % new_path); + continue; } - int nError; + 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) + if (-1 == nError) { - error("FilePath: Error creating directory!"); + error("FilePath: Error creating directory!"); } } - return FilePath(new_path); + return FilePath(new_path); } void -FilePath::add_extension(const std::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; + 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) + std::string::size_type pos = find_pos_of_extension(); + if (pos != std::string::npos) { - my_string.erase(pos); - my_string += e; + 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) + 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.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) + 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.substr(0, i + 1)); } - std::string empty; - return empty; + std::string empty; + return empty; } - std::string FilePath::get_filename() const { - std::size_t i = 0; + 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) + if (i != std::string::npos) { - return(my_string.substr(i+1, my_string.length() - i)); + return (my_string.substr(i + 1, my_string.length() - i)); } - return(my_string); + return (my_string); } std::string FilePath::get_filename_no_extension() const { - std::string ret = get_filename(); + std::string ret = get_filename(); - std::size_t i = find_pos_of_extension(); - if (i != std::string::npos) + std::size_t i = find_pos_of_extension(); + if (i != std::string::npos) { - return(ret.substr(0, i)); + return (ret.substr(0, i)); } - return(""); - + return (""); } std::string FilePath::get_extension() const { - std::size_t i = find_pos_of_extension(); - if (i != std::string::npos) + std::size_t i = find_pos_of_extension(); + if (i != std::string::npos) { - return(my_string.substr(i+1, my_string.length() - i)); + return (my_string.substr(i + 1, my_string.length() - i)); } - return(""); + return (""); } std::string FilePath::get_as_string() const { - return my_string; + return my_string; } -void FilePath::checks() const +void +FilePath::checks() const { - if (!run_checks) - return; + 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 ) + struct stat s; + if (stat(my_string.c_str(), &s) == 0) { - if ((s.st_mode & S_IFDIR ) && - ( s.st_mode & S_IFREG ) ) + 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); + error(boost::format("FilePath: File %1% is neither a directory nor a file") % my_string); } } - else + else { - error(boost::format("FilePath: Maybe %1% does not exist?")%my_string); + error(boost::format("FilePath: Maybe %1% does not exist?") % my_string); } #endif } -//On Windows there's GetCurrentDirectory -std::string FilePath::get_current_working_directory() +// 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; + char buffer[max_filename_length]; + char* ptr = getcwd(buffer, sizeof(buffer)); + std::string s_cwd; + if (ptr) + s_cwd = ptr; - return s_cwd; + return s_cwd; } -const std::vector FilePath::split(const std::string& s, const char* c) +const std::vector +FilePath::split(const std::string& s, const char* c) { - std::string buff = ""; - std::vector v; + 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++) + for (unsigned int i = 0; i < s.size(); i++) { - char n = s.at(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; + 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(); + 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; @@ -390,132 +396,129 @@ 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(); + 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 + // 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]; + // 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 +FilePath::merge(const std::string& first, const std::string& sec) { - std::string sep = separator; + 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()) + if (first[first.length() - 1] == *sep.c_str() && sec[0] == *sep.c_str()) { - return first.substr(0, first.length()-1) + sec; + 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())) + 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; + return first + sec; } - else /*( (first.back() != separator - && sec.front() != separator))*/ + else /*( (first.back() != separator + && sec.front() != separator))*/ { - return first + sep + sec; + return first + sep + sec; } } diff --git a/src/buildblock/GatedDiscretisedDensity.cxx b/src/buildblock/GatedDiscretisedDensity.cxx index f875cd7db..070a7bfd1 100644 --- a/src/buildblock/GatedDiscretisedDensity.cxx +++ b/src/buildblock/GatedDiscretisedDensity.cxx @@ -3,18 +3,18 @@ Copyright (C) 2005- 2009, Hammersmith Imanet Ltd Copyright (C) 2009- 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + 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" @@ -33,164 +33,162 @@ using std::string; START_NAMESPACE_STIR -GatedDiscretisedDensity:: -GatedDiscretisedDensity(const GatedDiscretisedDensity& 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) +GatedDiscretisedDensity::GatedDiscretisedDensity(const string& filename) { - const string gdef_filename=filename+".gdef"; + 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 ) - { + 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 ; + 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)); + 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() +void +GatedDiscretisedDensity::fill_with_zero() { - for (unsigned int gate_num=0; gate_num_time_gate_definitions.get_num_gates(); ++gate_num) + 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 ) - { + 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 ); + 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)); + 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 ) - { + 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 ; + 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)); + 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 +Succeeded +GatedDiscretisedDensity::write_to_files(const string& filename) const { - for ( unsigned int num = 1 ; num<=(_time_gate_definitions).get_num_gates() ; ++num ) + 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"; + 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) + 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; + } + 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 +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 ) + 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"; + 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) + 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; + } + 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 a4c55c422..981a51aba 100644 --- a/src/buildblock/GatedProjData.cxx +++ b/src/buildblock/GatedProjData.cxx @@ -35,8 +35,7 @@ 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) @@ -46,164 +45,153 @@ read_from_file(const string& filename) // The written image is read in respect t } 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 - warning("GatedProjData::read_from_file trying to read %s as ECAT7\n", filename.c_str()); -#endif - USING_NAMESPACE_ECAT - USING_NAMESPACE_ECAT7 - - 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(); - } - 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); - - 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"); - // 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()); +# ifndef NDEBUG + warning("GatedProjData::read_from_file trying to read %s as ECAT7\n", filename.c_str()); +# endif + USING_NAMESPACE_ECAT + USING_NAMESPACE_ECAT7 + + 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(); + } + 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); + + 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"); + // 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()); + } + else + { + if (is_ECAT7_file(filename)) + warning("GatedProjData::read_from_file ECAT7 file %s should be an emission sinogram\n", filename.c_str()); + } } - else - { - if (is_ECAT7_file(filename)) - 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, "Multi", 5) == 0) { + 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)); - } - + } + 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* GatedProjData::read_from_gdef(const string& filename) { - const string gdef_filename=filename+".gdef"; + 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 ) - { + 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"; + 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()); + 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); + 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 ) + 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; - } + 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; diff --git a/src/buildblock/GeneralisedPoissonNoiseGenerator.cxx b/src/buildblock/GeneralisedPoissonNoiseGenerator.cxx index 9a38abc21..112e8428e 100644 --- a/src/buildblock/GeneralisedPoissonNoiseGenerator.cxx +++ b/src/buildblock/GeneralisedPoissonNoiseGenerator.cxx @@ -10,7 +10,7 @@ /*! \file - \ingroup buildblock + \ingroup buildblock \brief Implements stir::GeneralisedPoissonNoiseGenerator \author Kris Thielemans \author Sanida Mustafovic @@ -31,30 +31,26 @@ 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) +GeneralisedPoissonNoiseGenerator::seed(unsigned int value) { - if (value==unsigned(0)) - error("Seed value has to be non-zero"); + 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.); @@ -62,77 +58,66 @@ generate_poisson_random(const float mu) // 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) - { - // 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 - // this has the advantage that we don't have to construct a normal_distrib - // 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; - - return static_cast(random<=0 ? 0 : round(random)); - } + { + // 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 + // this has the advantage that we don't have to construct a normal_distrib + // 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; + + return static_cast(random <= 0 ? 0 : round(random)); + } else - { - double u = random01(); - - // 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; - double accum = 1.; - double term = 1.; - unsigned int n = 1; - - while(accum 1 - 1.E-6) + u = 1 - 1.E-6; + + const double upper = exp(mu) * u; + double accum = 1.; + double term = 1.; + unsigned int n = 1; + + while (accum < upper) + { + accum += (term *= mu / n); + n++; + } + + return (n - 1); } - - return (n - 1); - } } float -GeneralisedPoissonNoiseGenerator:: -generate_scaled_poisson_random(const float mu, const float scaling_factor, const bool preserve_mean) +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); + 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) +GeneralisedPoissonNoiseGenerator::generate_random(const float mu) { - return - generate_scaled_poisson_random(mu, scaling_factor, preserve_mean); + 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++) +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); + 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) @@ -142,4 +127,3 @@ generate_random(ProjData& output_projdata, } END_NAMESPACE_STIR - diff --git a/src/buildblock/GeometryBlocksOnCylindrical.cxx b/src/buildblock/GeometryBlocksOnCylindrical.cxx old mode 100755 new mode 100644 index 3f1a1e8bb..81f3fd014 --- a/src/buildblock/GeometryBlocksOnCylindrical.cxx +++ b/src/buildblock/GeometryBlocksOnCylindrical.cxx @@ -6,7 +6,7 @@ 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, @@ -42,114 +42,105 @@ limitations under the License. START_NAMESPACE_STIR -GeometryBlocksOnCylindrical:: -GeometryBlocksOnCylindrical(const Scanner& scanner) +GeometryBlocksOnCylindrical::GeometryBlocksOnCylindrical(const Scanner& scanner) { build_crystal_maps(scanner); } stir::Array<2, float> -GeometryBlocksOnCylindrical:: -get_rotation_matrix(float alpha) const +GeometryBlocksOnCylindrical::get_rotation_matrix(float alpha) const { - return stir::make_array( - stir::make_1d_array(1.F,0.F,0.F), + return stir::make_array(stir::make_1d_array(1.F, 0.F, 0.F), stir::make_1d_array(0.F, std::cos(alpha), std::sin(alpha)), - stir::make_1d_array(0.F, -1*std::sin(alpha), std::cos(alpha)) - ); + stir::make_1d_array(0.F, -1 * std::sin(alpha), std::cos(alpha))); } void -GeometryBlocksOnCylindrical:: -build_crystal_maps(const Scanner& scanner) +GeometryBlocksOnCylindrical::build_crystal_maps(const Scanner& scanner) { - // local variables to describe scanner - int num_axial_crystals_per_block = scanner.get_num_axial_crystals_per_block(); - int num_transaxial_crystals_per_block = scanner.get_num_transaxial_crystals_per_block(); - int num_axial_blocks = scanner.get_num_axial_blocks(); - int num_transaxial_blocks_per_bucket = scanner.get_num_transaxial_blocks_per_bucket(); - int num_axial_blocks_per_bucket = scanner.get_num_axial_blocks_per_bucket(); - int num_transaxial_buckets = scanner.get_num_transaxial_blocks()/num_transaxial_blocks_per_bucket; - int num_axial_buckets = scanner.get_num_axial_blocks()/num_axial_blocks_per_bucket; - int num_detectors_per_ring = scanner.get_num_detectors_per_ring(); - float axial_block_spacing = scanner.get_axial_block_spacing(); - float transaxial_block_spacing = scanner.get_transaxial_block_spacing(); - float axial_crystal_spacing = scanner.get_axial_crystal_spacing(); - float transaxial_crystal_spacing = scanner.get_transaxial_crystal_spacing(); - - det_pos_to_coord_type cartesian_coord_map_given_detection_position_keys; - /*Building starts from a bucket perpendicular to y axis, from its first crystal. - see start_x*/ - - //calculate start_point to build the map. - -// estimate the angle covered by half bucket, csi - float csi=_PI/num_transaxial_buckets; - float trans_blocks_gap=transaxial_block_spacing-num_transaxial_crystals_per_block*transaxial_crystal_spacing; - float ax_blocks_gap=axial_block_spacing-num_axial_crystals_per_block*axial_crystal_spacing; - float csi_minus_csiGaps=csi-(csi/transaxial_block_spacing*2)* - (transaxial_crystal_spacing/2+trans_blocks_gap); -// distance between the center of the scannner and the first crystal in the bucket, r=Reffective/cos(csi) - float r=scanner.get_effective_ring_radius()/cos(csi_minus_csiGaps); - - float start_z = -(axial_block_spacing*(num_axial_blocks_per_bucket)*num_axial_buckets - -axial_crystal_spacing - ax_blocks_gap - *(num_axial_blocks_per_bucket*num_axial_buckets-1))/2; - float start_y = -1*scanner.get_effective_ring_radius(); - float start_x = -1*r*sin(csi_minus_csiGaps);//( -// ((num_transaxial_blocks_per_bucket-1)/2.)*transaxial_block_spacing -// + ((num_transaxial_crystals_per_block-1)/2.)*transaxial_crystal_spacing -// ); //the first crystal in the bucket - - stir::CartesianCoordinate3D start_point(start_z, start_y, start_x); - - for (int ax_bucket_num=0; ax_bucket_num det_pos(tangential_coord, axial_coord, radial_coord); - - //calculate cartesian coordinate for a given detector - stir::CartesianCoordinate3D transformation_matrix( - ax_block_num*axial_block_spacing + ax_crys_num*axial_crystal_spacing, - 0., - trans_block_num*transaxial_block_spacing + trans_crys_num*transaxial_crystal_spacing); - float alpha = scanner.get_intrinsic_azimuthal_tilt()+ - trans_bucket_num*(2*_PI)/num_transaxial_buckets+csi_minus_csiGaps; - - stir::Array<2, float> rotation_matrix = get_rotation_matrix(alpha); - // to match index range of CartesianCoordinate3D, which is 1 to 3 - rotation_matrix.set_min_index(1); - rotation_matrix[1].set_min_index(1); - rotation_matrix[2].set_min_index(1); - rotation_matrix[3].set_min_index(1); - - stir::CartesianCoordinate3D transformed_coord = - start_point + transformation_matrix; - stir::CartesianCoordinate3D cart_coord = - stir::matrix_multiply(rotation_matrix, transformed_coord); - - cartesian_coord_map_given_detection_position_keys[det_pos] = cart_coord; - } - set_detector_map(cartesian_coord_map_given_detection_position_keys); + // local variables to describe scanner + int num_axial_crystals_per_block = scanner.get_num_axial_crystals_per_block(); + int num_transaxial_crystals_per_block = scanner.get_num_transaxial_crystals_per_block(); + int num_axial_blocks = scanner.get_num_axial_blocks(); + int num_transaxial_blocks_per_bucket = scanner.get_num_transaxial_blocks_per_bucket(); + int num_axial_blocks_per_bucket = scanner.get_num_axial_blocks_per_bucket(); + int num_transaxial_buckets = scanner.get_num_transaxial_blocks() / num_transaxial_blocks_per_bucket; + int num_axial_buckets = scanner.get_num_axial_blocks() / num_axial_blocks_per_bucket; + int num_detectors_per_ring = scanner.get_num_detectors_per_ring(); + float axial_block_spacing = scanner.get_axial_block_spacing(); + float transaxial_block_spacing = scanner.get_transaxial_block_spacing(); + float axial_crystal_spacing = scanner.get_axial_crystal_spacing(); + float transaxial_crystal_spacing = scanner.get_transaxial_crystal_spacing(); + + det_pos_to_coord_type cartesian_coord_map_given_detection_position_keys; + /*Building starts from a bucket perpendicular to y axis, from its first crystal. + see start_x*/ + + // calculate start_point to build the map. + + // estimate the angle covered by half bucket, csi + float csi = _PI / num_transaxial_buckets; + float trans_blocks_gap = transaxial_block_spacing - num_transaxial_crystals_per_block * transaxial_crystal_spacing; + float ax_blocks_gap = axial_block_spacing - num_axial_crystals_per_block * axial_crystal_spacing; + float csi_minus_csiGaps = csi - (csi / transaxial_block_spacing * 2) * (transaxial_crystal_spacing / 2 + trans_blocks_gap); + // distance between the center of the scannner and the first crystal in the bucket, r=Reffective/cos(csi) + float r = scanner.get_effective_ring_radius() / cos(csi_minus_csiGaps); + + float start_z = -(axial_block_spacing * (num_axial_blocks_per_bucket)*num_axial_buckets - axial_crystal_spacing + - ax_blocks_gap * (num_axial_blocks_per_bucket * num_axial_buckets - 1)) + / 2; + float start_y = -1 * scanner.get_effective_ring_radius(); + float start_x + = -1 * r + * sin(csi_minus_csiGaps); //( + // ((num_transaxial_blocks_per_bucket-1)/2.)*transaxial_block_spacing + // + ((num_transaxial_crystals_per_block-1)/2.)*transaxial_crystal_spacing + // ); //the first crystal in the bucket + + stir::CartesianCoordinate3D start_point(start_z, start_y, start_x); + + for (int ax_bucket_num = 0; ax_bucket_num < num_axial_buckets; ++ax_bucket_num) + for (int ax_block_num = 0; ax_block_num < num_axial_blocks; ++ax_block_num) + for (int ax_crys_num = 0; ax_crys_num < num_axial_crystals_per_block; ++ax_crys_num) + for (int trans_bucket_num = 0; trans_bucket_num < num_transaxial_buckets; ++trans_bucket_num) + for (int trans_block_num = 0; trans_block_num < num_transaxial_blocks_per_bucket; ++trans_block_num) + for (int trans_crys_num = 0; trans_crys_num < num_transaxial_crystals_per_block; ++trans_crys_num) + { + // calculate detection position for a given detector + // note: in STIR convention, crystal(0,0,0) corresponds to card_coord(z=0,y=-r,x=0) + int tangential_coord; + tangential_coord = trans_bucket_num * num_transaxial_blocks_per_bucket * num_transaxial_crystals_per_block + + trans_block_num * num_transaxial_crystals_per_block + trans_crys_num; + + if (tangential_coord < 0) + tangential_coord += num_detectors_per_ring; + + int axial_coord = ax_bucket_num * num_axial_blocks_per_bucket * num_axial_crystals_per_block + + ax_block_num * num_axial_crystals_per_block + ax_crys_num; + int radial_coord = 0; + stir::DetectionPosition<> det_pos(tangential_coord, axial_coord, radial_coord); + + // calculate cartesian coordinate for a given detector + stir::CartesianCoordinate3D transformation_matrix( + ax_block_num * axial_block_spacing + ax_crys_num * axial_crystal_spacing, + 0., + trans_block_num * transaxial_block_spacing + trans_crys_num * transaxial_crystal_spacing); + float alpha = scanner.get_intrinsic_azimuthal_tilt() + trans_bucket_num * (2 * _PI) / num_transaxial_buckets + + csi_minus_csiGaps; + + stir::Array<2, float> rotation_matrix = get_rotation_matrix(alpha); + // to match index range of CartesianCoordinate3D, which is 1 to 3 + rotation_matrix.set_min_index(1); + rotation_matrix[1].set_min_index(1); + rotation_matrix[2].set_min_index(1); + rotation_matrix[3].set_min_index(1); + + stir::CartesianCoordinate3D transformed_coord = start_point + transformation_matrix; + stir::CartesianCoordinate3D cart_coord = stir::matrix_multiply(rotation_matrix, transformed_coord); + + cartesian_coord_map_given_detection_position_keys[det_pos] = cart_coord; + } + set_detector_map(cartesian_coord_map_given_detection_position_keys); } - END_NAMESPACE_STIR diff --git a/src/buildblock/HUToMuImageProcessor.cxx b/src/buildblock/HUToMuImageProcessor.cxx index 28230adb9..5c9460d2d 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 @@ -22,54 +22,48 @@ #include "stir/error.h" #include "stir/round.h" #ifdef HAVE_JSON - #include +# include #endif 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"; @@ -79,8 +73,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"); @@ -92,21 +85,18 @@ initialise_keymap() } template -const char * const -HUToMuImageProcessor::registered_name = "HUToMu"; +const char* const HUToMuImageProcessor::registered_name = "HUToMu"; 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) { #ifdef HAVE_JSON this->get_record_from_json(); @@ -117,58 +107,59 @@ virtual_set_up(const TargetT& image) #ifdef HAVE_JSON 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 + "\")"); + error("HUToMu: No or incorrect JSON slopes set (could not find \"scale\" in file \"" + filename + "\")"); } - //Put user-specified manufacturer into upper case. + // 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); + % 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) ) - location = pos; - pos++; - } + for (auto entry : target) + { + if ((stir::round(float(entry["kev"])) == keV) && (stir::round(float(entry["kvp"])) == kVp)) + location = pos; + pos++; + } - if (location == -1){ - stir::error("HUToMu: Desired slope not found!"); - } + 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"]; @@ -178,14 +169,13 @@ get_record_from_json() this->breakPoint = transform["break"]; - //std::cout << transform.dump(4); + // std::cout << transform.dump(4); } #endif template void -HUToMuImageProcessor:: -set_slope(float a1, float a2, float b1, float b2, float breakPoint) +HUToMuImageProcessor::set_slope(float a1, float a2, float b1, float b2, float breakPoint) { this->a1 = a1; this->a2 = a2; @@ -196,58 +186,53 @@ set_slope(float a1, float a2, float b1, float b2, float breakPoint) 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); - } - - ++in_iter; ++out_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; + } } 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 +HUToMuImageProcessor::virtual_apply(TargetT& density) const { - shared_ptr copy_sptr(density.clone()); + 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 34b1cf3ab..c47b5a918 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 @@ -26,60 +26,58 @@ START_NAMESPACE_STIR template bool -IndexRange::get_regular_range( - BasicCoordinate& min, - BasicCoordinate& max) const +IndexRange::get_regular_range(BasicCoordinate& min, + BasicCoordinate& max) const { - // check if empty range + // check if empty range if (base_type::begin() == base_type::end()) - { - std::fill(min.begin(), min.end(), 0); - std::fill(max.begin(), max.end(),-1); - return true; - } + { + std::fill(min.begin(), min.end(), 0); + std::fill(max.begin(), max.end(), -1); + return true; + } // if not a regular range, exit 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 (!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())) - { - is_regular_range = regular_false; - return false; - } + // 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 (!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())) + { + is_regular_range = regular_false; + return false; + } + } + // yes, they do + is_regular_range = regular_true; } - // yes, they do - is_regular_range = regular_true; - } min = join(base_type::get_min_index(), lower_dim_min); - max = join(base_type::get_max_index(), lower_dim_max); + max = join(base_type::get_max_index(), lower_dim_max); return true; } - /*************************************************** instantiations ***************************************************/ diff --git a/src/buildblock/KeyParser.cxx b/src/buildblock/KeyParser.cxx index 8f6d5c980..5e80e2bfe 100644 --- a/src/buildblock/KeyParser.cxx +++ b/src/buildblock/KeyParser.cxx @@ -46,7 +46,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; @@ -67,21 +67,21 @@ 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); #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 + 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,...); @@ -91,61 +91,58 @@ static void read_line(istream& input, string& line, 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 + 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); + { + 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, + // 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); - } + { + 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; - } - } + { + 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; - } + { + // exit the loop + break; + } } // replace ${text} with value of environment variable @@ -153,27 +150,24 @@ static void read_line(istream& input, string& line, 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); - } + 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); + } } } } @@ -181,114 +175,105 @@ static void read_line(istream& input, string& line, // 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, +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) + 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(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() -{ -} +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) +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; + 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() { - - current_index=-1; - status=end_parsing; - current=0;//KTnew map_element(); + + current_index = -1; + status = end_parsing; + current = 0; // KTnew map_element(); } KeyParser::~KeyParser() -{ -} +{} -bool KeyParser::parse(const char * const filename, const bool write_warning) +bool +KeyParser::parse(const char* const filename, const bool write_warning) { - ifstream hdr_stream(filename); - if (!hdr_stream) - { + 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); + return parse(hdr_stream, write_warning); } -bool KeyParser::parse(const std::string& s, const bool write_warning) +bool +KeyParser::parse(const std::string& s, const bool write_warning) { std::stringstream hdr_stream(s); 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' @@ -296,35 +281,34 @@ bool KeyParser::parse(istream& f, const bool write_warning) with a single space. */ -string +string KeyParser::standardise_keyword(const string& keyword) const { return standardise_interfile_keyword(keyword); } // KT 07/10/2002 moved here from Line -string +string KeyParser::get_keyword(const string& line) const { - // keyword stops at either := or an index [] - auto eok = line.find_first_of(":[",0); + // keyword stops at either := or an index [] + auto eok = line.find_first_of(":[", 0); // check that = follows : to allow keywords containing colons - while (eok != string::npos && line[eok] == ':' && eok+1 < line.size() && line[eok+1] != '=') + while (eok != string::npos && line[eok] == ':' && eok + 1 < line.size() && line[eok + 1] != '=') { - eok = line.find_first_of(":[", eok+1); + eok = line.find_first_of(":[", eok + 1); } - return line.substr(0,eok); + return line.substr(0, eok); } -map_element* KeyParser::find_in_keymap(const string& keyword) +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); - } + for (Keymap::iterator iter = kmap.begin(); iter != kmap.end(); ++iter) + { + if (iter->first == keyword) + return &(iter->second); + } // it wasn't there return 0; } @@ -332,237 +316,232 @@ map_element* KeyParser::find_in_keymap(const string& keyword) 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; - } - } + 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 +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); + 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; - } + { + 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)); + 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); - } +{ + 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); - } +{ + 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); - } +{ + add_key(keyword, KeyArgument::NONE, &KeyParser::do_nothing); +} void KeyParser::add_start_key(const string& keyword) - { - add_key(keyword, KeyArgument::NONE, &KeyParser::start_parsing); - } +{ + add_key(keyword, KeyArgument::NONE, &KeyParser::start_parsing); +} void KeyParser::add_stop_key(const string& keyword) - { - add_key(keyword, KeyArgument::NONE, &KeyParser::stop_parsing); - } - - - +{ + 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::add_alias_key(const std::string& keyword, const std::string& alias, bool deprecated_key) +void +KeyParser::add_alias_key(const std::string& keyword, const std::string& alias, bool deprecated_key) { const auto std_alias = standardise_keyword(alias); const auto std_kw = standardise_keyword(keyword); @@ -576,61 +555,60 @@ void KeyParser::print_keywords_to_stream(ostream& out) const { for (Keymap::const_iterator key = kmap.begin(); key != kmap.end(); ++key) - { - out << key->first << '\n'; - } + { + out << key->first << '\n'; + } out << endl; } - -Succeeded KeyParser::parse_header(const bool write_warning) +Succeeded +KeyParser::parse_header(const bool write_warning) { - - if (read_and_parse_line(false) == Succeeded::yes) + + if (read_and_parse_line(false) == Succeeded::yes) process_key(); 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) - { - 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()); + // 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) + { + 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()); + } + 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; } - else + + while (status == parsing) { - // 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"); + if (read_and_parse_line(write_warning) == Succeeded::yes) + process_key(); + if (input->eof()) + { + status = end_parsing; + } } - return Succeeded::no; - } - while(status==parsing) - { - if(read_and_parse_line(write_warning) == Succeeded::yes) - process_key(); - if (input->eof()) { - status = end_parsing; - } - } - - return Succeeded::yes; - -} +} -std::string KeyParser::resolve_alias(const std::string& kw) const +std::string +KeyParser::resolve_alias(const std::string& kw) const { // search in alias_map { @@ -654,50 +632,49 @@ std::string KeyParser::resolve_alias(const std::string& kw) const return kw; } -Succeeded KeyParser::read_and_parse_line(const bool write_warning) +Succeeded +KeyParser::read_and_parse_line(const bool write_warning) { - string line; + 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; - } - + { + 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) + if (pos != string::npos) + break; + // check if empty line + if (line.size() == 0) break; - // check if empty line - if (line.size() == 0) - break; } // gets keyword - keyword=resolve_alias(standardise_keyword(get_keyword(line))); + keyword = resolve_alias(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 +static Succeeded get_param_from_string(T& param, const string& s) { - const string::size_type cp=s.find('=',0); - if(cp==string::npos) + 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; } @@ -706,19 +683,19 @@ template <> Succeeded 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 cp = s.find('=', 0); + if (cp != 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); - return Succeeded::yes; + // 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) + { + // strip trailing white space + const string::size_type eok = s.find_last_not_of(" \t", s.length()); + param = s.substr(sok, eok - sok + 1); + return Succeeded::yes; + } } - } return Succeeded::no; } @@ -726,57 +703,55 @@ get_param_from_string(string& param, const string& s) // this is currently only used for the matrix_size keywords in InterfileHeader. template -static -Succeeded +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) + const string::size_type cp = s.find('=', 0); + if (cp != string::npos) { - istrstream str(s.c_str()+start); - - if (s[start] == '{') - str >> param; - else - { - param.resize(1); - str >> param[0]; - } - return str.fail() ? Succeeded::no : Succeeded::yes; + // 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); + + if (s[start] == '{') + str >> param; + else + { + param.resize(1); + str >> param[0]; + } + return str.fail() ? Succeeded::no : Succeeded::yes; + } } - } return Succeeded::no; } template -static -Succeeded +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) + const string::size_type cp = s.find('=', 0); + if (cp != string::npos) { - istrstream str(s.c_str()+start); - - if (s[start] == '{') - str >> param; - else - { - param = VectorWithOffset(); // TODO will NOT work with multi-dimensional arrays - param.grow(0,0); - str >> param[0]; - } - return str.fail() ? Succeeded::no : Succeeded::yes; + // 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); + + if (s[start] == '{') + str >> param; + else + { + param = VectorWithOffset(); // TODO will NOT work with multi-dimensional arrays + param.grow(0, 0); + str >> param[0]; + } + return str.fail() ? Succeeded::no : Succeeded::yes; + } } - } return Succeeded::no; } @@ -785,74 +760,75 @@ template <> Succeeded 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) + string::size_type cp = s.find('=', 0); + if (cp != string::npos) { - if (s[start] == '{') - { - bool end=false; - cp = start+1; - while (!end) + // 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) { - cp=s.find_first_not_of("},",cp); - cp=s.find_first_not_of(" \t",cp); - - if(cp==string::npos) - { - end=true; - } + 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; + } + } + } else - { - string::size_type eop=s.find_first_of(",}",cp); - if(eop==string::npos) { - end=true; - eop=s.length(); + param.resize(1); + param[0] = s.substr(start, s.find_last_not_of(" \t", s.size())); } - // 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; - } + return Succeeded::yes; } - } - else - { - param.resize(1); - param[0] = s.substr(start, s.find_last_not_of(" \t",s.size())); - } - return Succeeded::yes; } - } return Succeeded::no; } // 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); - // check if closing bracket really there - if (eok == string::npos) + const string::size_type cp = line.find_first_of(":[", 0); + if (cp != string::npos && line[cp] == '[') { - // 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."); - return 0; + 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) + { + // 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."); + return 0; + } + in = atoi(line.substr(sok, eok - sok).c_str()); } - in=atoi(line.substr(sok,eok-sok).c_str()); - } return in; } @@ -866,110 +842,97 @@ struct Type2Type }; 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 : - keyword_has_a_value = false; - break; - 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; - break; - 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; - 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; - break; - case KeyArgument::DOUBLE : - 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; - break; - 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_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; - break; - case KeyArgument::ARRAY2D_OF_FLOATS: - 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; - break; - case KeyArgument::BASICCOORDINATE3D_OF_FLOATS: - 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; - break; - 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 + 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: + // 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; + break; + 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; + 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; + break; + case KeyArgument::DOUBLE: + 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; + break; + 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_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; + break; + case KeyArgument::ARRAY2D_OF_FLOATS: + 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; + break; + case KeyArgument::BASICCOORDINATE3D_OF_FLOATS: + 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; + break; + 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 + } + return Succeeded::yes; } - return Succeeded::yes; - } // skip empty lines and comments if (keyword.length() != 0 && keyword[0] != ';' && write_warning) @@ -979,457 +942,443 @@ Succeeded KeyParser::parse_value_in_line(const string& line, const bool write_wa return Succeeded::no; } -void KeyParser::start_parsing() +void +KeyParser::start_parsing() { - status=parsing; + status = parsing; } -void KeyParser::stop_parsing() +void +KeyParser::stop_parsing() { - status=end_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) +void static assign_to_list(T1& mylist, const T2& value, const int current_index, const string& keyword) { - if(mylist.size() < static_cast(current_index)) + 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); + "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; + 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_index) { - if (current->vectorised_key_level>0) + 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" + 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; + 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; - } + { + // 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; + } #undef KP_case_assign } - else // Sets vector elements using current_index + 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 (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; - } + { + // 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 - std::stringstream stemp; - - // 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; - } - } +/* 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 + std::stringstream stemp; + + // 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; + } } -void KeyParser::value_to_stream(std::ostream& s, const map_element& element) +} // namespace detail + +void +KeyParser::value_to_stream(std::ostream& s, const map_element& element) { -#define KP_case_to_stream(KeyArgumentValue, type) \ - case KeyArgumentValue : \ - s << *reinterpret_cast(element.p_object_variable); break - switch(element.type) +#define KP_case_to_stream(KeyArgumentValue, type) \ + case KeyArgumentValue: \ + s << *reinterpret_cast(element.p_object_variable); \ + break + switch (element.type) { KP_case_to_stream(KeyArgument::INT, int); KP_case_to_stream(KeyArgument::UINT, unsigned int); - KP_case_to_stream(KeyArgument::ULONG,unsigned long); - KP_case_to_stream(KeyArgument::LONG,long); - KP_case_to_stream(KeyArgument::DOUBLE,double); - KP_case_to_stream(KeyArgument::FLOAT,float); + KP_case_to_stream(KeyArgument::ULONG, unsigned long); + KP_case_to_stream(KeyArgument::LONG, long); + KP_case_to_stream(KeyArgument::DOUBLE, double); + KP_case_to_stream(KeyArgument::FLOAT, float); KP_case_to_stream(KeyArgument::ASCII, std::string); KP_case_to_stream(KeyArgument::LIST_OF_INTS, IntVect); KP_case_to_stream(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; + // 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_to_stream(KeyArgument::ARRAY2D_OF_FLOATS, KP_array2d); // KP_case_to_stream(KeyArgument::ARRAY3D_OF_FLOATS, KP_array3d); KP_case_to_stream(KeyArgument::BASICCOORDINATE3D_OF_FLOATS, KP_coord); - KP_case_to_stream(KeyArgument::BASICCOORDINATE3D_OF_ARRAY3D_OF_FLOATS,KP_coord_array3d); + KP_case_to_stream(KeyArgument::BASICCOORDINATE3D_OF_ARRAY3D_OF_FLOATS, KP_coord_array3d); KP_case_to_stream(KeyArgument::LIST_OF_ASCII, std::vector); case KeyArgument::BOOL: - s << (*reinterpret_cast(element.p_object_variable) ? 1 : 0); break; + s << (*reinterpret_cast(element.p_object_variable) ? 1 : 0); + break; case KeyArgument::NONE: break; - case KeyArgument::ASCIIlist : - { + case KeyArgument::ASCIIlist: { const int index = *reinterpret_cast(element.p_object_variable); - s << (index == -1 ? - "UNALLOWED VALUE" : - (*element.p_object_list_of_values)[index]); + s << (index == -1 ? "UNALLOWED VALUE" : (*element.p_object_list_of_values)[index]); break; } - case KeyArgument::PARSINGOBJECT: - { - auto parsing_object_ptr = - *reinterpret_cast(element.p_object_variable); - if (parsing_object_ptr!=0) - { - s << parsing_object_ptr->get_registered_name() << endl; - s << parsing_object_ptr->parameter_info() << endl; - } + case KeyArgument::PARSINGOBJECT: { + auto parsing_object_ptr = *reinterpret_cast(element.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: - { - auto parsing_object_ptr = - (*reinterpret_cast*>(element.p_object_variable)); + case KeyArgument::SHARED_PARSINGOBJECT: { + auto parsing_object_ptr = (*reinterpret_cast*>(element.p_object_variable)); if (!is_null_ptr(parsing_object_ptr)) - { - s << parsing_object_ptr->get_registered_name() << endl; - s << parsing_object_ptr->parameter_info(); - } + { + s << parsing_object_ptr->get_registered_name() << endl; + s << parsing_object_ptr->parameter_info(); + } else s << "None"; break; } case KeyArgument::ARRAY2D_OF_FLOATS: - detail::to_stream(s, *reinterpret_cast*>(element.p_object_variable)); break; + detail::to_stream(s, *reinterpret_cast*>(element.p_object_variable)); + break; case KeyArgument::ARRAY3D_OF_FLOATS: - detail::to_stream(s, *reinterpret_cast*>(element.p_object_variable)); break; - default : + detail::to_stream(s, *reinterpret_cast*>(element.p_object_variable)); + break; + default: warning("KeyParser error: unknown type. Implementation error\n"); break; } - #undef KP_case_to_stream +#undef KP_case_to_stream } // sadly largely a repetition of the above, but now with a cast to std::vector and a loop // Ugly! -void KeyParser::vectorised_value_to_stream(std::ostream& s, const std::string& keyword, const map_element& element) -{ -#define KP_case_to_stream(KeyArgumentValue, type) \ - case KeyArgumentValue : \ - { \ - auto vect = *reinterpret_cast *>(element.p_object_variable); \ - for (unsigned current_index=1; current_index <= vect.size(); ++current_index) \ - s << keyword << '[' << current_index << "] := " << vect[current_index-1] << '\n'; \ - } \ - break - switch(element.type) +void +KeyParser::vectorised_value_to_stream(std::ostream& s, const std::string& keyword, const map_element& element) +{ +#define KP_case_to_stream(KeyArgumentValue, type) \ + case KeyArgumentValue: { \ + auto vect = *reinterpret_cast*>(element.p_object_variable); \ + for (unsigned current_index = 1; current_index <= vect.size(); ++current_index) \ + s << keyword << '[' << current_index << "] := " << vect[current_index - 1] << '\n'; \ + } \ + break + switch (element.type) { KP_case_to_stream(KeyArgument::INT, int); KP_case_to_stream(KeyArgument::UINT, unsigned int); - KP_case_to_stream(KeyArgument::ULONG,unsigned long); - KP_case_to_stream(KeyArgument::LONG,long); - KP_case_to_stream(KeyArgument::DOUBLE,double); - KP_case_to_stream(KeyArgument::FLOAT,float); + KP_case_to_stream(KeyArgument::ULONG, unsigned long); + KP_case_to_stream(KeyArgument::LONG, long); + KP_case_to_stream(KeyArgument::DOUBLE, double); + KP_case_to_stream(KeyArgument::FLOAT, float); KP_case_to_stream(KeyArgument::ASCII, std::string); KP_case_to_stream(KeyArgument::LIST_OF_INTS, IntVect); KP_case_to_stream(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; + // 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_to_stream(KeyArgument::ARRAY2D_OF_FLOATS, KP_array2d); // KP_case_to_stream(KeyArgument::ARRAY3D_OF_FLOATS, KP_array3d); KP_case_to_stream(KeyArgument::BASICCOORDINATE3D_OF_FLOATS, KP_coord); - KP_case_to_stream(KeyArgument::BASICCOORDINATE3D_OF_ARRAY3D_OF_FLOATS,KP_coord_array3d); + KP_case_to_stream(KeyArgument::BASICCOORDINATE3D_OF_ARRAY3D_OF_FLOATS, KP_coord_array3d); KP_case_to_stream(KeyArgument::LIST_OF_ASCII, std::vector); - case KeyArgument::BOOL: - { - auto vect = *reinterpret_cast *>(element.p_object_variable); - for (unsigned current_index=1; current_index <= vect.size(); ++current_index) - s << keyword << '[' << current_index << "] := " << (vect[current_index-1] ? 1 : 0) << '\n'; + case KeyArgument::BOOL: { + auto vect = *reinterpret_cast*>(element.p_object_variable); + for (unsigned current_index = 1; current_index <= vect.size(); ++current_index) + s << keyword << '[' << current_index << "] := " << (vect[current_index - 1] ? 1 : 0) << '\n'; break; } case KeyArgument::NONE: break; - case KeyArgument::ASCIIlist : - { - auto vect = *reinterpret_cast *>(element.p_object_variable); - for (unsigned current_index=1; current_index <= vect.size(); ++current_index) + case KeyArgument::ASCIIlist: { + auto vect = *reinterpret_cast*>(element.p_object_variable); + for (unsigned current_index = 1; current_index <= vect.size(); ++current_index) { s << keyword << '[' << current_index << "] := "; - const int index = vect[current_index-1]; - s << (index == -1 ? - "UNALLOWED VALUE" : - (*element.p_object_list_of_values)[index]) - << '\n'; + const int index = vect[current_index - 1]; + s << (index == -1 ? "UNALLOWED VALUE" : (*element.p_object_list_of_values)[index]) << '\n'; } break; } - case KeyArgument::PARSINGOBJECT: - { + case KeyArgument::PARSINGOBJECT: { warning("KeyParser::parameter_info(): vectorised keyword type PARSINGOBJECT not yet supported"); break; } - case KeyArgument::SHARED_PARSINGOBJECT: - { + case KeyArgument::SHARED_PARSINGOBJECT: { warning("KeyParser::parameter_info(): vectorised keyword type PARSINGOBJECT not yet supported"); break; } - case KeyArgument::ARRAY2D_OF_FLOATS: - { - auto vect = *reinterpret_cast> *>(element.p_object_variable); - for (unsigned current_index=1; current_index <= vect.size(); ++current_index) + case KeyArgument::ARRAY2D_OF_FLOATS: { + auto vect = *reinterpret_cast>*>(element.p_object_variable); + for (unsigned current_index = 1; current_index <= vect.size(); ++current_index) { s << keyword << '[' << current_index << "] := "; - detail::to_stream(s, vect[current_index-1]); + detail::to_stream(s, vect[current_index - 1]); } } - case KeyArgument::ARRAY3D_OF_FLOATS: - { - auto vect = *reinterpret_cast> *>(element.p_object_variable); - for (unsigned current_index=1; current_index <= vect.size(); ++current_index) + case KeyArgument::ARRAY3D_OF_FLOATS: { + auto vect = *reinterpret_cast>*>(element.p_object_variable); + for (unsigned current_index = 1; current_index <= vect.size(); ++current_index) { s << keyword << '[' << current_index << "] := "; - detail::to_stream(s, vect[current_index-1]); + detail::to_stream(s, vect[current_index - 1]); } } - default : + default: warning("KeyParser error: unknown type. Implementation error\n"); break; } #undef KP_case_to_stream } -string KeyParser::parameter_info() const -{ - std::ostringstream s; +string +KeyParser::parameter_info() const +{ + std::ostringstream s; - // first find start key - for (Keymap::const_iterator i=kmap.begin(); i!= kmap.end(); ++i) - { + // 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"; + s << i->first << " :=\n"; } - 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 || - i->second.p_object_member == &KeyParser::stop_parsing) - continue; + 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) { @@ -1442,55 +1391,55 @@ string KeyParser::parameter_info() const } s << endl; } - // finally, find stop key - for (Keymap::const_iterator i=kmap.begin(); i!= kmap.end(); ++i) - { + // 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"; + s << i->first << " := \n"; } - return s.str(); - } + return s.str(); +} -void KeyParser::ask_parameters() -{ - // This is necessary for set_parsing_object. It will allow the +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) - { - string line; - - for (Keymap::const_iterator i=kmap.begin(); i!= kmap.end(); ++i) + while (true) { - - 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; + string line; - if (i->second.vectorised_key_level > 0) + for (Keymap::const_iterator i = kmap.begin(); i != kmap.end(); ++i) { - warning("KeyParser: cannot handle vectorised key yet");//TODO - continue; - } - keyword = i->first; + 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; - cout << keyword << " := "; - { - read_line(cin, line); - // prepend ":=" such that parse_value_in_line can work properly - line.insert(0, ":= "); - } + if (i->second.vectorised_key_level > 0) + { + warning("KeyParser: cannot handle vectorised key yet"); // TODO + continue; + } + + keyword = i->first; - if (parse_value_in_line(line, false) == Succeeded::yes) - process_key(); + cout << keyword << " := "; + { + 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(); + } + if (post_processing()) + cout << " Asking all questions again! (Sorry)\n"; + else + return; } - if (post_processing()) - cout << " Asking all questions again! (Sorry)\n"; - else - return; - } } END_NAMESPACE_STIR diff --git a/src/buildblock/ML_norm.cxx b/src/buildblock/ML_norm.cxx index fd26331cb..bc8c10910 100644 --- a/src/buildblock/ML_norm.cxx +++ b/src/buildblock/ML_norm.cxx @@ -44,11 +44,11 @@ DetPairData::DetPairData() {} DetPairData::DetPairData(const IndexRange<2>& range) -:base_type(range), num_detectors(range.get_length()) -{ -} + : base_type(range), + num_detectors(range.get_length()) +{} -DetPairData& +DetPairData& DetPairData::operator=(const DetPairData& other) { base_type::operator=(other); @@ -56,271 +56,263 @@ DetPairData::operator=(const DetPairData& other) return *this; } -float & DetPairData::operator()(const int a, const int b) +float& +DetPairData::operator()(const int a, const int b) { - return (*this)[a][b=get_min_index(a)) - return b<=get_max_index(a); + 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; } template -static void make_det_pair_data_help(DetPairData& det_pair_data, +static void +make_det_pair_data_help(DetPairData& det_pair_data, const TProjDataInfo& proj_data_info_general_type, const int segment_num, const int ax_pos_num) { - const int num_detectors = - proj_data_info_general_type.get_scanner_ptr()->get_num_detectors_per_ring(); - const int fan_size = - 2*max(proj_data_info_general_type.get_max_tangential_pos_num(), - -proj_data_info_general_type.get_min_tangential_pos_num()) + 1; + const int num_detectors = proj_data_info_general_type.get_scanner_ptr()->get_num_detectors_per_ring(); + const int fan_size = 2 + * max(proj_data_info_general_type.get_max_tangential_pos_num(), + -proj_data_info_general_type.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); + 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[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 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) { - if (proj_data_info_general_type.get_scanner_ptr()->get_scanner_geometry()=="Cylindrical") + if (proj_data_info_general_type.get_scanner_ptr()->get_scanner_geometry() == "Cylindrical") { - auto proj_data_info = - dynamic_cast(proj_data_info_general_type); + auto proj_data_info = dynamic_cast(proj_data_info_general_type); - make_det_pair_data_help(det_pair_data, proj_data_info, segment_num, ax_pos_num); + make_det_pair_data_help(det_pair_data, proj_data_info, segment_num, ax_pos_num); } - else + else { - auto proj_data_info = - dynamic_cast(proj_data_info_general_type); + auto proj_data_info = dynamic_cast(proj_data_info_general_type); - make_det_pair_data_help(det_pair_data, proj_data_info, segment_num, ax_pos_num); + make_det_pair_data_help(det_pair_data, proj_data_info, segment_num, ax_pos_num); } - } template -static void make_det_pair_data_help(DetPairData& det_pair_data, +static void +make_det_pair_data_help(DetPairData& det_pair_data, const TProjDataInfo& proj_data_info, 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(); + 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(); - 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))); - + 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) + 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; 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]; + 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 make_det_pair_data(DetPairData& det_pair_data, - const ProjData& proj_data, - const int segment_num, - const int ax_pos_num) +void +make_det_pair_data(DetPairData& det_pair_data, const ProjData& proj_data, const int segment_num, const int ax_pos_num) { - if (proj_data.get_proj_data_info_sptr()->get_scanner_ptr()->get_scanner_geometry()=="Cylindrical") + if (proj_data.get_proj_data_info_sptr()->get_scanner_ptr()->get_scanner_geometry() == "Cylindrical") { - auto proj_data_info = - dynamic_cast(*proj_data.get_proj_data_info_sptr()); + auto proj_data_info = dynamic_cast(*proj_data.get_proj_data_info_sptr()); - make_det_pair_data_help(det_pair_data, proj_data_info, proj_data, segment_num, ax_pos_num); + make_det_pair_data_help(det_pair_data, proj_data_info, proj_data, segment_num, ax_pos_num); } - else + else { - auto proj_data_info = - dynamic_cast(*proj_data.get_proj_data_info_sptr()); + auto proj_data_info = dynamic_cast(*proj_data.get_proj_data_info_sptr()); - make_det_pair_data_help(det_pair_data, proj_data_info, proj_data, segment_num, ax_pos_num); + make_det_pair_data_help(det_pair_data, proj_data_info, proj_data, segment_num, ax_pos_num); } } - -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) + 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; + // 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]; + 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]; + 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) + 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 (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 + 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]; + 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]; + 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) + 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 (det_pair_data(a, b) == 0) + continue; if (apply) - det_pair_data(a,b) *= - efficiencies[a]*efficiencies[b%num_detectors]; + det_pair_data(a, b) *= efficiencies[a] * efficiencies[b % num_detectors]; else - det_pair_data(a,b) /= - efficiencies[a]*efficiencies[b%num_detectors]; + 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); @@ -329,126 +321,118 @@ 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 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; + 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; - } + { + // 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) + 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; + 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) + 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; + 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 +KL(const DetPairData& d1, const DetPairData& d2, const double threshold) { - double sum=0; + 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); + 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() {} @@ -456,47 +440,49 @@ 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) - - 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) + // 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) + 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 + // 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; + 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) @@ -506,7 +492,8 @@ GeoData3D::operator=(const GeoData3D& other) return ra=0); - assert(b>=0); - return + assert(a >= 0); + assert(b >= 0); + return - (*this)[ra][a%num_detectors_per_ring][rb][b=0); - assert(b>=0); - return + 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); + 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); } -void GeoData3D::fill(const float d) +void +GeoData3D::fill(const float d) { - base_type::fill(d); + base_type::fill(d); } - -int GeoData3D::get_min_ra() const +int +GeoData3D::get_min_ra() const { - return base_type::get_min_index(); + return base_type::get_min_index(); } -int GeoData3D::get_max_ra() const +int +GeoData3D::get_max_ra() const { - return base_type::get_max_index(); + return base_type::get_max_index(); } - -int GeoData3D::get_min_a() const +int +GeoData3D::get_min_a() const { - return (*this)[get_min_index()].get_min_index(); + return (*this)[get_min_index()].get_min_index(); } -int GeoData3D::get_max_a() const +int +GeoData3D::get_max_a() const { - return (*this)[get_min_index()].get_max_index(); + return (*this)[get_min_index()].get_max_index(); } - -int GeoData3D::get_min_rb(const int ra) const +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(); + 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_rb(const int ra) const +int +GeoData3D::get_max_rb(const int ra) const { - return (*this)[ra][(*this)[ra].get_min_index()].get_max_index(); + return (*this)[ra][(*this)[ra].get_min_index()].get_max_index(); } -int GeoData3D::get_min_b(const int a) const +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(); + return (*this)[get_min_index()][a][(*this)[get_min_index()][a].get_min_index()].get_min_index(); } -int GeoData3D::get_max_b(const int a) const +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(); + return (*this)[get_min_index()][a][(*this)[get_min_index()][a].get_min_index()].get_max_index(); } - -float GeoData3D::sum() const +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; + // 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::sum(const int ra, const int a) const +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; + // 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_max() const +float +GeoData3D::find_max() const { - return base_type::find_max(); + return base_type::find_max(); } -float GeoData3D::find_min() const +float +GeoData3D::find_min() const { - return base_type::find_min(); + return base_type::find_min(); } -int GeoData3D::get_num_axial_crystals_per_block() const +int +GeoData3D::get_num_axial_crystals_per_block() const { - return num_axial_crystals_per_block; + return num_axial_crystals_per_block; } -int GeoData3D::get_half_num_transaxial_crystals_per_block() const +int +GeoData3D::get_half_num_transaxial_crystals_per_block() const { - return half_num_transaxial_crystals_per_block; + return half_num_transaxial_crystals_per_block; } - -std::ostream& operator<<(std::ostream& s, const GeoData3D& geo_data) +std::ostream& +operator<<(std::ostream& s, const GeoData3D& geo_data) { - return s << static_cast(geo_data); + return s << static_cast(geo_data); } -std::istream& operator>>(std::istream& s, GeoData3D& 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; - - + 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) - + 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) + 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) + 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); + 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) + 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) + 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); + 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); + geo_data[ra][a][rb].set_offset(a); } } } - - return s; -} + return s; +} //////////////////////////////////////////////////// - - - FanProjData::FanProjData() - : num_rings(0), num_detectors_per_ring(0), max_ring_diff(0), half_fan_size(0) + : num_rings(0), + num_detectors_per_ring(0), + max_ring_diff(0), + half_fan_size(0) {} FanProjData::~FanProjData() @@ -721,37 +720,37 @@ 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) +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); + 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); + 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); + } } - } grow(fan_indices); fill(0); } -FanProjData& +FanProjData& FanProjData::operator=(const FanProjData& other) { base_type::operator=(other); @@ -762,41 +761,41 @@ FanProjData::operator=(const FanProjData& other) return *this; } -float & FanProjData::operator()(const int ra, const int a, const int rb, const int b) +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 +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()) + 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); } @@ -810,514 +809,499 @@ 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_max_delta() const +int +FanProjData::get_max_delta() const { return max_ring_diff; } -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 +int +FanProjData::get_min_rb(const int ra) const { - return max(ra-max_ring_diff, 0); + 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 +float +FanProjData::sum() const { - //return base_type::sum(); + // 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 +float +FanProjData::sum(const int ra, const int a) const { - //return (*this)[ra][a].sum(); + // 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) - // 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; + + // 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; 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) - { - 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); - } - 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) + 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) { - 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); + 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); + } + 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); + } + 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); - } } - } return s; } void -get_fan_info(int& num_rings, int& num_detectors_per_ring, - int& max_ring_diff, int& fan_size, - const ProjDataInfo& proj_data_info) +get_fan_info(int& num_rings, int& num_detectors_per_ring, int& max_ring_diff, int& fan_size, const ProjDataInfo& proj_data_info) { - auto proj_data_info_ptr = - dynamic_cast(&proj_data_info); + auto proj_data_info_ptr = dynamic_cast(&proj_data_info); - if (proj_data_info_ptr == 0) + 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; - max_ring_diff = proj_data_info.get_max_segment_num(); - + 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.get_max_segment_num(); } template -static void set_det_pair_data_help(ProjData& proj_data, - const TProjDataInfo proj_data_info, - const DetPairData& det_pair_data, - const int segment_num, - const int ax_pos_num) +static void +set_det_pair_data_help(ProjData& proj_data, + const TProjDataInfo proj_data_info, + const DetPairData& det_pair_data, + const int segment_num, + const int ax_pos_num) { 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))); + 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) + 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; + int det_num_a = 0; + int det_num_b = 0; - proj_data_info.get_det_num_pair_for_view_tangential_pos_num(det_num_a, det_num_b, 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); - (*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); + (*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 set_det_pair_data(ProjData& proj_data, - const DetPairData& det_pair_data, - const int segment_num, - const int ax_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(); + const shared_ptr proj_data_info_sptr = proj_data.get_proj_data_info_sptr(); - if (proj_data.get_proj_data_info_sptr()->get_scanner_ptr()->get_scanner_geometry()=="Cylindrical") + if (proj_data.get_proj_data_info_sptr()->get_scanner_ptr()->get_scanner_geometry() == "Cylindrical") { - auto proj_data_info = - dynamic_cast(*proj_data_info_sptr); + auto proj_data_info = dynamic_cast(*proj_data_info_sptr); - set_det_pair_data_help(proj_data, proj_data_info, det_pair_data, segment_num, ax_pos_num); + set_det_pair_data_help(proj_data, proj_data_info, det_pair_data, segment_num, ax_pos_num); } - else - { - auto proj_data_info = - dynamic_cast(*proj_data_info_sptr); + else + { + auto proj_data_info = dynamic_cast(*proj_data_info_sptr); - set_det_pair_data_help(proj_data, proj_data_info, det_pair_data, segment_num, ax_pos_num); - } + set_det_pair_data_help( + proj_data, proj_data_info, det_pair_data, segment_num, ax_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 *** /// template -static void make_fan_data_remove_gaps_help(FanProjData& fan_data, - int num_rings, - int num_detectors_per_ring, - int max_delta, - int fan_size, - const TProjDataInfo& proj_data_info, - const ProjData& proj_data) -{ - if(proj_data.get_proj_data_info_sptr()->is_tof_data()) - error("make_fan_data: Incompatible with TOF data. Abort."); - - const int half_fan_size = fan_size/2; - const int num_virtual_axial_crystals_per_block = - proj_data_info.get_scanner_sptr()-> - get_num_virtual_axial_crystals_per_block(); - - const int num_virtual_transaxial_crystals_per_block = - proj_data_info.get_scanner_sptr()-> - get_num_virtual_transaxial_crystals_per_block(); - - const int num_transaxial_blocks = - proj_data_info.get_scanner_sptr()-> - get_num_transaxial_blocks(); - const int num_axial_blocks = - proj_data_info.get_scanner_sptr()-> - get_num_axial_blocks(); - const int num_transaxial_crystals_per_block = - proj_data_info.get_scanner_sptr()-> - get_num_transaxial_crystals_per_block(); - const int num_axial_crystals_per_block = - proj_data_info.get_scanner_sptr()-> - get_num_axial_crystals_per_block(); - - const int num_physical_transaxial_crystals_per_block = num_transaxial_crystals_per_block - num_virtual_transaxial_crystals_per_block; - - const int num_physical_axial_crystals_per_block = num_axial_crystals_per_block - num_virtual_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*num_virtual_transaxial_crystals_per_block; - 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)*num_virtual_axial_crystals_per_block; - const int num_physical_detectors_per_ring = num_detectors_per_ring - num_transaxial_blocks*num_virtual_transaxial_crystals_per_block; - const int num_physical_rings = num_rings - (num_axial_blocks-1)*num_virtual_axial_crystals_per_block; - fan_data = FanProjData(num_physical_rings, num_physical_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()) +static void +make_fan_data_remove_gaps_help(FanProjData& fan_data, + int num_rings, + int num_detectors_per_ring, + int max_delta, + int fan_size, + const TProjDataInfo& proj_data_info, + const ProjData& proj_data) +{ + if (proj_data.get_proj_data_info_sptr()->is_tof_data()) + error("make_fan_data: Incompatible with TOF data. Abort."); + + const int half_fan_size = fan_size / 2; + const int num_virtual_axial_crystals_per_block = proj_data_info.get_scanner_sptr()->get_num_virtual_axial_crystals_per_block(); + + const int num_virtual_transaxial_crystals_per_block + = proj_data_info.get_scanner_sptr()->get_num_virtual_transaxial_crystals_per_block(); + + const int num_transaxial_blocks = proj_data_info.get_scanner_sptr()->get_num_transaxial_blocks(); + const int num_axial_blocks = proj_data_info.get_scanner_sptr()->get_num_axial_blocks(); + const int num_transaxial_crystals_per_block = proj_data_info.get_scanner_sptr()->get_num_transaxial_crystals_per_block(); + const int num_axial_crystals_per_block = proj_data_info.get_scanner_sptr()->get_num_axial_crystals_per_block(); + + const int num_physical_transaxial_crystals_per_block + = num_transaxial_crystals_per_block - num_virtual_transaxial_crystals_per_block; + + const int num_physical_axial_crystals_per_block = num_axial_crystals_per_block - num_virtual_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 * num_virtual_transaxial_crystals_per_block; + 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)*num_virtual_axial_crystals_per_block; + const int num_physical_detectors_per_ring + = num_detectors_per_ring - num_transaxial_blocks * num_virtual_transaxial_crystals_per_block; + const int num_physical_rings = num_rings - (num_axial_blocks - 1) * num_virtual_axial_crystals_per_block; + fan_data = FanProjData(num_physical_rings, num_physical_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()))); + 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.get_det_pair_for_bin(a, ra, b, rb, bin); - int a_in_block = a % num_transaxial_crystals_per_block; - - if (a_in_block >= num_physical_transaxial_crystals_per_block) - continue; - int new_a = a - (a / num_transaxial_crystals_per_block) * num_virtual_transaxial_crystals_per_block; - - int ra_in_block = ra % num_axial_crystals_per_block; - if (ra_in_block >= num_physical_axial_crystals_per_block) - continue; - int new_ra = ra - (ra / num_axial_crystals_per_block) * num_virtual_axial_crystals_per_block; - - int b_in_block = b % num_transaxial_crystals_per_block; - if (b_in_block >= num_physical_transaxial_crystals_per_block) - continue; - int new_b = b - (b / num_transaxial_crystals_per_block) * num_virtual_transaxial_crystals_per_block; - - int rb_in_block = rb % num_axial_crystals_per_block; - if (rb_in_block >= num_physical_axial_crystals_per_block) - continue; - int new_rb = rb - (rb / num_axial_crystals_per_block) * num_virtual_axial_crystals_per_block; - - 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()]; - } + 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.get_det_pair_for_bin(a, ra, b, rb, bin); + int a_in_block = a % num_transaxial_crystals_per_block; + + if (a_in_block >= num_physical_transaxial_crystals_per_block) + continue; + int new_a = a - (a / num_transaxial_crystals_per_block) * num_virtual_transaxial_crystals_per_block; + + int ra_in_block = ra % num_axial_crystals_per_block; + if (ra_in_block >= num_physical_axial_crystals_per_block) + continue; + int new_ra = ra - (ra / num_axial_crystals_per_block) * num_virtual_axial_crystals_per_block; + + int b_in_block = b % num_transaxial_crystals_per_block; + if (b_in_block >= num_physical_transaxial_crystals_per_block) + continue; + int new_b = b - (b / num_transaxial_crystals_per_block) * num_virtual_transaxial_crystals_per_block; + + int rb_in_block = rb % num_axial_crystals_per_block; + if (rb_in_block >= num_physical_axial_crystals_per_block) + continue; + int new_rb = rb - (rb / num_axial_crystals_per_block) * num_virtual_axial_crystals_per_block; + + 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) +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; + 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."); + if (proj_data.get_proj_data_info_sptr()->is_tof_data()) + error("make_fan_data: Incompatible with TOF data. Abort."); - const ProjDataInfo& proj_data_info =*proj_data.get_proj_data_info_sptr(); - get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, proj_data_info); + const ProjDataInfo& proj_data_info = *proj_data.get_proj_data_info_sptr(); + get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, proj_data_info); - if (proj_data.get_proj_data_info_sptr()->get_scanner_ptr()->get_scanner_geometry()=="Cylindrical") + if (proj_data.get_proj_data_info_sptr()->get_scanner_ptr()->get_scanner_geometry() == "Cylindrical") { - auto proj_data_info_ptr = - dynamic_cast(&proj_data_info); + auto proj_data_info_ptr = dynamic_cast(&proj_data_info); - make_fan_data_remove_gaps_help(fan_data, num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data_info_ptr, proj_data); + make_fan_data_remove_gaps_help( + fan_data, num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data_info_ptr, proj_data); } - else + else { - auto proj_data_info_ptr = - dynamic_cast(&proj_data_info); + auto proj_data_info_ptr = dynamic_cast(&proj_data_info); - make_fan_data_remove_gaps_help(fan_data, num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data_info_ptr, proj_data); + make_fan_data_remove_gaps_help( + fan_data, num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data_info_ptr, proj_data); } } /// **** This function make proj_data from fan_data while adding the intermodule gaps **** //// /// *** fan_data doesn't have gaps, proj_data has gaps *** /// template -static void set_fan_data_add_gaps_help(ProjData& proj_data, - int num_rings, - int num_detectors_per_ring, - int max_delta, - int fan_size, - const TProjDataInfo& proj_data_info, - const FanProjData& fan_data, - const float gap_value=0.F) -{ - const int half_fan_size = fan_size/2; - - - const int num_virtual_axial_crystals_per_block = - proj_data_info.get_scanner_sptr()-> - get_num_virtual_axial_crystals_per_block(); - const int num_virtual_transaxial_crystals_per_block = - proj_data_info.get_scanner_sptr()-> - get_num_virtual_transaxial_crystals_per_block(); - const int num_transaxial_crystals_per_block = - proj_data_info.get_scanner_sptr()-> - get_num_transaxial_crystals_per_block(); - const int num_axial_crystals_per_block = - proj_data_info.get_scanner_sptr()-> - get_num_axial_crystals_per_block(); - - const int num_physical_transaxial_crystals_per_block = num_transaxial_crystals_per_block - num_virtual_transaxial_crystals_per_block; - - const int num_physical_axial_crystals_per_block = num_axial_crystals_per_block - num_virtual_axial_crystals_per_block; +static void +set_fan_data_add_gaps_help(ProjData& proj_data, + int num_rings, + int num_detectors_per_ring, + int max_delta, + int fan_size, + const TProjDataInfo& proj_data_info, + const FanProjData& fan_data, + const float gap_value = 0.F) +{ + const int half_fan_size = fan_size / 2; + + const int num_virtual_axial_crystals_per_block = proj_data_info.get_scanner_sptr()->get_num_virtual_axial_crystals_per_block(); + const int num_virtual_transaxial_crystals_per_block + = proj_data_info.get_scanner_sptr()->get_num_virtual_transaxial_crystals_per_block(); + const int num_transaxial_crystals_per_block = proj_data_info.get_scanner_sptr()->get_num_transaxial_crystals_per_block(); + const int num_axial_crystals_per_block = proj_data_info.get_scanner_sptr()->get_num_axial_crystals_per_block(); + + const int num_physical_transaxial_crystals_per_block + = num_transaxial_crystals_per_block - num_virtual_transaxial_crystals_per_block; + + const int num_physical_axial_crystals_per_block = num_axial_crystals_per_block - num_virtual_axial_crystals_per_block; #ifdef STIR_OPENMP - #pragma omp parallel for schedule(dynamic) +# pragma omp parallel for schedule(dynamic) #endif - for (int segment = proj_data.get_min_segment_num(); segment <= proj_data.get_max_segment_num(); ++segment) + for (int segment = proj_data.get_min_segment_num(); segment <= proj_data.get_max_segment_num(); ++segment) { - Bin bin; - shared_ptr > segment_ptr; - bin.segment_num() = segment; - - segment_ptr.reset(new SegmentBySinogram(proj_data.get_empty_segment_by_sinogram(bin.segment_num()))); + Bin bin; + shared_ptr> segment_ptr; + bin.segment_num() = segment; - 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; + segment_ptr.reset(new SegmentBySinogram(proj_data.get_empty_segment_by_sinogram(bin.segment_num()))); - proj_data_info.get_det_pair_for_bin(a, ra, b, rb, bin); + 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; - (*segment_ptr)[bin.axial_pos_num()][bin.view_num()][bin.tangential_pos_num()] = gap_value; + proj_data_info.get_det_pair_for_bin(a, ra, b, rb, bin); + (*segment_ptr)[bin.axial_pos_num()][bin.view_num()][bin.tangential_pos_num()] = gap_value; - proj_data_info.get_det_pair_for_bin(a, ra, b, rb, bin); - int a_in_block = a % num_transaxial_crystals_per_block; + proj_data_info.get_det_pair_for_bin(a, ra, b, rb, bin); + int a_in_block = a % num_transaxial_crystals_per_block; - if (a_in_block >= num_physical_transaxial_crystals_per_block) - continue; - int new_a = a - (a / num_transaxial_crystals_per_block) * num_virtual_transaxial_crystals_per_block; + if (a_in_block >= num_physical_transaxial_crystals_per_block) + continue; + int new_a = a - (a / num_transaxial_crystals_per_block) * num_virtual_transaxial_crystals_per_block; - int ra_in_block = ra % num_axial_crystals_per_block; - if (ra_in_block >= num_physical_axial_crystals_per_block) - continue; - int new_ra = ra - (ra / num_axial_crystals_per_block) * num_virtual_axial_crystals_per_block; + int ra_in_block = ra % num_axial_crystals_per_block; + if (ra_in_block >= num_physical_axial_crystals_per_block) + continue; + int new_ra = ra - (ra / num_axial_crystals_per_block) * num_virtual_axial_crystals_per_block; - int b_in_block = b % num_transaxial_crystals_per_block; - if (b_in_block >= num_physical_transaxial_crystals_per_block) - continue; - int new_b = b - (b / num_transaxial_crystals_per_block) * num_virtual_transaxial_crystals_per_block; + int b_in_block = b % num_transaxial_crystals_per_block; + if (b_in_block >= num_physical_transaxial_crystals_per_block) + continue; + int new_b = b - (b / num_transaxial_crystals_per_block) * num_virtual_transaxial_crystals_per_block; - int rb_in_block = rb % num_axial_crystals_per_block; - if (rb_in_block >= num_physical_axial_crystals_per_block) - continue; - int new_rb = rb - (rb / num_axial_crystals_per_block) * num_virtual_axial_crystals_per_block; + int rb_in_block = rb % num_axial_crystals_per_block; + if (rb_in_block >= num_physical_axial_crystals_per_block) + continue; + int new_rb = rb - (rb / num_axial_crystals_per_block) * num_virtual_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); + (*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, - const float gap_value) +void +set_fan_data_add_gaps(ProjData& proj_data, const FanProjData& fan_data, const float gap_value) { - int num_rings; - int num_detectors_per_ring; - int fan_size; - int max_delta; - get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, - *proj_data.get_proj_data_info_sptr()); + int num_rings; + int num_detectors_per_ring; + int fan_size; + int max_delta; + get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data.get_proj_data_info_sptr()); - if (proj_data.get_proj_data_info_sptr()->get_scanner_ptr()->get_scanner_geometry()=="Cylindrical") + if (proj_data.get_proj_data_info_sptr()->get_scanner_ptr()->get_scanner_geometry() == "Cylindrical") { - auto proj_data_info_ptr = - dynamic_cast(&(*proj_data.get_proj_data_info_sptr())); + auto proj_data_info_ptr + = dynamic_cast(&(*proj_data.get_proj_data_info_sptr())); - set_fan_data_add_gaps_help(proj_data, num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data_info_ptr, fan_data, gap_value); + set_fan_data_add_gaps_help( + proj_data, num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data_info_ptr, fan_data, gap_value); } - else + else { - auto proj_data_info_ptr = - dynamic_cast(&(*proj_data.get_proj_data_info_sptr())); + auto proj_data_info_ptr + = dynamic_cast(&(*proj_data.get_proj_data_info_sptr())); - set_fan_data_add_gaps_help(proj_data, num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data_info_ptr, fan_data, gap_value); + set_fan_data_add_gaps_help( + proj_data, num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data_info_ptr, fan_data, gap_value); } } -void apply_block_norm(FanProjData& fan_data, const BlockData3D& block_data, const bool apply) +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 @@ -1350,311 +1334,300 @@ 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); } template -static void make_fan_sum_data_help(Array<2,float>& data_fan_sums, - int num_rings, int num_detectors_per_ring, - int max_ring_diff, int fan_size, - const TProjDataInfo& proj_data_info, - const ProjData& proj_data) -{ - if(proj_data.get_proj_data_info_sptr()->is_tof_data()) - error("make_fan_data: Incompatible with TOF data. Abort."); - - const int half_fan_size = fan_size/2; +static void +make_fan_sum_data_help(Array<2, float>& data_fan_sums, + int num_rings, + int num_detectors_per_ring, + int max_ring_diff, + int fan_size, + const TProjDataInfo& proj_data_info, + const ProjData& proj_data) +{ + if (proj_data.get_proj_data_info_sptr()->is_tof_data()) + error("make_fan_data: Incompatible with TOF data. Abort."); + + 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()) - { - // 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()) + 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()/*,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.get_det_pair_for_bin(a, ra, b, rb, bin); + // 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()*/))); - 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; - } + 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.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; + } + } } - } } -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; - get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, - *proj_data.get_proj_data_info_sptr()); + int num_rings; + int num_detectors_per_ring; + int fan_size; + int max_delta; + get_fan_info(num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data.get_proj_data_info_sptr()); - if(proj_data.get_proj_data_info_sptr()->get_scanner_sptr()->get_scanner_geometry()=="Cylindrical") + if (proj_data.get_proj_data_info_sptr()->get_scanner_sptr()->get_scanner_geometry() == "Cylindrical") { - auto proj_data_info_ptr = - dynamic_cast(&(*proj_data.get_proj_data_info_sptr())); - make_fan_sum_data_help(data_fan_sums, num_rings, num_detectors_per_ring, - max_delta, fan_size, *proj_data_info_ptr, proj_data); + auto proj_data_info_ptr + = dynamic_cast(&(*proj_data.get_proj_data_info_sptr())); + make_fan_sum_data_help( + data_fan_sums, num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data_info_ptr, proj_data); } - else + else { - auto proj_data_info_ptr = - dynamic_cast(&(*proj_data.get_proj_data_info_sptr())); - make_fan_sum_data_help(data_fan_sums, num_rings, num_detectors_per_ring, - max_delta, fan_size, *proj_data_info_ptr, proj_data); + auto proj_data_info_ptr + = dynamic_cast(&(*proj_data.get_proj_data_info_sptr())); + make_fan_sum_data_help( + data_fan_sums, num_rings, num_detectors_per_ring, max_delta, fan_size, *proj_data_info_ptr, proj_data); } } -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; + 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()); @@ -1663,24 +1636,26 @@ void iterate_efficiencies(DetectorEfficiencies& efficiencies, 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) - { - 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; - } - } + { + 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; + } + } } // 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(); @@ -1689,100 +1664,99 @@ void iterate_efficiencies(DetectorEfficiencies& efficiencies, #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) - { - 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; - } -#ifdef WRITE_ALL + { + if (data_fan_sums[ra][a] == 0) + efficiencies[ra][a] = 0; + else { - 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); - } + 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); + } + } #endif - } + } } -void iterate_geo_norm(GeoData3D& norm_geo_data, - const GeoData3D& measured_geo_data, - const FanProjData& model) +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; - } + 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 +KL(const FanProjData& d1, const FanProjData& d2, const double threshold) { - double sum=0; + double sum = 0; for (int ra = d1.get_min_ra(); ra <= d1.get_max_ra(); ++ra) { - double asum=0; + 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 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)); + 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; @@ -1800,19 +1774,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; } @@ -1824,5 +1798,4 @@ double KL(const FanProjData& d1, const FanProjData& d2, const double threshold) } */ - END_NAMESPACE_STIR diff --git a/src/buildblock/MaximalArrayFilter3D.cxx b/src/buildblock/MaximalArrayFilter3D.cxx index a54f83199..93b0f6e1e 100644 --- a/src/buildblock/MaximalArrayFilter3D.cxx +++ b/src/buildblock/MaximalArrayFilter3D.cxx @@ -2,9 +2,9 @@ Copyright (C) 2006 - 2007, Hammersmith Imanet Ltd Copyright (C) 2010 - 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details */ /*! @@ -41,61 +41,58 @@ 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) +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]; - } - } + 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); + 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); - } + 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 +MaximalArrayFilter3D::is_trivial() const { - if (mask_radius_x!=1 &&mask_radius_y !=1 &&mask_radius_z!=1) + 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 4ad7c9d62..a1fbf762e 100644 --- a/src/buildblock/MaximalImageFilter3D.cxx +++ b/src/buildblock/MaximalImageFilter3D.cxx @@ -2,16 +2,16 @@ Copyright (C) 2006 - 2007, Hammersmith Imanet Ltd Copyright (C) 2010 - 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details */ /*! \file \ingroup ImageProcessor \brief Implementations for class stir::MaximalImageFilter3D - + \author Charalampos Tsoumpas \author Kris Thielemans @@ -21,11 +21,10 @@ #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(); @@ -33,20 +32,18 @@ MaximalImageFilter3D:: MaximalImageFilter3D(const CartesianCoordinate3D -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; } @@ -55,16 +52,17 @@ template void MaximalImageFilter3D::virtual_apply(DiscretisedDensity<3, elemT>& density) const { - //assert(consistency_check(density) == Succeeded::yes); - maximal_filter(density); + // 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 +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); + // assert(consistency_check(in_density) == Succeeded::yes); + maximal_filter(out_density, in_density); } template @@ -79,7 +77,7 @@ MaximalImageFilter3D::set_defaults() } template -void +void MaximalImageFilter3D::initialise_keymap() { base_type::initialise_keymap(); @@ -91,16 +89,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 ada27d77c..166bc7f60 100644 --- a/src/buildblock/MedianArrayFilter3D.cxx +++ b/src/buildblock/MedianArrayFilter3D.cxx @@ -20,7 +20,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 */ @@ -33,7 +33,6 @@ using std::nth_element; START_NAMESPACE_STIR - template MedianArrayFilter3D::MedianArrayFilter3D(const Coordinate3D& mask_radius) { @@ -41,12 +40,12 @@ MedianArrayFilter3D::MedianArrayFilter3D(const Coordinate3D& mask_ra 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 @@ -57,78 +56,70 @@ MedianArrayFilter3D::MedianArrayFilter3D() 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) +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]; - } - } + 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 +MedianArrayFilter3D::is_trivial() const { - if (mask_radius_x!=1 &&mask_radius_y !=1 &&mask_radius_z!=1) + 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 96913b1f0..a7aa54350 100644 --- a/src/buildblock/MedianImageFilter3D.cxx +++ b/src/buildblock/MedianImageFilter3D.cxx @@ -22,11 +22,10 @@ #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(); @@ -34,39 +33,38 @@ MedianImageFilter3D:: MedianImageFilter3D(const CartesianCoordinate3D -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); + // 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 +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); + // assert(consistency_check(in_density) == Succeeded::yes); + median_filter(out_density, in_density); } template @@ -81,7 +79,7 @@ MedianImageFilter3D::set_defaults() } template -void +void MedianImageFilter3D::initialise_keymap() { base_type::initialise_keymap(); @@ -93,20 +91,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 4a987fff1..7d9335f67 100644 --- a/src/buildblock/MinimalArrayFilter3D.cxx +++ b/src/buildblock/MinimalArrayFilter3D.cxx @@ -42,65 +42,61 @@ 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) +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]; - } - } + 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); + 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); - } + 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 +MinimalArrayFilter3D::is_trivial() const { - if (mask_radius_x!=1 &&mask_radius_y !=1 &&mask_radius_z!=1) + 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 2f32c0d83..ad999b942 100644 --- a/src/buildblock/MinimalImageFilter3D.cxx +++ b/src/buildblock/MinimalImageFilter3D.cxx @@ -22,11 +22,10 @@ #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(); @@ -34,39 +33,38 @@ MinimalImageFilter3D:: MinimalImageFilter3D(const CartesianCoordinate3D -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); + // 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 +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); + // assert(consistency_check(in_density) == Succeeded::yes); + minimal_filter(out_density, in_density); } template @@ -81,7 +79,7 @@ MinimalImageFilter3D::set_defaults() } template -void +void MinimalImageFilter3D::initialise_keymap() { base_type::initialise_keymap(); @@ -93,16 +91,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 008164b55..bf46624f7 100644 --- a/src/buildblock/MultipleDataSetHeader.cxx +++ b/src/buildblock/MultipleDataSetHeader.cxx @@ -14,7 +14,7 @@ \ingroup data_buildblock \brief Implementation of class stir::MultipleDataSetHeader \author Richard Brown - + */ #include "stir/MultipleDataSetHeader.h" @@ -23,54 +23,54 @@ START_NAMESPACE_STIR -const char * const MultipleDataSetHeader:: -registered_name = "MultipleDataSetHeader"; +const char* const MultipleDataSetHeader::registered_name = "MultipleDataSetHeader"; -MultipleDataSetHeader:: -MultipleDataSetHeader() +MultipleDataSetHeader::MultipleDataSetHeader() { - this->set_defaults(); - this->initialise_keymap(); + this->set_defaults(); + this->initialise_keymap(); } -void MultipleDataSetHeader:: -set_defaults() +void +MultipleDataSetHeader::set_defaults() { - _num_data_sets = 0; + _num_data_sets = 0; } -void MultipleDataSetHeader:: -initialise_keymap() +void +MultipleDataSetHeader::initialise_keymap() { - this->add_start_key("Multi"); - this->add_stop_key("End"); + 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 +MultipleDataSetHeader::post_processing() { - bool empty_filenames = false; - for (int i=0; i<_num_data_sets; ++i) { - if (_filenames[i].size() == unsigned(0)) { + 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; + empty_filenames = true; } } - return empty_filenames; + return empty_filenames; } -void MultipleDataSetHeader:: -read_num_data_sets() +void +MultipleDataSetHeader::read_num_data_sets() { - set_variable(); - _filenames.resize(_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 38ae7c8d2..abf7e9c4c 100644 --- a/src/buildblock/MultipleProjData.cxx +++ b/src/buildblock/MultipleProjData.cxx @@ -15,7 +15,7 @@ \brief Implementation of class stir::MultipleProjData \author Kris Thielemans \author Richard Brown - + */ #include "stir/MultipleProjData.h" @@ -30,8 +30,7 @@ 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(); @@ -39,57 +38,54 @@ get_proj_data_info_sptr() const 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) +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; -} + 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) +MultipleProjData::MultipleProjData(const shared_ptr& exam_info_sptr, const int num_gates) + : ExamData(exam_info_sptr) { - this->_proj_datas.resize(num_gates); + this->_proj_datas.resize(num_gates); } unique_ptr -MultipleProjData:: -read_from_file(const std::string ¶meter_file) +MultipleProjData::read_from_file(const std::string& parameter_file) { - MultipleDataSetHeader header; + MultipleDataSetHeader header; - if (header.parse(parameter_file.c_str()) == false) - error(boost::format("MultipleProjData::read_from_file: Error parsing %1%") % parameter_file); + 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(); + const int num_data_sets = header.get_num_data_sets(); - if (num_data_sets == 0) - error("MultipleProjData::read_from_file: no data sets provided"); + 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 ); + // 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))); + // 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(); + // 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)); + // 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; + 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 dae6310b2..8d5746e69 100644 --- a/src/buildblock/NonseparableConvolutionUsingRealDFTImageFilter.cxx +++ b/src/buildblock/NonseparableConvolutionUsingRealDFTImageFilter.cxx @@ -12,7 +12,7 @@ \file \ingroup ImageProcessor \brief Implementations for class stir::NonseparableConvolutionUsingRealDFTImageFilter - + \author Sanida Mustafovic \author Kris Thielemans */ @@ -31,130 +31,123 @@ START_NAMESPACE_STIR static const int num_dimensions = 3; template -NonseparableConvolutionUsingRealDFTImageFilter:: -NonseparableConvolutionUsingRealDFTImageFilter() -{ +NonseparableConvolutionUsingRealDFTImageFilter::NonseparableConvolutionUsingRealDFTImageFilter() +{ this->set_defaults(); } template -NonseparableConvolutionUsingRealDFTImageFilter:: -NonseparableConvolutionUsingRealDFTImageFilter( const Array<3,elemT>& filter_coefficients ) +NonseparableConvolutionUsingRealDFTImageFilter::NonseparableConvolutionUsingRealDFTImageFilter( + const Array<3, elemT>& filter_coefficients) { - this->_filter_coefficients = 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) + 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.))))); + 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=""; + 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() +bool +NonseparableConvolutionUsingRealDFTImageFilter::post_processing() { if (this->_kernel_filename.length() == 0) - { warning("You need to specify a kernel file"); return true; } + { + 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; + 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)); + } 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 c71b09251..cb3044ed2 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 @@ -15,7 +15,7 @@ See STIR/LICENSE.txt for details */ -/* +/* History: - first version Kris Thielemans @@ -30,98 +30,97 @@ using std::string; START_NAMESPACE_STIR 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") - { - it_is_signed = true; - it_is_integral = true; - } + { + it_is_signed = true; + it_is_integral = true; + } else if (number_format == "unsigned integer") - { - it_is_signed = false; - it_is_integral = true; - } + { + it_is_signed = false; + it_is_integral = true; + } else if (number_format == "float") - { - it_is_signed = true; - it_is_integral = false; - } - + { + it_is_signed = true; + it_is_integral = false; + } + else if (number_format == "bit") - { - id = BIT; - return; - } + { + id = BIT; + return; + } else - { - // set to some values which are guaranteed to break later on - it_is_signed = false; - it_is_integral = false; - } - + { + // 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++) - { - 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()) - { - id = (Type)t; - return; + 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()) + { + 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) - { - 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; - case UNKNOWN_TYPE: - number_format = "unknown"; break; - } -} - + 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; + case UNKNOWN_TYPE: + 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(); + 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); @@ -135,25 +134,29 @@ size_t NumericType::size_in_bytes() const CASE(NumericType::FLOAT); CASE(NumericType::DOUBLE); #undef CASE - case UNKNOWN_TYPE: - return 0; - } - // we never get here, but VC++ wants a return nevertheless + 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(); } +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(); +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); @@ -167,22 +170,23 @@ bool NumericType::signed_type() const CASE(NumericType::FLOAT); CASE(NumericType::DOUBLE); #undef CASE - case UNKNOWN_TYPE: - return false; - } - // we never get here, but VC++ wants a return nevertheless + case UNKNOWN_TYPE: 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(); +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); @@ -196,11 +200,10 @@ bool NumericType::integer_type() const CASE(NumericType::FLOAT); CASE(NumericType::DOUBLE); #undef CASE - case UNKNOWN_TYPE: - return false; - - } - // we never get here, but VC++ wants a return nevertheless + 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 1d5bc2c4e..03d6ac4fe 100644 --- a/src/buildblock/ParseDiscretisedDensityParameters.cxx +++ b/src/buildblock/ParseDiscretisedDensityParameters.cxx @@ -1,24 +1,24 @@ /* 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 part of STIR. + SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license - + 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" @@ -27,29 +27,27 @@ START_NAMESPACE_STIR -void -ParseDiscretisedDensityParameters:: -set_defaults() +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; + // 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) +ParseDiscretisedDensityParameters::add_to_keymap(KeyParser& parser) { - //base_type::initialise_keymap(); + // 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()); } @@ -67,8 +65,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, @@ -80,75 +78,91 @@ 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 +ParseDiscretisedDensityParameters::check_values() const { if (zoom_xy <= 0) - { error("zoom should be positive"); } + { + 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)"); } + { + 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 f505d91d8..2f63008de 100644 --- a/src/buildblock/ParsingObject.cxx +++ b/src/buildblock/ParsingObject.cxx @@ -27,84 +27,76 @@ using std::ifstream; START_NAMESPACE_STIR -ParsingObject::ParsingObject() -: - keymap_is_initialised(false) +ParsingObject::ParsingObject() + : keymap_is_initialised(false) {} - - - ParsingObject::ParsingObject(const ParsingObject& par) -: - keymap_is_initialised(false) - {} - + : keymap_is_initialised(false) +{} ParsingObject& -ParsingObject::operator =(const ParsingObject& par) +ParsingObject::operator=(const ParsingObject& par) { - if (&par == this) return *this; + 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(); - keymap_is_initialised = true; - } + { + initialise_keymap(); + keymap_is_initialised = true; + } set_key_values(); if (!parser.parse(in)) - { - warning("Error parsing.\n"); - return false; - } - else if (post_processing()==true) { - warning("Error post processing keyword values.\n"); + warning("Error parsing.\n"); + return false; + } + 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) - { - error("ParsingObject::parse: couldn't open file %s\n", filename); - return false; - } + { + error("ParsingObject::parse: couldn't open file %s\n", filename); + return false; + } return parse(hdr_stream); } @@ -113,37 +105,37 @@ ParsingObject::ask_parameters() { // potentially remove the if() and always call initialise_keymap if (!keymap_is_initialised) - { - initialise_keymap(); - keymap_is_initialised = true; - } + { + initialise_keymap(); + keymap_is_initialised = true; + } // TODO drop next line set_defaults(); set_key_values(); - while(true) - { - parser.ask_parameters(); - - if (post_processing()==true) + while (true) { - warning("\nError post processing keyword values. Doing it all over again...\n"); + parser.ask_parameters(); + + if (post_processing() == true) + { + warning("\nError post processing keyword values. Doing it all over again...\n"); + } + else + return; } - else - return; - } } std::string ParsingObject::parameter_info() -{ +{ if (!keymap_is_initialised) - { - initialise_keymap(); - keymap_is_initialised = true; - } + { + 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 70127e9a4..3d3715db4 100644 --- a/src/buildblock/PatientPosition.cxx +++ b/src/buildblock/PatientPosition.cxx @@ -22,26 +22,44 @@ START_NAMESPACE_STIR PatientPosition::PatientPosition(PatientPosition::PositionValue position) { - switch(position) + switch (position) { case FFP: - orientation=feet_in; rotation=prone; break; + orientation = feet_in; + rotation = prone; + break; case HFP: - orientation=head_in; rotation=prone; break; + orientation = head_in; + rotation = prone; + break; case FFS: - orientation=feet_in; rotation=supine; break; + orientation = feet_in; + rotation = supine; + break; case HFS: - orientation=head_in; rotation=supine; break; + orientation = head_in; + rotation = supine; + break; case FFDR: - orientation=feet_in; rotation=right; break; + orientation = feet_in; + rotation = right; + break; case HFDR: - orientation=head_in; rotation=right; break; + orientation = head_in; + rotation = right; + break; case FFDL: - orientation=feet_in; rotation=left; break; + orientation = feet_in; + rotation = left; + break; case HFDL: - orientation=head_in; rotation=left; break; + orientation = head_in; + rotation = left; + break; case unknown_position: - orientation=unknown_orientation; rotation=unknown_rotation; break; + orientation = unknown_orientation; + rotation = unknown_rotation; + break; } } @@ -49,9 +67,9 @@ PatientPosition::PositionValue PatientPosition::get_position() const { // make use of order of enum's - if (orientation<=feet_in && rotation<=left) + if (orientation <= feet_in && rotation <= left) { - return static_cast(orientation*4 + rotation); + return static_cast(orientation * 4 + rotation); } else { @@ -59,20 +77,27 @@ PatientPosition::get_position() const } } -const char * const -PatientPosition:: -get_position_as_string() const +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 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"; diff --git a/src/buildblock/ProjData.cxx b/src/buildblock/ProjData.cxx index 515b72f9c..438d03f28 100644 --- a/src/buildblock/ProjData.cxx +++ b/src/buildblock/ProjData.cxx @@ -14,7 +14,7 @@ */ /*! \file - \ingroup projdata + \ingroup projdata \brief Implementations for non-inline functions of class stir::ProjData @@ -37,14 +37,13 @@ #include "stir/IO/interfile.h" #include "stir/ProjDataInterfile.h" #include "stir/ProjDataFromStream.h" // needed for converting ProjDataFromStream* to ProjData* -#include "stir/ProjDataInMemory.h" // needed for subsets +#include "stir/ProjDataInMemory.h" // needed for subsets #include "stir/ProjDataInfoSubsetByView.h" #include "stir/Viewgram.h" - #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/ViewgramIndices.h" @@ -62,9 +61,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 @@ -85,10 +84,8 @@ START_NAMESPACE_STIR 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 @@ -96,93 +93,93 @@ read_from_file(const string& filename, const std::size_t comma_pos = filename.find(','); if (comma_pos != std::string::npos) { - actual_filename.resize(comma_pos); + 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(); #ifdef HAVE_LLN_MATRIX // ECAT 7 if (strncmp(signature, "MATRIX", 6) == 0) - { -#ifndef NDEBUG - info("ProjData::read_from_file trying to read " + filename + " as ECAT7", 3); -#endif - USING_NAMESPACE_ECAT; - USING_NAMESPACE_ECAT7; - - if (is_ECAT7_emission_file(actual_filename) || is_ECAT7_attenuation_file(actual_filename)) - { - info("Reading frame 1, gate 1, data 0, bed 0 from file " + actual_filename, 3); - 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 { - if (is_ECAT7_file(actual_filename)) - error("ProjData::read_from_file ECAT7 file " + actual_filename + " is of unsupported file type"); +# ifndef NDEBUG + info("ProjData::read_from_file trying to read " + filename + " as ECAT7", 3); +# endif + USING_NAMESPACE_ECAT; + USING_NAMESPACE_ECAT7; + + if (is_ECAT7_emission_file(actual_filename) || is_ECAT7_attenuation_file(actual_filename)) + { + info("Reading frame 1, gate 1, data 0, bed 0 from file " + actual_filename, 3); + 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 + { + if (is_ECAT7_file(actual_filename)) + error("ProjData::read_from_file ECAT7 file " + actual_filename + " is of unsupported file type"); + } } - } #endif // HAVE_LLN_MATRIX // Interfile if (is_interfile_signature(signature)) - { + { #ifndef NDEBUG - info("ProjData::read_from_file trying to read " + filename + " as Interfile", 3); + info("ProjData::read_from_file trying to read " + filename + " as Interfile", 3); #endif - shared_ptr ptr(read_interfile_PDFS(filename, openmode)); - if (!is_null_ptr(ptr)) - return ptr; - } - + shared_ptr ptr(read_interfile_PDFS(filename, openmode)); + if (!is_null_ptr(ptr)) + return ptr; + } + #ifdef HAVE_HDF5 if (GE::RDF_HDF5::GEHDF5Wrapper::check_GE_signature(actual_filename)) { -#ifndef NDEBUG +# ifndef NDEBUG info("ProjData::read_from_file trying to read " + filename + " as GE HDF5", 3); -#endif +# endif shared_ptr ptr(new GE::RDF_HDF5::ProjDataGEHDF5(filename)); if (!is_null_ptr(ptr)) - return ptr; - } + return ptr; + } #endif // GE HDF5 - error("ProjData::read_from_file could not read projection data " + filename + ".\n" - "Unsupported file format? Aborting."); + error("ProjData::read_from_file could not read projection data " + filename + + ".\n" + "Unsupported file format? Aborting."); // 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)); -//} - +// this->exam_info_sptr.reset(new ExamInfo(new_exam_info)); +// } unique_ptr ProjData::get_subset(const std::vector& views) const { - auto subset_proj_data_info_sptr = - std::make_shared(proj_data_info_sptr, views); + auto subset_proj_data_info_sptr = std::make_shared(proj_data_info_sptr, views); unique_ptr subset_proj_data_uptr(new ProjDataInMemory(exam_info_sptr, subset_proj_data_info_sptr)); 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=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) { - for (int subset_view_num=0; subset_view_num < static_cast(views.size()); ++subset_view_num) + for (int subset_view_num = 0; subset_view_num < static_cast(views.size()); ++subset_view_num) { const auto viewgram = this->get_viewgram(views[subset_view_num], segment_num, false, timing_pos_num); // construct new one with data from viewgram, but appropriate meta-data - const Viewgram subset_viewgram(viewgram, subset_proj_data_info_sptr, subset_view_num, segment_num, timing_pos_num); + const Viewgram subset_viewgram( + viewgram, subset_proj_data_info_sptr, subset_view_num, segment_num, timing_pos_num); if (subset_proj_data_uptr->set_viewgram(subset_viewgram) != Succeeded::yes) error("ProjData::get_subset failed to set a viewgram"); } @@ -191,7 +188,6 @@ ProjData::get_subset(const std::vector& views) const return subset_proj_data_uptr; } - Viewgram ProjData::get_empty_viewgram(const ViewgramIndices& ind) const { @@ -205,41 +201,35 @@ ProjData::get_empty_sinogram(const SinogramIndices& ind) const } 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 +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); + 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 int timing_pos) const +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); + 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 int timing_pos) const +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); -} - + 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 int timing_pos) const +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); + return proj_data_info_sptr->get_empty_segment_by_view(segment_num, make_num_tangential_poss_odd, timing_pos); } SegmentBySinogram @@ -261,39 +251,35 @@ ProjData::get_empty_related_viewgrams(const ViewgramIndices& view_segmnet_num, 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); + return proj_data_info_sptr->get_empty_related_viewgrams( + view_segmnet_num, symmetries_used, make_num_tangential_poss_odd, timing_pos); } - -RelatedViewgrams +RelatedViewgrams ProjData::get_related_viewgrams(const ViewgramIndices& viewgram_indices, const shared_ptr& symmetries_used, const bool make_num_tangential_poss_odd, const int timing_pos) const { vector pairs; - symmetries_used->get_related_view_segment_numbers( - pairs, - viewgram_indices - ); + symmetries_used->get_related_view_segment_numbers(pairs, viewgram_indices); - vector > viewgrams; + vector> viewgrams; viewgrams.reserve(pairs.size()); - for (unsigned int i=0; iget_viewgram(pairs[i])); - } + for (unsigned int i = 0; i < pairs.size(); i++) + { + // TODO optimise to get shared proj_data_info_ptr + // TODOTOF + pairs[i].timing_pos_num() = timing_pos; + viewgrams.push_back(this->get_viewgram(pairs[i])); + } return RelatedViewgrams(viewgrams, symmetries_used); } -//std::vector -//ProjData::get_related_bin_values(const std::vector& r_bins) const +// std::vector +// ProjData::get_related_bin_values(const std::vector& r_bins) const //{ // std::vector values; @@ -308,18 +294,17 @@ ProjData::get_related_viewgrams(const ViewgramIndices& viewgram_indices, // return values; //} - -Succeeded -ProjData::set_related_viewgrams( const RelatedViewgrams& viewgrams) +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) - return Succeeded::no; - ++r_viewgrams_iter; - } + while (r_viewgrams_iter != viewgrams.end()) + { + if (set_viewgram(*r_viewgrams_iter) == Succeeded::no) + return Succeeded::no; + ++r_viewgrams_iter; + } return Succeeded::yes; } @@ -333,102 +318,96 @@ ProjData::set_related_viewgrams( const RelatedViewgrams& viewgrams) } #endif -SegmentBySinogram ProjData::get_segment_by_sinogram(const int segment_num, const int timing_pos) const +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); + 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, timing_pos)); + 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 int timing_pos) const +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); + 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, timing_pos)); + segment.set_viewgram(get_viewgram(view_num, segment_num, false, timing_pos)); return segment; } -Succeeded +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; - } + { + if (set_viewgram(segment.get_viewgram(view_num)) == Succeeded::no) + return Succeeded::no; + } return Succeeded::yes; } -Succeeded +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; - } + { + if (set_viewgram(segment.get_viewgram(view_num)) == Succeeded::no) + return Succeeded::no; + } return Succeeded::yes; } - -void +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"); - } - } + 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 +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) - { - 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"); - } - } + { + 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); out_projdata.fill(*this); // will have thrown if it failed, so return it was ok @@ -436,27 +415,22 @@ write_to_file(const string& output_filename) const } void -ProjData:: -axpby( const float a, const ProjData& x, - const float b, const ProjData& y) +ProjData::axpby(const float a, const ProjData& x, const float b, const ProjData& y) { - xapyb(x,a,y,b); + xapyb(x, a, y, b); } void -ProjData:: -xapyb(const ProjData& x, const float a, - const ProjData& y, const float b) +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()) + 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 s_min = get_min_segment_num(); const int s_max = get_max_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) - for (int s=s_min; s<=s_max; ++s) + for (int s = s_min; s <= s_max; ++s) { auto seg = get_empty_segment_by_sinogram(s, false, timing_pos_num); const auto sx = x.get_segment_by_sinogram(s, timing_pos_num); @@ -468,21 +442,17 @@ xapyb(const ProjData& x, const float a, } void -ProjData:: -xapyb(const ProjData& x, const ProjData& a, - const ProjData& y, const ProjData& b) +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()) + 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 s_min = get_min_segment_num(); const int s_max = get_max_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) - for (int s=s_min; s<=s_max; ++s) + for (int s = s_min; s <= s_max; ++s) { auto seg = get_empty_segment_by_sinogram(s, false, timing_pos_num); const auto sx = x.get_segment_by_sinogram(s, timing_pos_num); @@ -497,26 +467,22 @@ xapyb(const ProjData& x, const ProjData& a, } void -ProjData:: -sapyb(const float a, const ProjData& y, const float b) +ProjData::sapyb(const float a, const ProjData& y, const float b) { - this->xapyb(*this,a,y,b); + this->xapyb(*this, a, y, b); } void -ProjData:: -sapyb(const ProjData& a, const ProjData& y,const ProjData& b) +ProjData::sapyb(const ProjData& a, const ProjData& y, const ProjData& b) { - this->xapyb(*this,a,y,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(); @@ -525,13 +491,13 @@ standard_segment_sequence(const ProjDataInfo& pdi) unsigned idx = 1; int segment_num = 1; while (idx < segment_sequence.size()) - { - if (segment_num<=max_segment_num) - segment_sequence[idx++] = segment_num; - if (-segment_num>=min_segment_num) - segment_sequence[idx++] = -segment_num; - ++segment_num; - } + { + if (segment_num <= max_segment_num) + segment_sequence[idx++] = segment_num; + if (-segment_num >= min_segment_num) + segment_sequence[idx++] = -segment_num; + ++segment_num; + } return segment_sequence; } diff --git a/src/buildblock/ProjDataFromStream.cxx b/src/buildblock/ProjDataFromStream.cxx index e7e546265..bcb47f9c6 100644 --- a/src/buildblock/ProjDataFromStream.cxx +++ b/src/buildblock/ProjDataFromStream.cxx @@ -52,104 +52,100 @@ using std::cerr; using std::endl; using std::vector; - START_NAMESPACE_STIR //--------------------------------------------------------- // constructors //--------------------------------------------------------- ProjDataFromStream::ProjDataFromStream(shared_ptr const& exam_info_sptr, - shared_ptr const& proj_data_info_sptr, - shared_ptr const& s, const streamoff offs, + 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) + : 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(); - + activate_TOF(); } ProjDataFromStream::ProjDataFromStream(shared_ptr const& exam_info_sptr, - shared_ptr const& proj_data_info_sptr, - shared_ptr const& s, const streamoff offs, + 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) + : 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_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 + // 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_sptr->get_min_segment_num(); - segment_num<=proj_data_info_sptr->get_max_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; - } + { + segment_sequence[i] = segment_num; + } if (proj_data_info_sptr->get_num_tof_poss() > 1) activate_TOF(); - } 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) + 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()); + offset_3d_data = static_cast(sum * on_disk_data_type.size_in_bytes()); - // Now, lets initialise a TOF stream - Similarly to segments - if (storage_order == Segment_View_AxialPos_TangPos || storage_order == Timing_Segment_View_AxialPos_TangPos) - storage_order = Timing_Segment_View_AxialPos_TangPos; - else if (storage_order == Segment_AxialPos_View_TangPos || storage_order == Timing_Segment_AxialPos_View_TangPos) - storage_order = Timing_Segment_AxialPos_View_TangPos; - else - error("ProjDataFromStream: unsupported storage_order for TOF data"); + // Now, lets initialise a TOF stream - Similarly to segments + if (storage_order == Segment_View_AxialPos_TangPos || storage_order == Timing_Segment_View_AxialPos_TangPos) + storage_order = Timing_Segment_View_AxialPos_TangPos; + else if (storage_order == Segment_AxialPos_View_TangPos || storage_order == Timing_Segment_AxialPos_View_TangPos) + storage_order = Timing_Segment_AxialPos_View_TangPos; + else + error("ProjDataFromStream: unsupported storage_order for TOF data"); - timing_poss_sequence.resize(proj_data_info_sptr->get_num_tof_poss()); + 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) + 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; + timing_poss_sequence[i] = timing_pos_num; } - } void @@ -158,60 +154,69 @@ ProjDataFromStream::set_timing_poss_sequence_in_stream(const std::vector& s this->timing_poss_sequence = seq; } -namespace detail { - // 2 local functions to avoid cluttering code below - - static void checked_seekg(const std::string& fname, std::istream& s, const std::streamoff offset) - { - s.seekg(offset, ios::beg); - if (!s) - error("ProjDataFromStream::" + fname + " error after seekg to offset " + std::to_string(offset)); - } - - static void checked_seekp(const std::string& fname, std::ostream& s, const std::streamoff offset) - { - s.seekp(offset, ios::beg); - if (!s) - error("ProjDataFromStream::" + fname + " error after seekp to offset " + std::to_string(offset)); - } +namespace detail +{ +// 2 local functions to avoid cluttering code below + +static void +checked_seekg(const std::string& fname, std::istream& s, const std::streamoff offset) +{ + s.seekg(offset, ios::beg); + if (!s) + error("ProjDataFromStream::" + fname + " error after seekg to offset " + std::to_string(offset)); } +static void +checked_seekp(const std::string& fname, std::ostream& s, const std::streamoff offset) +{ + s.seekp(offset, ios::beg); + if (!s) + error("ProjDataFromStream::" + fname + " error after seekp to offset " + std::to_string(offset)); +} +} // namespace detail + Viewgram -ProjDataFromStream::get_viewgram(const int view_num, const int segment_num, - const bool make_num_tangential_poss_odd, const int timing_pos) const +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) - { - error("ProjDataFromStream::get_viewgram: error in stream state before reading\n"); - } + { + error("ProjDataFromStream::get_viewgram: stream ptr is 0\n"); + } + if (!*sino_stream) + { + error("ProjDataFromStream::get_viewgram: error in stream state before reading\n"); + } Viewgram viewgram(proj_data_info_sptr, view_num, segment_num, timing_pos); float scale = float(1); - Succeeded succeeded = Succeeded::yes; + Succeeded succeeded = Succeeded::yes; Bin bin(segment_num, view_num, this->get_min_axial_pos_num(segment_num), this->get_min_tangential_pos_num(), timing_pos); #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif try { if (get_storage_order() == Segment_AxialPos_View_TangPos || get_storage_order() == Timing_Segment_AxialPos_View_TangPos) - { - for (bin.axial_pos_num() = get_min_axial_pos_num(segment_num); bin.axial_pos_num() <= get_max_axial_pos_num(segment_num); bin.axial_pos_num()++) + { + for (bin.axial_pos_num() = get_min_axial_pos_num(segment_num); + bin.axial_pos_num() <= get_max_axial_pos_num(segment_num); + bin.axial_pos_num()++) { detail::checked_seekg("get_viewgram", *sino_stream, get_offset(bin)); - if ((succeeded = read_data(*sino_stream, viewgram[bin.axial_pos_num()], on_disk_data_type, scale, on_disk_byte_order)) + if ((succeeded + = read_data(*sino_stream, viewgram[bin.axial_pos_num()], on_disk_data_type, scale, on_disk_byte_order)) == Succeeded::no) break; - if(scale != 1) + if (scale != 1) break; } - } - else if (get_storage_order() == Segment_View_AxialPos_TangPos || get_storage_order() == Timing_Segment_View_AxialPos_TangPos) + } + else if (get_storage_order() == Segment_View_AxialPos_TangPos + || get_storage_order() == Timing_Segment_View_AxialPos_TangPos) { // read in one go (skipping the extra seek) detail::checked_seekg("get_viewgram", *sino_stream, get_offset(bin)); @@ -228,127 +233,122 @@ ProjDataFromStream::get_viewgram(const int view_num, const int segment_num, succeeded = Succeeded::no; } // end of critical section - if(scale != 1) + if (scale != 1) error("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1"); if (succeeded == Succeeded::no) error("ProjDataFromStream: error reading data (file truncated?)"); viewgram *= scale_factor; - if (make_num_tangential_poss_odd &&(get_num_tangential_poss()%2==0)) + 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), + 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)); + new_max_tangential_pos)); } - return viewgram; + return viewgram; } float ProjDataFromStream::get_bin_value(const Bin& this_bin) const { - if (is_null_ptr(sino_stream)) + if (is_null_ptr(sino_stream)) { - error("ProjDataFromStream::get_bin_value: stream ptr is 0\n"); + error("ProjDataFromStream::get_bin_value: stream ptr is 0\n"); } - if (! *sino_stream) + if (!*sino_stream) { - error("ProjDataFromStream::get_bin_value: error in stream state before reading\n"); + error("ProjDataFromStream::get_bin_value: error in stream state before reading\n"); } - detail::checked_seekg("get_bin_value", *sino_stream, get_offset(this_bin)); + detail::checked_seekg("get_bin_value", *sino_stream, get_offset(this_bin)); - Array< 1, float> value(1); - float scale = float(1); + Array<1, float> value(1); + float scale = float(1); - 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"); + 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) +ProjDataFromStream::set_bin_value(const Bin& this_bin) { - if (is_null_ptr(sino_stream)) + if (is_null_ptr(sino_stream)) { - error("ProjDataFromStream::set_bin_value: stream ptr is 0\n"); + error("ProjDataFromStream::set_bin_value: stream ptr is 0\n"); } - if (! *sino_stream) + if (!*sino_stream) { - error("ProjDataFromStream::set_bin_value: error in stream state before writing"); + error("ProjDataFromStream::set_bin_value: error in stream state before writing"); } - detail::checked_seekp("set_bin_value", *sino_stream, get_offset(this_bin)); - - 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"); + detail::checked_seekp("set_bin_value", *sino_stream, get_offset(this_bin)); + + 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"); } Succeeded 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) - { - warning("ProjDataFromStream::set_viewgram: error in stream state before writing\n"); - return Succeeded::no; - } + { + warning("ProjDataFromStream::set_viewgram: stream ptr is 0\n"); + return Succeeded::no; + } + 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) - { - warning("ProjDataFromStream::set_viewgram: non-float output uses original " - "scale factor %g which might not be appropriate for the current data\n", - 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"); - return Succeeded::no; - } + { + warning("ProjDataFromStream::set_viewgram: non-float output uses original " + "scale factor %g which might not be appropriate for the current data\n", + scale_factor); + } - 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_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"); + return Succeeded::no; + } 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() - ); - - return Succeeded::no; - } + { + 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()); + + return Succeeded::no; + } const int segment_num = v.get_segment_num(); const int view_num = v.get_view_num(); const int timing_pos = v.get_timing_pos_num(); @@ -358,17 +358,18 @@ ProjDataFromStream::set_viewgram(const Viewgram& v) Succeeded succeeded = Succeeded::yes; #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif try { if (get_storage_order() == Segment_AxialPos_View_TangPos || get_storage_order() == Timing_Segment_AxialPos_View_TangPos) { - for (bin.axial_pos_num() = get_min_axial_pos_num(segment_num); bin.axial_pos_num() <= get_max_axial_pos_num(segment_num); bin.axial_pos_num()++) + for (bin.axial_pos_num() = get_min_axial_pos_num(segment_num); + bin.axial_pos_num() <= get_max_axial_pos_num(segment_num); + bin.axial_pos_num()++) { detail::checked_seekp("set_viewgram", *sino_stream, get_offset(bin)); - if (write_data(*sino_stream, v[bin.axial_pos_num()], on_disk_data_type, scale, on_disk_byte_order) - == Succeeded::no + if (write_data(*sino_stream, v[bin.axial_pos_num()], on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no || scale != scale_factor) { succeeded = Succeeded::no; @@ -376,12 +377,12 @@ ProjDataFromStream::set_viewgram(const Viewgram& v) } } } - else if (get_storage_order() == Segment_View_AxialPos_TangPos || get_storage_order() == Timing_Segment_View_AxialPos_TangPos) + else if (get_storage_order() == Segment_View_AxialPos_TangPos + || get_storage_order() == Timing_Segment_View_AxialPos_TangPos) { // write in one go (skipping the extra seek) - detail::checked_seekp( "set_viewgram", *sino_stream, get_offset(bin)); - if (write_data(*sino_stream, v, on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no - || scale != scale_factor) + detail::checked_seekp("set_viewgram", *sino_stream, get_offset(bin)); + if (write_data(*sino_stream, v, on_disk_data_type, scale, on_disk_byte_order) == Succeeded::no || scale != scale_factor) { succeeded = Succeeded::no; } @@ -402,109 +403,94 @@ ProjDataFromStream::set_viewgram(const Viewgram& v) if (succeeded == Succeeded::no) error("ProjDataFromStream::set_viewgram: viewgram (view=%d, segment=%d, timing_pos=%d)" " corrupted due to problems with writing or the scale factor (out of disk space?)", - view_num, segment_num, timing_pos); + view_num, + segment_num, + timing_pos); return succeeded; } - std::streamoff ProjDataFromStream::get_offset(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_offset: 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_offset: 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_offset: axial_pos_num out of range : %d", this_bin.axial_pos_num()); - if (!(this_bin.timing_pos_num() >= get_min_tof_pos_num() && - this_bin.timing_pos_num() <= get_max_tof_pos_num())) - error("ProjDataFromStream::get_offset: timing_num out of range : %d", this_bin.timing_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_offset: axial_pos_num out of range : %d", this_bin.axial_pos_num()); + if (!(this_bin.timing_pos_num() >= get_min_tof_pos_num() && this_bin.timing_pos_num() <= get_max_tof_pos_num())) + error("ProjDataFromStream::get_offset: timing_num out of range : %d", this_bin.timing_pos_num()); - const int index = - static_cast(std::find(segment_sequence.begin(), segment_sequence.end(), this_bin.segment_num()) - - segment_sequence.begin()); + const int index = static_cast(std::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(num_axial_pos_offset* - get_num_tangential_poss() * - get_num_views() * - on_disk_data_type.size_in_bytes()); + 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 || get_storage_order() == Timing_Segment_AxialPos_View_TangPos) + // Now we are just in front of the correct segment + if (get_storage_order() == Segment_AxialPos_View_TangPos || get_storage_order() == Timing_Segment_AxialPos_View_TangPos) { - if (proj_data_info_sptr->get_num_tof_poss() > 1) - { - // The timing offset will be added to the segment offset to minimise the changes - const int timing_index = static_cast(std::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 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 - - //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(); - - return segment_offset + ax_pos_offset + view_offset +tang_offset; + if (proj_data_info_sptr->get_num_tof_poss() > 1) + { + // The timing offset will be added to the segment offset to minimise the changes + const int timing_index + = static_cast(std::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 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 + + // 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(); + + return segment_offset + ax_pos_offset + view_offset + tang_offset; } - else if (get_storage_order() == Segment_View_AxialPos_TangPos || get_storage_order() == Timing_Segment_View_AxialPos_TangPos) + else if (get_storage_order() == Segment_View_AxialPos_TangPos || get_storage_order() == Timing_Segment_View_AxialPos_TangPos) { - if (proj_data_info_sptr->get_num_tof_poss() > 1) - { - // The timing offset will be added to the segment offset. This approach we minimise the changes - const int timing_index = static_cast(std::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(); - - return segment_offset + ax_pos_offset +view_offset + tang_offset; + if (proj_data_info_sptr->get_num_tof_poss() > 1) + { + // The timing offset will be added to the segment offset. This approach we minimise the changes + const int timing_index + = static_cast(std::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(); + + return segment_offset + ax_pos_offset + view_offset + tang_offset; } - else + else { error("ProjDataFromStream::get_offset: unsupported storage order"); return streamoff(0); // return something to avoid compiler warning @@ -512,17 +498,19 @@ ProjDataFromStream::get_offset(const Bin& this_bin) const } Sinogram -ProjDataFromStream::get_sinogram(const int ax_pos_num, const int segment_num, - const bool make_num_tangential_poss_odd, const int timing_pos) const +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"); - } - if (! *sino_stream) - { - error("ProjDataFromStream::get_sinogram: error in stream state before reading"); - } + { + error("ProjDataFromStream::get_sinogram: stream ptr is 0"); + } + if (!*sino_stream) + { + error("ProjDataFromStream::get_sinogram: error in stream state before reading"); + } Sinogram sinogram(proj_data_info_sptr, ax_pos_num, segment_num, timing_pos); float scale = float(1); @@ -530,7 +518,7 @@ ProjDataFromStream::get_sinogram(const int ax_pos_num, const int segment_num, Bin bin(segment_num, this->get_min_view_num(), ax_pos_num, this->get_min_tangential_pos_num(), timing_pos); #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif try { @@ -538,8 +526,9 @@ ProjDataFromStream::get_sinogram(const int ax_pos_num, const int segment_num, { detail::checked_seekg("get_sinogram", *sino_stream, get_offset(bin)); succeeded = read_data(*sino_stream, sinogram, on_disk_data_type, scale, on_disk_byte_order); - } - else if (get_storage_order() == Segment_View_AxialPos_TangPos || get_storage_order() == Timing_Segment_View_AxialPos_TangPos) + } + else if (get_storage_order() == Segment_View_AxialPos_TangPos + || get_storage_order() == Timing_Segment_View_AxialPos_TangPos) { for (bin.view_num() = get_min_view_num(); bin.view_num() <= get_max_view_num(); bin.view_num()++) { @@ -547,9 +536,9 @@ ProjDataFromStream::get_sinogram(const int ax_pos_num, const int segment_num, if ((succeeded = read_data(*sino_stream, sinogram[bin.view_num()], on_disk_data_type, scale, on_disk_byte_order)) == Succeeded::no) break; - if(scale != 1) + if (scale != 1) break; - } + } } else { @@ -562,21 +551,18 @@ ProjDataFromStream::get_sinogram(const int ax_pos_num, const int segment_num, succeeded = Succeeded::no; } // end of critical section - if(scale != 1) + if (scale != 1) error("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1"); if (succeeded == Succeeded::no) error("ProjDataFromStream: error reading data"); sinogram *= scale_factor; - if (make_num_tangential_poss_odd&&(get_num_tangential_poss()%2==0)) + 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; @@ -586,34 +572,33 @@ Succeeded 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) - { - warning("ProjDataFromStream::set_sinogram: error in stream state before writing\n"); - return Succeeded::no; - } + { + warning("ProjDataFromStream::set_sinogram: stream ptr is 0\n"); + return Succeeded::no; + } + 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) - { - warning("ProjDataFromStream::set_sinogram: non-float output uses original " - "scale factor %g which might not be appropriate for the current data\n", - scale_factor); - } + { + warning("ProjDataFromStream::set_sinogram: non-float output uses original " + "scale factor %g which might not be appropriate for the current data\n", + scale_factor); + } 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() - ); - - return Succeeded::no; - } + { + 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()); + + return Succeeded::no; + } int segment_num = s.get_segment_num(); int ax_pos_num = s.get_axial_pos_num(); int timing_pos = s.get_timing_pos_num(); @@ -622,35 +607,35 @@ ProjDataFromStream::set_sinogram(const Sinogram& s) Succeeded succeeded = Succeeded::yes; #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif try { if (get_storage_order() == Segment_AxialPos_View_TangPos || get_storage_order() == Timing_Segment_AxialPos_View_TangPos) { detail::checked_seekp("set_sinogram", *sino_stream, get_offset(bin)); - if (write_data(*sino_stream, s, on_disk_data_type, scale, on_disk_byte_order) - == Succeeded::no - || scale != scale_factor) + 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); + ax_pos_num, + segment_num); succeeded = Succeeded::no; } } - else if (get_storage_order() == Segment_View_AxialPos_TangPos || get_storage_order() == Timing_Segment_View_AxialPos_TangPos) + else if (get_storage_order() == Segment_View_AxialPos_TangPos + || get_storage_order() == Timing_Segment_View_AxialPos_TangPos) { for (bin.view_num() = get_min_view_num(); bin.view_num() <= get_max_view_num(); bin.view_num()++) { detail::checked_seekp("set_sinogram", *sino_stream, get_offset(bin)); - if (write_data(*sino_stream, s[bin.view_num()], on_disk_data_type, scale, on_disk_byte_order) - == Succeeded::no + if (write_data(*sino_stream, s[bin.view_num()], 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); + ax_pos_num, + segment_num); succeeded = Succeeded::no; break; } @@ -658,7 +643,7 @@ ProjDataFromStream::set_sinogram(const Sinogram& s) } else { - warning("ProjDataFromStream::set_sinogram: unsupported storage order"); + warning("ProjDataFromStream::set_sinogram: unsupported storage order"); succeeded = Succeeded::no; } // flush the stream, see the class documentation @@ -675,23 +660,27 @@ ProjDataFromStream::set_sinogram(const Sinogram& s) SegmentBySinogram 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) - { - error("ProjDataFromStream::get_segment_by_sinogram: error in stream state before reading\n"); - } + if (is_null_ptr(sino_stream)) + { + error("ProjDataFromStream::get_segment_by_sinogram: stream ptr is 0\n"); + } + if (!*sino_stream) + { + error("ProjDataFromStream::get_segment_by_sinogram: error in stream state before reading\n"); + } if (get_storage_order() == Segment_AxialPos_View_TangPos || get_storage_order() == Timing_Segment_AxialPos_View_TangPos) { - SegmentBySinogram segment(proj_data_info_sptr,segment_num, timing_num); + SegmentBySinogram segment(proj_data_info_sptr, segment_num, timing_num); float scale = float(1); Succeeded succeeded = Succeeded::yes; - const Bin bin(segment_num, this->get_min_view_num(), this->get_min_axial_pos_num(segment_num), this->get_min_tangential_pos_num(), timing_num); + const Bin bin(segment_num, + this->get_min_view_num(), + this->get_min_axial_pos_num(segment_num), + this->get_min_tangential_pos_num(), + timing_num); #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif try { @@ -703,90 +692,98 @@ ProjDataFromStream::get_segment_by_sinogram(const int segment_num, const int tim succeeded = Succeeded::no; } // end of critical section - if (succeeded == Succeeded::no) - error("ProjDataFromStream: error reading data\n"); - if(scale != 1) - error("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1\n"); + if (succeeded == Succeeded::no) + error("ProjDataFromStream: error reading data\n"); + if (scale != 1) + error("ProjDataFromStream: error reading data: scale factor returned by read_data should be 1\n"); - segment *= scale_factor; - return segment; + segment *= scale_factor; + return segment; } else { // TODO rewrite in terms of get_viewgram - return SegmentBySinogram (get_segment_by_view(segment_num, timing_num)); + return SegmentBySinogram(get_segment_by_view(segment_num, timing_num)); } } SegmentByView 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) - { - error("ProjDataFromStream::get_segment_by_view: error in stream state before reading\n"); - } + if (is_null_ptr(sino_stream)) + { + error("ProjDataFromStream::get_segment_by_view: stream ptr is 0\n"); + } + if (!*sino_stream) + { + error("ProjDataFromStream::get_segment_by_view: error in stream state before reading\n"); + } 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); - float scale = float(1); - Succeeded succeeded = Succeeded::yes; - const Bin bin(segment_num, this->get_min_view_num(), this->get_min_axial_pos_num(segment_num), this->get_min_tangential_pos_num(), timing_pos); + { + SegmentByView segment(proj_data_info_sptr, segment_num, timing_pos); + float scale = float(1); + Succeeded succeeded = Succeeded::yes; + const Bin bin(segment_num, + this->get_min_view_num(), + this->get_min_axial_pos_num(segment_num), + this->get_min_tangential_pos_num(), + timing_pos); #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif - try - { - detail::checked_seekg("get_segment_by_view", *sino_stream, get_offset(bin)); - succeeded = read_data(*sino_stream, segment, on_disk_data_type, scale, on_disk_byte_order); - } - catch (...) - { - succeeded = Succeeded::no; - } - // 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\n"); - - segment *= scale_factor; - return segment; - } - else + try + { + detail::checked_seekg("get_segment_by_view", *sino_stream, get_offset(bin)); + succeeded = read_data(*sino_stream, segment, on_disk_data_type, scale, on_disk_byte_order); + } + catch (...) + { + succeeded = Succeeded::no; + } + // 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\n"); + + segment *= scale_factor; + return segment; + } + else // TODO rewrite in terms of get_sinogram as this doubles memory temporarily - return SegmentByView (get_segment_by_sinogram(segment_num, timing_pos)); + return SegmentByView(get_segment_by_sinogram(segment_num, timing_pos)); } Succeeded 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) - { - error("ProjDataFromStream::set_segment: error in stream state before writing\n"); - } + if (is_null_ptr(sino_stream)) + { + error("ProjDataFromStream::set_segment: stream ptr is 0\n"); + } + 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"); - return Succeeded::no; - } + { + 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"); - return Succeeded::no; - } + { + warning("ProjDataFromStream::set_segment: num_views is not correct\n"); + return Succeeded::no; + } const int segment_num = segmentbysinogram_v.get_segment_num(); - const Bin bin(segment_num, this->get_min_view_num(), this->get_min_axial_pos_num(segment_num), this->get_min_tangential_pos_num(), segmentbysinogram_v.get_timing_pos_num()); + const Bin bin(segment_num, + this->get_min_view_num(), + this->get_min_axial_pos_num(segment_num), + this->get_min_tangential_pos_num(), + segmentbysinogram_v.get_timing_pos_num()); if (get_storage_order() == Segment_AxialPos_View_TangPos || get_storage_order() == Timing_Segment_AxialPos_View_TangPos) { @@ -795,23 +792,23 @@ ProjDataFromStream::set_segment(const SegmentBySinogram& segmentbysinogra { warning("ProjDataFromStream::set_segment: non-float output uses original " "scale factor %g which might not be appropriate for the current data\n", - scale_factor); + scale_factor); } float scale = scale_factor; Succeeded succeeded = Succeeded::yes; #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif try { detail::checked_seekp("set_segment", *sino_stream, get_offset(bin)); - if (write_data(*sino_stream, segmentbysinogram_v, on_disk_data_type, scale, on_disk_byte_order) - == Succeeded::no - || scale != scale_factor) + 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()); + segment_num, + segmentbysinogram_v.get_timing_pos_num()); succeeded = Succeeded::no; } // flush the stream, see the class documentation @@ -824,90 +821,89 @@ ProjDataFromStream::set_segment(const SegmentBySinogram& segmentbysinogra // end of critical section return succeeded; } - else + else { // TODO rewrite in terms of set_viewgram - const SegmentByView segmentbyview= - SegmentByView(segmentbysinogram_v); + 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)) - { - error("ProjDataFromStream::set_segment: stream ptr is 0\n"); - } - if (! *sino_stream) - { - error("ProjDataFromStream::set_segment: error in stream state before writing\n"); - } - + if (is_null_ptr(sino_stream)) + { + error("ProjDataFromStream::set_segment: stream ptr is 0\n"); + } + 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"); - return Succeeded::no; - } + { + 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"); - return Succeeded::no; - } + { + warning("ProjDataFromStream::set_segment: num_views is not correct\n"); + return Succeeded::no; + } const int segment_num = segmentbyview_v.get_segment_num(); - const Bin bin(segment_num, this->get_min_view_num(), this->get_min_axial_pos_num(segment_num), this->get_min_tangential_pos_num(), segmentbyview_v.get_timing_pos_num()); + const Bin bin(segment_num, + this->get_min_view_num(), + this->get_min_axial_pos_num(segment_num), + this->get_min_tangential_pos_num(), + segmentbyview_v.get_timing_pos_num()); - if (get_storage_order() == Segment_View_AxialPos_TangPos || get_storage_order() == Timing_Segment_View_AxialPos_TangPos) + 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); + scale_factor); } - float scale = scale_factor; - Succeeded succeeded = Succeeded::yes; + float scale = scale_factor; + Succeeded succeeded = Succeeded::yes; #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAFROMSTREAMIO) +# pragma omp critical(PROJDATAFROMSTREAMIO) #endif - try - { - detail::checked_seekp("set_segment", *sino_stream, get_offset(bin)); - 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(); - } - catch (...) - { - succeeded = Succeeded::no; - } - // end of critical section - return succeeded; + try + { + detail::checked_seekp("set_segment", *sino_stream, get_offset(bin)); + 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(); + } + catch (...) + { + succeeded = Succeeded::no; + } + // end of critical section + return succeeded; } - else + else { - // TODO rewrite in terms of set_sinogram - const SegmentBySinogram segmentbysinogram = - SegmentBySinogram(segmentbyview_v); + // 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) { @@ -1065,16 +1061,7 @@ ProjDataFromStream* ProjDataFromStream::ask_parameters(const bool on_disk) float ProjDataFromStream::get_scale_factor() const { - return scale_factor;} - - + return scale_factor; +} END_NAMESPACE_STIR - - - - - - - - diff --git a/src/buildblock/ProjDataGEHDF5.cxx b/src/buildblock/ProjDataGEHDF5.cxx index dba0a58e2..ec5174021 100644 --- a/src/buildblock/ProjDataGEHDF5.cxx +++ b/src/buildblock/ProjDataGEHDF5.cxx @@ -20,8 +20,6 @@ See STIR/LICENSE.txt for details */ - - #include "stir/ProjDataGEHDF5.h" #include "stir/IndexRange.h" #include "stir/IndexRange3D.h" @@ -37,65 +35,70 @@ using std::ios; START_NAMESPACE_STIR -namespace GE { -namespace RDF_HDF5 { +namespace GE +{ +namespace RDF_HDF5 +{ -ProjDataGEHDF5::ProjDataGEHDF5(const std::string& input_filename) : - ProjData() +ProjDataGEHDF5::ProjDataGEHDF5(const std::string& input_filename) + : ProjData() { - this->m_input_hdf5_sptr.reset(new GEHDF5Wrapper(input_filename)); - this->initialise_from_wrapper(); + 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) +ProjDataGEHDF5::ProjDataGEHDF5(shared_ptr input_hdf5_sptr) + : ProjData(), + m_input_hdf5_sptr(input_hdf5_sptr) { - this->initialise_from_wrapper(); + this->initialise_from_wrapper(); } -void ProjDataGEHDF5::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(); + 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); m_input_hdf5_sptr->read_sinogram(buffer); this->tof_data.push_back(buffer); - } - + } } -void ProjDataGEHDF5::initialise_segment_sequence() +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.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; + 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()); @@ -104,52 +107,52 @@ void ProjDataGEHDF5::initialise_ax_pos_offset() 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]; + { + const int segment_num = segment_sequence[i_seg - 1]; - seg_ax_offset[i_seg] = static_cast(get_num_axial_poss(segment_num)) + - previous_value; + 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 int timing_pos) const +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) + 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); + + // 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]); - } + 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; @@ -175,46 +178,50 @@ 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) +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; + // 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 int timing_pos) const +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); + // TODO + error("ProjDataGEHDF5::get_sinogram not implemented yet"); + return get_empty_sinogram(ax_pos_num, segment_num); } -Succeeded ProjDataGEHDF5::set_sinogram(const Sinogram& s) +Succeeded +ProjDataGEHDF5::set_sinogram(const Sinogram& s) { - error("ProjDataGEHDF5::set_sinogram not implemented yet"); - return Succeeded::no; + error("ProjDataGEHDF5::set_sinogram not implemented yet"); + return Succeeded::no; } unsigned int ProjDataGEHDF5::find_segment_index_in_sequence(const int segment_num) const { - 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); // 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 +{ + return segment_sequence; } + +} // namespace RDF_HDF5 +} // namespace GE END_NAMESPACE_STIR diff --git a/src/buildblock/ProjDataInMemory.cxx b/src/buildblock/ProjDataInMemory.cxx index 9c6f0aa72..bcd0bc771 100644 --- a/src/buildblock/ProjDataInMemory.cxx +++ b/src/buildblock/ProjDataInMemory.cxx @@ -23,7 +23,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/ProjDataInMemory.h" #include "stir/shared_ptr.h" #include "stir/Succeeded.h" @@ -39,43 +38,38 @@ using std::streamoff; START_NAMESPACE_STIR -ProjDataInMemory:: -~ProjDataInMemory() +ProjDataInMemory::~ProjDataInMemory() {} -ProjDataInMemory:: -ProjDataInMemory(shared_ptr const& exam_info_sptr, - shared_ptr const& proj_data_info_ptr, const bool initialise_with_0) - : - ProjData(exam_info_sptr, proj_data_info_ptr), - segment_sequence(ProjData::standard_segment_sequence(*proj_data_info_ptr)) +ProjDataInMemory::ProjDataInMemory(shared_ptr const& exam_info_sptr, + shared_ptr const& proj_data_info_ptr, + const bool initialise_with_0) + : ProjData(exam_info_sptr, proj_data_info_ptr), + segment_sequence(ProjData::standard_segment_sequence(*proj_data_info_ptr)) { this->create_buffer(initialise_with_0); 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(); + 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); + offset_3d_data = static_cast(sum); 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(); + 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; } - } void -ProjDataInMemory:: -create_buffer(const bool initialise_with_0) +ProjDataInMemory::create_buffer(const bool initialise_with_0) { #if 0 float *b = new float[this->size_all()]; @@ -83,71 +77,83 @@ create_buffer(const bool initialise_with_0) memset(b, 0, this->size_all()*sizeof(float)); return b; #else - this->buffer = Array<1,float>(static_cast(this->size_all())); + this->buffer = Array<1, float>(static_cast(this->size_all())); #endif } ///////////////// /set functions -namespace detail { - template - void copy_data_from_buffer(const Array<1,float>& buffer, Array& array, std::streamoff offset) - { +namespace detail +{ +template +void +copy_data_from_buffer(const Array<1, float>& buffer, Array& array, std::streamoff offset) +{ #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAINMEMORYCOPY) +# pragma omp critical(PROJDATAINMEMORYCOPY) #endif - { - const float * ptr = buffer.get_const_data_ptr() + offset; - std::copy(ptr, ptr + array.size_all(), array.begin_all()); - buffer.release_const_data_ptr(); - } + { + const float* ptr = buffer.get_const_data_ptr() + offset; + std::copy(ptr, ptr + array.size_all(), array.begin_all()); + buffer.release_const_data_ptr(); } +} - template - void copy_data_to_buffer(Array<1,float>& buffer, const Array& array, std::streamoff offset) - { +template +void +copy_data_to_buffer(Array<1, float>& buffer, const Array& array, std::streamoff offset) +{ #ifdef STIR_OPENMP -#pragma omp critical(PROJDATAINMEMORYCOPY) +# pragma omp critical(PROJDATAINMEMORYCOPY) #endif - { - float * ptr = buffer.get_data_ptr() + offset; - std::copy(array.begin_all(), array.end_all(), ptr); - buffer.release_data_ptr(); - } + { + float* ptr = buffer.get_data_ptr() + offset; + std::copy(array.begin_all(), array.end_all(), ptr); + buffer.release_data_ptr(); } } +} // namespace detail Viewgram -ProjDataInMemory::get_viewgram(const int view_num, const int segment_num, - const bool make_num_tangential_poss_odd +ProjDataInMemory::get_viewgram(const int view_num, + const int segment_num, + const bool make_num_tangential_poss_odd #ifdef STIR_TOF - , const int timing_pos + , + const int timing_pos #endif - ) const +) const { - Viewgram viewgram(proj_data_info_sptr, view_num, segment_num + Viewgram viewgram(proj_data_info_sptr, + view_num, + segment_num #ifdef STIR_TOF - , timing_pos + , + timing_pos #endif - ); - Bin bin(segment_num, view_num, this->get_min_axial_pos_num(segment_num), this->get_min_tangential_pos_num() + ); + Bin bin(segment_num, + view_num, + this->get_min_axial_pos_num(segment_num), + this->get_min_tangential_pos_num() #ifdef STIR_TOF - , timing_pos + , + timing_pos #endif - ); + ); - for (bin.axial_pos_num() = get_min_axial_pos_num(segment_num); bin.axial_pos_num() <= get_max_axial_pos_num(segment_num); bin.axial_pos_num()++) + for (bin.axial_pos_num() = get_min_axial_pos_num(segment_num); bin.axial_pos_num() <= get_max_axial_pos_num(segment_num); + bin.axial_pos_num()++) { detail::copy_data_from_buffer(this->buffer, viewgram[bin.axial_pos_num()], this->get_index(bin)); } - if (make_num_tangential_poss_odd &&(get_num_tangential_poss()%2==0)) + 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), + 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)); @@ -164,8 +170,7 @@ ProjDataInMemory::set_viewgram(const Viewgram& v) "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() - ); + v.get_proj_data_info_sptr()->parameter_info().c_str()); return Succeeded::no; } @@ -175,13 +180,18 @@ ProjDataInMemory::set_viewgram(const Viewgram& v) const int timing_pos = v.get_timing_pos_num(); #endif - Bin bin(segment_num, view_num, this->get_min_axial_pos_num(segment_num), this->get_min_tangential_pos_num() + Bin bin(segment_num, + view_num, + this->get_min_axial_pos_num(segment_num), + this->get_min_tangential_pos_num() #ifdef STIR_TOF - , timing_pos + , + timing_pos #endif - ); + ); - for (bin.axial_pos_num() = get_min_axial_pos_num(segment_num); bin.axial_pos_num() <= get_max_axial_pos_num(segment_num); bin.axial_pos_num()++) + for (bin.axial_pos_num() = get_min_axial_pos_num(segment_num); bin.axial_pos_num() <= get_max_axial_pos_num(segment_num); + bin.axial_pos_num()++) { detail::copy_data_to_buffer(this->buffer, v[bin.axial_pos_num()], this->get_index(bin)); } @@ -189,100 +199,94 @@ ProjDataInMemory::set_viewgram(const Viewgram& v) return Succeeded::yes; } - std::streamoff ProjDataInMemory::get_index(const Bin& this_bin) const { - if (!(this_bin.segment_num() >= get_min_segment_num() && - this_bin.segment_num() <= get_max_segment_num())) + if (!(this_bin.segment_num() >= get_min_segment_num() && this_bin.segment_num() <= get_max_segment_num())) error("ProjDataInMemory::this->get_index: 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()))) + 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("ProjDataInMemory::this->get_index: axial_pos_num out of range : %d", this_bin.axial_pos_num()); #ifdef STIR_TOF - if (!(this_bin.timing_pos_num() >= get_min_tof_pos_num() && - this_bin.timing_pos_num() <= get_max_tof_pos_num())) + if (!(this_bin.timing_pos_num() >= get_min_tof_pos_num() && this_bin.timing_pos_num() <= get_max_tof_pos_num())) error("ProjDataInMemory::this->get_index: timing_pos_num out of range : %d", this_bin.timing_pos_num()); #endif - const int index = - static_cast(std::find(segment_sequence.begin(), segment_sequence.end(), this_bin.segment_num()) - - segment_sequence.begin()); + const int index = static_cast(std::find(segment_sequence.begin(), segment_sequence.end(), this_bin.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()); + streamoff segment_offset = static_cast(num_axial_pos_offset * get_num_tangential_poss() * get_num_views()); // Now we are just in front of the correct segment { #ifdef STIR_TOF if (proj_data_info_sptr->get_num_tof_poss() > 1) { - const int timing_index = static_cast(std::find(timing_poss_sequence.begin(), timing_poss_sequence.end(), this_bin.timing_pos_num()) - - timing_poss_sequence.begin()); + const int timing_index + = static_cast(std::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; } #endif // 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(); + 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(); // sinogram location - //find view - const streamoff view_offset = - (this_bin.view_num() - get_min_view_num()) - * get_num_tangential_poss(); + // find view + const streamoff view_offset = (this_bin.view_num() - get_min_view_num()) * get_num_tangential_poss(); // find tang pos - const streamoff tang_offset = - (this_bin.tangential_pos_num() - get_min_tangential_pos_num()); + const streamoff tang_offset = (this_bin.tangential_pos_num() - get_min_tangential_pos_num()); - return segment_offset + ax_pos_offset + view_offset +tang_offset; + return segment_offset + ax_pos_offset + view_offset + tang_offset; } } Sinogram -ProjDataInMemory::get_sinogram(const int ax_pos_num, const int segment_num, - const bool make_num_tangential_poss_odd +ProjDataInMemory::get_sinogram(const int ax_pos_num, + const int segment_num, + const bool make_num_tangential_poss_odd #ifdef STIR_TOF - , const int timing_pos + , + const int timing_pos #endif - ) const +) const { - Sinogram sinogram(proj_data_info_sptr, ax_pos_num, segment_num + Sinogram sinogram(proj_data_info_sptr, + ax_pos_num, + segment_num #ifdef STIR_TOF - , timing_pos + , + timing_pos #endif - ); - Bin bin(segment_num, this->get_min_view_num(), ax_pos_num, this->get_min_tangential_pos_num() + ); + Bin bin(segment_num, + this->get_min_view_num(), + ax_pos_num, + this->get_min_tangential_pos_num() #ifdef STIR_TOF - , timing_pos + , + timing_pos #endif - ); + ); detail::copy_data_from_buffer(this->buffer, sinogram, this->get_index(bin)); - if (make_num_tangential_poss_odd&&(get_num_tangential_poss()%2==0)) + 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; @@ -292,26 +296,29 @@ Succeeded ProjDataInMemory::set_sinogram(const Sinogram& s) { if (*get_proj_data_info_sptr() != *(s.get_proj_data_info_sptr())) - { - warning("ProjDataInMemory::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() - ); - - return Succeeded::no; - } + { + warning("ProjDataInMemory::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()); + + return Succeeded::no; + } int segment_num = s.get_segment_num(); int ax_pos_num = s.get_axial_pos_num(); #ifdef STIR_TOF int timing_pos = s.get_timing_pos_num(); #endif - Bin bin(segment_num, this->get_min_view_num(), ax_pos_num, this->get_min_tangential_pos_num() + Bin bin(segment_num, + this->get_min_view_num(), + ax_pos_num, + this->get_min_tangential_pos_num() #ifdef STIR_TOF - , timing_pos + , + timing_pos #endif - ); + ); detail::copy_data_to_buffer(this->buffer, s, this->get_index(bin)); return Succeeded::yes; @@ -320,20 +327,27 @@ ProjDataInMemory::set_sinogram(const Sinogram& s) SegmentBySinogram ProjDataInMemory::get_segment_by_sinogram(const int segment_num #ifdef STIR_TOF - , const int timing_pos_num + , + const int timing_pos_num #endif - ) const +) const { - SegmentBySinogram segment(proj_data_info_sptr,segment_num + SegmentBySinogram segment(proj_data_info_sptr, + segment_num #ifdef STIR_TOF - , timing_pos_num + , + timing_pos_num #endif - ); - const Bin bin(segment_num, this->get_min_view_num(), this->get_min_axial_pos_num(segment_num), this->get_min_tangential_pos_num() + ); + const Bin bin(segment_num, + this->get_min_view_num(), + this->get_min_axial_pos_num(segment_num), + this->get_min_tangential_pos_num() #ifdef STIR_TOF - , timing_pos_num + , + timing_pos_num #endif - ); + ); detail::copy_data_from_buffer(this->buffer, segment, this->get_index(bin)); return segment; } @@ -341,44 +355,49 @@ ProjDataInMemory::get_segment_by_sinogram(const int segment_num SegmentByView ProjDataInMemory::get_segment_by_view(const int segment_num #ifdef STIR_TOF - , const int timing_pos + , + const int timing_pos #endif - ) const +) const { // 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 #ifdef STIR_TOF - , timing_pos + , + timing_pos #endif - )); + )); } Succeeded ProjDataInMemory::set_segment(const SegmentBySinogram& segmentbysinogram_v) { if (get_num_tangential_poss() != segmentbysinogram_v.get_num_tangential_poss()) - { - warning("ProjDataInMemory::set_segmen: num_bins is not correct\n"); - return Succeeded::no; - } + { + warning("ProjDataInMemory::set_segmen: num_bins is not correct\n"); + return Succeeded::no; + } if (get_num_views() != segmentbysinogram_v.get_num_views()) - { - warning("ProjDataInMemory::set_segment: num_views is not correct\n"); - return Succeeded::no; - } + { + warning("ProjDataInMemory::set_segment: num_views is not correct\n"); + return Succeeded::no; + } const int segment_num = segmentbysinogram_v.get_segment_num(); - const Bin bin(segment_num, this->get_min_view_num(), this->get_min_axial_pos_num(segment_num), this->get_min_tangential_pos_num() + const Bin bin(segment_num, + this->get_min_view_num(), + this->get_min_axial_pos_num(segment_num), + this->get_min_tangential_pos_num() #ifdef STIR_TOF - , segmentbysinogram_v.get_timing_pos_num() + , + segmentbysinogram_v.get_timing_pos_num() #endif - ); + ); detail::copy_data_to_buffer(this->buffer, segmentbysinogram_v, this->get_index(bin)); return Succeeded::yes; } - Succeeded ProjDataInMemory::set_segment(const SegmentByView& segmentbyview_v) { @@ -387,7 +406,6 @@ ProjDataInMemory::set_segment(const SegmentByView& segmentbyview_v) return set_segment(segmentbysinogram); } - ///////////////// other functions void ProjDataInMemory::fill(const float value) @@ -398,9 +416,8 @@ ProjDataInMemory::fill(const float 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())) + 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()); } @@ -410,65 +427,55 @@ ProjDataInMemory::fill(const ProjData& proj_data) } } -ProjDataInMemory:: -ProjDataInMemory(const ProjData& proj_data) - : ProjDataInMemory(proj_data.get_exam_info_sptr(), - proj_data.get_proj_data_info_sptr()->create_shared_clone(), - false) +ProjDataInMemory::ProjDataInMemory(const ProjData& proj_data) + : ProjDataInMemory(proj_data.get_exam_info_sptr(), proj_data.get_proj_data_info_sptr()->create_shared_clone(), false) { this->fill(proj_data); } -ProjDataInMemory:: -ProjDataInMemory (const ProjDataInMemory& proj_data) - : ProjDataInMemory(proj_data.get_exam_info_sptr(), - proj_data.get_proj_data_info_sptr()->create_shared_clone(), - false) +ProjDataInMemory::ProjDataInMemory(const ProjDataInMemory& proj_data) + : ProjDataInMemory(proj_data.get_exam_info_sptr(), proj_data.get_proj_data_info_sptr()->create_shared_clone(), false) { std::copy(proj_data.begin_all(), proj_data.end_all(), this->begin_all()); } -float +float ProjDataInMemory::get_bin_value(Bin& bin) { return buffer[this->get_index(bin)]; } -void +void ProjDataInMemory::set_bin_value(const Bin& bin) { - buffer[this->get_index(bin)]=bin.get_bin_value(); + buffer[this->get_index(bin)] = bin.get_bin_value(); } void -ProjDataInMemory:: -axpby( const float a, const ProjData& x, - const float b, const ProjData& y) +ProjDataInMemory::axpby(const float a, const ProjData& x, const float b, const ProjData& y) { - xapyb(x,a,y,b); + xapyb(x, a, y, b); } void -ProjDataInMemory:: -xapyb(const ProjData& x, const float a, - const ProjData& y, const float b) +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; + // 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 + // 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"); + // 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 @@ -481,38 +488,33 @@ 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) +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; + // 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 + // 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"); + // 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 @@ -527,22 +529,20 @@ 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) +ProjDataInMemory::sapyb(const float a, const ProjData& y, const float b) { - this->xapyb(*this,a,y,b); + this->xapyb(*this, a, y, b); } void -ProjDataInMemory:: -sapyb(const ProjData& a, const ProjData& y,const ProjData& b) +ProjDataInMemory::sapyb(const ProjData& a, const ProjData& y, const ProjData& b) { - this->xapyb(*this,a,y,b); + this->xapyb(*this, a, y, b); } END_NAMESPACE_STIR diff --git a/src/buildblock/ProjDataInfo.cxx b/src/buildblock/ProjDataInfo.cxx index 47ef19af8..05adde73c 100644 --- a/src/buildblock/ProjDataInfo.cxx +++ b/src/buildblock/ProjDataInfo.cxx @@ -68,10 +68,10 @@ 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); + 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); } double @@ -83,89 +83,80 @@ ProjDataInfo::get_tof_delta_time(const Bin& bin) const 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; + 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 +float ProjDataInfo::get_sampling_in_t(const Bin& bin) const { - return - abs(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; + return abs(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 +float ProjDataInfo::get_sampling_in_m(const Bin& bin) const { - return - abs(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; + return abs(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 +float ProjDataInfo::get_sampling_in_s(const Bin& bin) const { - return - abs(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; + return abs(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 +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 +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 +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 + // 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 +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 +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) { @@ -182,15 +173,13 @@ ProjDataInfo::set_max_tangential_pos_num(const int max_tang_poss) void ProjDataInfo::set_tof_mash_factor(const int new_num) { - if (scanner_ptr->is_tof_ready() && new_num > 0 ) + if (scanner_ptr->is_tof_ready() && new_num > 0) { - tof_mash_factor = new_num; - if(tof_mash_factor > scanner_ptr->get_max_num_timing_poss()) - error("ProjDataInfo::set_tof_mash_factor: TOF mashing factor (" - + std::to_string(tof_mash_factor) + - + ") must be smaller than or equal to the scanner's number of max timing bins (" - + std::to_string(scanner_ptr->get_max_num_timing_poss()) - + ")."); + tof_mash_factor = new_num; + if (tof_mash_factor > scanner_ptr->get_max_num_timing_poss()) + error("ProjDataInfo::set_tof_mash_factor: TOF mashing factor (" + std::to_string(tof_mash_factor) + + +") must be smaller than or equal to the scanner's number of max timing bins (" + + std::to_string(scanner_ptr->get_max_num_timing_poss()) + ")."); #if 0 // KT: code disabled as buggy but currently not needed @@ -219,49 +208,50 @@ ProjDataInfo::set_tof_mash_factor(const int new_num) } #endif - // 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()); + // 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()); - // TODO cope with even numbers! - 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; + // TODO cope with even numbers! + 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; - num_tof_bins = max_tof_pos_num - min_tof_pos_num +1 ; + 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."); + // 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); + // 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); + tof_bin_boundaries_ps.grow(min_tof_pos_num, max_tof_pos_num); - for (int k = min_tof_pos_num; k <= max_tof_pos_num; ++k ) + 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)); + 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 + 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 + 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 } } @@ -278,18 +268,18 @@ ProjDataInfo::get_original_view_nums() const } ProjDataInfo::ProjDataInfo() - : bed_position_horizontal(0.F), bed_position_vertical(0.F) + : 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 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) -{ + : 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); @@ -307,7 +297,7 @@ ProjDataInfo::ProjDataInfo(const shared_ptr& scanner_ptr_v, const int num_views_v, const int num_tangential_poss_v, const int tof_mash_factor_v) - :scanner_ptr(scanner_ptr_v) + : scanner_ptr(scanner_ptr_v) { set_tof_mash_factor(tof_mash_factor_v); @@ -317,96 +307,85 @@ ProjDataInfo::ProjDataInfo(const shared_ptr& scanner_ptr_v, } string -ProjDataInfo::parameter_info() const +ProjDataInfo::parameter_info() const { std::ostringstream s; 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 << "start vertical bed position (mm) := " << get_bed_position_vertical() << endl; + s << "start horizontal bed position (mm) := " << get_bed_position_horizontal() << endl; s << "\nTOF mashing factor in data: " << get_tof_mash_factor() << '\n'; s << "Number of TOF positions in data: " << get_num_tof_poss() << '\n'; - s << "\nSegment_num range: (" - << get_min_segment_num() - << ", " << get_max_segment_num() << ")\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 int timing_pos_num) 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, timing_pos_num); - + return v; } -Viewgram +Viewgram ProjDataInfo::get_empty_viewgram(const ViewgramIndices& ind) const -{ +{ // we can't access the shared ptr, so we have to clone 'this'. - shared_ptr proj_data_info_sptr(this->clone()); + shared_ptr proj_data_info_sptr(this->clone()); Viewgram v(proj_data_info_sptr, ind); return v; } - Sinogram -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 +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, timing_pos_num); - + return s; } @@ -414,53 +393,53 @@ Sinogram ProjDataInfo::get_empty_sinogram(const SinogramIndices& ind) const { // we can't access the shared ptr, so we have to clone 'this'. - shared_ptr proj_data_info_sptr(this->clone()); + shared_ptr proj_data_info_sptr(this->clone()); Sinogram s(proj_data_info_sptr, ind); return s; } SegmentBySinogram -ProjDataInfo::get_empty_segment_by_sinogram(const int segment_num, - const bool make_num_tangential_poss_odd, - const int timing_pos_num) 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, timing_pos_num); return s; -} +} SegmentBySinogram ProjDataInfo::get_empty_segment_by_sinogram(const SegmentIndices& ind) const { // we can't access the shared ptr, so we have to clone 'this'. - shared_ptr proj_data_info_sptr(this->clone()); + shared_ptr proj_data_info_sptr(this->clone()); SegmentBySinogram s(proj_data_info_sptr, ind); return s; } SegmentByView -ProjDataInfo::get_empty_segment_by_view(const int segment_num, - const bool make_num_tangential_poss_odd, - const int timing_pos_num) 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, timing_pos_num); return s; @@ -470,171 +449,166 @@ SegmentByView ProjDataInfo::get_empty_segment_by_view(const SegmentIndices& ind) const { // we can't access the shared ptr, so we have to clone 'this'. - shared_ptr proj_data_info_sptr(this->clone()); + shared_ptr proj_data_info_sptr(this->clone()); SegmentByView s(proj_data_info_sptr, ind); return s; } -RelatedViewgrams +RelatedViewgrams ProjDataInfo::get_empty_related_viewgrams(const ViewgramIndices& viewgram_indices, - const shared_ptr& symmetries_used, - const bool make_num_tangential_poss_odd, - const int timing_pos_num) const + const shared_ptr& symmetries_used, + const bool make_num_tangential_poss_odd, + const int timing_pos_num) const { if (make_num_tangential_poss_odd) error("make_num_tangential_poss_odd is no longer supported"); vector pairs; symmetries_used->get_related_view_segment_numbers(pairs, viewgram_indices); - 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 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) + 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); + RDmintmp[0] = -((span - 1) / 2); RDmaxtmp[0] = RDmintmp[0] + span - 1; } else { - RDmintmp[0] = -(span/2); + RDmintmp[0] = -(span / 2); RDmaxtmp[0] = RDmintmp[0] + span; } - int seg_num =0; + int seg_num = 0; while (RDmaxtmp[seg_num] < max_delta) - { - seg_num++; - RDmintmp[seg_num] = RDmaxtmp[seg_num-1] + 1; - RDmaxtmp[seg_num] = RDmintmp[seg_num] + span - 1; - } + { + seg_num++; + 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]); - // Palak Wadwha changed this to max_delta to accomodate GE scanners, it is more general anyway. - 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++) - { - // 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]; - } - - if (span==1) - { - num_axial_pos_per_segment[0] = num_ring; - 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]; + } + + if (span == 1) { - num_axial_pos_per_segment[i]= - num_axial_pos_per_segment[-i] = num_ring -i; + 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; + } } - } 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]); - } - } - + 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 (scanner->get_scanner_geometry() == "BlocksOnCylindrical") - return - new ProjDataInfoBlocksOnCylindricalNoArcCorr(scanner, - num_axial_pos_per_segment, - min_ring_difference, - max_ring_difference, - num_views,num_tangential_poss); + return new ProjDataInfoBlocksOnCylindricalNoArcCorr( + scanner, num_axial_pos_per_segment, min_ring_difference, max_ring_difference, num_views, num_tangential_poss); else if (scanner->get_scanner_geometry() == "Generic") - return - new ProjDataInfoGenericNoArcCorr(scanner, - num_axial_pos_per_segment, - min_ring_difference, - max_ring_difference, - num_views,num_tangential_poss); + return new ProjDataInfoGenericNoArcCorr( + scanner, num_axial_pos_per_segment, min_ring_difference, max_ring_difference, num_views, num_tangential_poss); else if (scanner->get_scanner_geometry() == "Cylindrical" && arc_corrected) - 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); + 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, - tof_mash_factor); + 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, - const int tof_mash_factor) + 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)); + unique_ptr pdi( + ProjDataInfoCTI(scanner_sptr, span, max_delta, num_views, num_tangential_poss, arc_corrected, tof_mash_factor)); return pdi; } @@ -643,11 +617,11 @@ ProjDataInfo::construct_proj_data_info(const shared_ptr& scanner_sptr, ProjDataInfo* ProjDataInfo::ProjDataInfoGE(const shared_ptr& scanner, const int max_delta, - const int num_views, const int num_tangential_poss, + 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, @@ -655,141 +629,115 @@ 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, - tof_mash_factor); + 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, - tof_mash_factor); + 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 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(), 1) : 0; - - const bool arc_corrected = - ask("Is the data arc-corrected?",false); - - 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()); - - const bool is_GE = scanner_ptr->get_name().substr(0,2) == "GE"; - const bool is_Siemens = scanner_ptr->get_name().substr(0,6) == "Siemens"; - int span = is_GE ? 2 : (is_Siemens ? 11 : 1); - span = - ask_num("Span value : ", 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, - 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() <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(), 1) : 0; + + const bool arc_corrected = ask("Is the data arc-corrected?", false); + + 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()); + + const bool is_GE = scanner_ptr->get_name().substr(0, 2) == "GE"; + const bool is_Siemens = scanner_ptr->get_name().substr(0, 6) == "Siemens"; + int span = is_GE ? 2 : (is_Siemens ? 11 : 1); + span = ask_num("Span value : ", 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, 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())&& - (get_tof_mash_factor() == proj.get_tof_mash_factor()) && - (get_min_tof_pos_num() == proj.get_min_tof_pos_num()) && - (get_max_tof_pos_num() == proj.get_max_tof_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()) + && (get_tof_mash_factor() == proj.get_tof_mash_factor()) && (get_min_tof_pos_num() == proj.get_min_tof_pos_num()) + && (get_max_tof_pos_num() == proj.get_max_tof_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()); } 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); } @@ -801,8 +749,7 @@ operator !=(const root_type& that) const \warning Currently view and TOF 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; @@ -815,20 +762,18 @@ operator>=(const ProjDataInfo& proj_data_info) const if (proj_data_info.get_tof_mash_factor() != larger_proj_data_info.get_tof_mash_factor()) return false; - 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_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()) + 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_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()) return false; - for (int segment_num=proj_data_info.get_min_segment_num(); - segment_num<=proj_data_info.get_max_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) { - 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)) + 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; } @@ -837,15 +782,13 @@ operator>=(const ProjDataInfo& proj_data_info) const // 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) + 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); @@ -855,4 +798,3 @@ operator>=(const ProjDataInfo& proj_data_info) const } END_NAMESPACE_STIR - diff --git a/src/buildblock/ProjDataInfoBlocksOnCylindricalNoArcCorr.cxx b/src/buildblock/ProjDataInfoBlocksOnCylindricalNoArcCorr.cxx index d5c10ec6e..7e45fba12 100644 --- a/src/buildblock/ProjDataInfoBlocksOnCylindricalNoArcCorr.cxx +++ b/src/buildblock/ProjDataInfoBlocksOnCylindricalNoArcCorr.cxx @@ -39,20 +39,18 @@ using std::endl; using std::ends; START_NAMESPACE_STIR -ProjDataInfoBlocksOnCylindricalNoArcCorr:: -ProjDataInfoBlocksOnCylindricalNoArcCorr() +ProjDataInfoBlocksOnCylindricalNoArcCorr::ProjDataInfoBlocksOnCylindricalNoArcCorr() {} -ProjDataInfoBlocksOnCylindricalNoArcCorr:: -ProjDataInfoBlocksOnCylindricalNoArcCorr(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) -: ProjDataInfoGenericNoArcCorr(scanner_ptr, - num_axial_pos_per_segment, - min_ring_diff_v, max_ring_diff_v, - num_views, num_tangential_poss) +ProjDataInfoBlocksOnCylindricalNoArcCorr::ProjDataInfoBlocksOnCylindricalNoArcCorr( + 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) + : ProjDataInfoGenericNoArcCorr( + scanner_ptr, num_axial_pos_per_segment, min_ring_diff_v, max_ring_diff_v, num_views, num_tangential_poss) { if (is_null_ptr(scanner_ptr)) error("ProjDataInfoBlocksOnCylindricalNoArcCorr needs to be initialised with a non-empty Scanner"); @@ -60,8 +58,6 @@ ProjDataInfoBlocksOnCylindricalNoArcCorr(const shared_ptr scanner_ptr, error("ProjDataInfoBlocksOnCylindricalNoArcCorr needs to be initialised with a Scanner with appropriate geometry"); } - - ProjDataInfo* ProjDataInfoBlocksOnCylindricalNoArcCorr::clone() const { @@ -69,27 +65,23 @@ ProjDataInfoBlocksOnCylindricalNoArcCorr::clone() const } bool -ProjDataInfoBlocksOnCylindricalNoArcCorr:: -operator==(const self_type& that) const +ProjDataInfoBlocksOnCylindricalNoArcCorr::operator==(const self_type& that) const { if (!base_type::blindly_equals(&that)) return false; // TODOBLOCKS check crystal_map - return - true; + return true; } bool -ProjDataInfoBlocksOnCylindricalNoArcCorr:: -blindly_equals(const root_type * const that_ptr) const +ProjDataInfoBlocksOnCylindricalNoArcCorr::blindly_equals(const root_type* const that_ptr) const { - assert(dynamic_cast(that_ptr) != 0); - return - this->operator==(static_cast(*that_ptr)); + assert(dynamic_cast(that_ptr) != 0); + return this->operator==(static_cast(*that_ptr)); } std::string -ProjDataInfoBlocksOnCylindricalNoArcCorr::parameter_info() const +ProjDataInfoBlocksOnCylindricalNoArcCorr::parameter_info() const { std::ostringstream s; @@ -100,42 +92,38 @@ ProjDataInfoBlocksOnCylindricalNoArcCorr::parameter_info() const return s.str(); } -//!warning Use crystal map +//! warning Use crystal map Succeeded -ProjDataInfoBlocksOnCylindricalNoArcCorr:: -find_scanner_coordinates_given_cartesian_coordinates(int& det1, int& det2, int& ring1, int& ring2, - const CartesianCoordinate3D& c1, - const CartesianCoordinate3D& c2) const +ProjDataInfoBlocksOnCylindricalNoArcCorr::find_scanner_coordinates_given_cartesian_coordinates( + int& det1, int& det2, int& ring1, int& ring2, const CartesianCoordinate3D& c1, const CartesianCoordinate3D& c2) + const { DetectionPosition<> det_pos1; DetectionPosition<> det_pos2; - if (get_scanner_ptr()->find_detection_position_given_cartesian_coordinate(det_pos1, c1+this->z_shift)==Succeeded::no || - get_scanner_ptr()->find_detection_position_given_cartesian_coordinate(det_pos2, c2+this->z_shift)==Succeeded::no) - { - return Succeeded::no; - } + if (get_scanner_ptr()->find_detection_position_given_cartesian_coordinate(det_pos1, c1 + this->z_shift) == Succeeded::no + || get_scanner_ptr()->find_detection_position_given_cartesian_coordinate(det_pos2, c2 + this->z_shift) == Succeeded::no) + { + return Succeeded::no; + } det1 = det_pos1.tangential_coord(); det2 = det_pos2.tangential_coord(); ring1 = det_pos1.axial_coord(); ring2 = det_pos2.axial_coord(); - 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() && - det1!=det2) - ? Succeeded::yes : Succeeded::no; + return (ring1 >= 0 && ring1 < get_scanner_ptr()->get_num_rings() && ring2 >= 0 && ring2 < get_scanner_ptr()->get_num_rings() + && det1 != det2) + ? Succeeded::yes + : Succeeded::no; } void -ProjDataInfoBlocksOnCylindricalNoArcCorr:: -find_bin_given_cartesian_coordinates_of_detection(Bin& bin, - const CartesianCoordinate3D& coord_1, - const CartesianCoordinate3D& coord_2) const +ProjDataInfoBlocksOnCylindricalNoArcCorr::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; @@ -143,26 +131,20 @@ find_bin_given_cartesian_coordinates_of_detection(Bin& bin, 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) - { - bin.set_bin_value(-1); - return; - } + 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())); + assert(!(ring_a < 0 || ring_a >= get_scanner_ptr()->get_num_rings() || ring_b < 0 + || ring_b >= get_scanner_ptr()->get_num_rings())); const DetectionPositionPair<> det_pos_pair(DetectionPosition<>(det_num_a, ring_a), DetectionPosition<>(det_num_b, ring_b)); - if (!get_bin_for_det_pos_pair(bin, det_pos_pair).succeeded() || - bin.tangential_pos_num() < get_min_tangential_pos_num() || - bin.tangential_pos_num() > get_max_tangential_pos_num()) + if (!get_bin_for_det_pos_pair(bin, det_pos_pair).succeeded() || bin.tangential_pos_num() < get_min_tangential_pos_num() + || bin.tangential_pos_num() > get_max_tangential_pos_num()) bin.set_bin_value(-1); } diff --git a/src/buildblock/ProjDataInfoCylindrical.cxx b/src/buildblock/ProjDataInfoCylindrical.cxx index 2e4a73f83..8878214a0 100644 --- a/src/buildblock/ProjDataInfoCylindrical.cxx +++ b/src/buildblock/ProjDataInfoCylindrical.cxx @@ -51,40 +51,39 @@ using std::vector; START_NAMESPACE_STIR -ProjDataInfoCylindrical:: -ProjDataInfoCylindrical() +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) +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); + azimuthal_angle_sampling = static_cast(_PI / num_views); azimuthal_angle_offset = scanner_ptr->get_intrinsic_azimuthal_tilt(); // adjust offset for view-mashing { - const int num_detectors_per_ring = scanner_ptr->get_num_detectors_per_ring(); - if ((num_detectors_per_ring > 2) && (num_views*2 != num_detectors_per_ring)) + const int num_detectors_per_ring = scanner_ptr->get_num_detectors_per_ring(); + if ((num_detectors_per_ring > 2) && (num_views * 2 != num_detectors_per_ring)) { - if ((num_detectors_per_ring % (num_views*2)) != 0) + if ((num_detectors_per_ring % (num_views * 2)) != 0) { - warning(boost::format("Expected the number of views (%1%) to be related to the number of detectors per ring (%2%)," - " but this is not the case. Continuing anyway (but without adjusting the azimuthal angle offset).") - % num_views % num_detectors_per_ring); + warning( + boost::format("Expected the number of views (%1%) to be related to the number of detectors per ring (%2%)," + " but this is not the case. Continuing anyway (but without adjusting the azimuthal angle offset).") + % num_views % num_detectors_per_ring); } else { const int view_mashing = get_view_mashing_factor(); - const float offset_inc = static_cast(_PI/(num_detectors_per_ring/2) * (view_mashing-1)/2.F); - info(boost::format("Detected view-mashing factor %1% from the number of views (%2%) and the number of detectors per ring (%3%).\n" + const float offset_inc = static_cast(_PI / (num_detectors_per_ring / 2) * (view_mashing - 1) / 2.F); + info(boost::format("Detected view-mashing factor %1% from the number of views (%2%) and the number of detectors per " + "ring (%3%).\n" "Adjusting the azimuthal angle offset accordingly (an extra offset of %4% degrees)") % view_mashing % num_views % num_detectors_per_ring % (offset_inc * 180 / _PI)); @@ -93,224 +92,211 @@ ProjDataInfoCylindrical(const shared_ptr& scanner_ptr, } } - ring_radius.resize(0,0); + 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]) - { - 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); - swap(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); + 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]) - { - 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); - } + 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); + } } - // 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) - { - m_offset[segment_num] = - ((get_max_axial_pos_num(segment_num) + get_min_axial_pos_num(segment_num)) - *get_axial_sampling(segment_num) - )/2; - } + 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; + } } - // initialise ax_pos_num_offset + // 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 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 - segment,ax_pos. - - Ignoring the difficulties of axial compression for a second, it is clear that - for a given bin, there will be 2 rings as follows: - ring2 = get_m(bin)/ring_spacing + ring_diff/2 + (num_rings-1)/2 - 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 - 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) - 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 - - 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_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... - (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); - if (get_scanner_sptr()->get_scanner_geometry()=="Cylindrical") - { - // 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); - } - } + 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 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 + segment,ax_pos. + + Ignoring the difficulties of axial compression for a second, it is clear that + for a given bin, there will be 2 rings as follows: + ring2 = get_m(bin)/ring_spacing + ring_diff/2 + (num_rings-1)/2 + 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 + 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) + 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 + + 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_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... + (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); + if (get_scanner_sptr()->get_scanner_geometry() == "Cylindrical") + { + // 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 (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()); - - // 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 - // 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)); - // 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); - - 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]) + { + 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 + // 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)); + // 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); + + 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]) + { #if 0 std::cerr << "ring diff " << ring_diff << " stored in s:" << segment_num << std::endl; #endif - ring_diff_to_segment_num[ring_diff] = segment_num; - break; + ring_diff_to_segment_num[ring_diff] = segment_num; + 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) { - 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); - // check that it was integer - if (get_scanner_sptr()->get_scanner_geometry()=="Cylindrical") + 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) { - assert(fabs(ring1_plus_ring2 - ring1_plus_ring2_float) < 1E-4) ; + 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); + // check that it was integer + if (get_scanner_sptr()->get_scanner_geometry() == "Cylindrical") + { + 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; + } } - segment_axial_pos_to_ring1_plus_ring2[s_num][ax_pos_num] = ring1_plus_ring2; - } } - } // now also initialise the segment_axial_pos_to_ring_pair table if (sampling_corresponds_to_physical_rings) { allocate_segment_axial_pos_to_ring_pair(); - for (int s_num=get_min_segment_num(); s_num<=get_max_segment_num(); ++s_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); - for (int ax_pos_num=min_ax_pos_num; ax_pos_num<=max_ax_pos_num; ++ax_pos_num) + for (int ax_pos_num = min_ax_pos_num; ax_pos_num <= max_ax_pos_num; ++ax_pos_num) { compute_segment_axial_pos_to_ring_pair(s_num, ax_pos_num); } @@ -323,35 +309,29 @@ initialise_ring_diff_arrays() const // we use, another thread can check the value of the variable before this function // is done. 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"); @@ -362,113 +342,95 @@ 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_offset(const float angle_v) +ProjDataInfoCylindrical::set_azimuthal_angle_offset(const float angle_v) { - azimuthal_angle_offset = angle_v; + azimuthal_angle_offset = angle_v; } void -ProjDataInfoCylindrical:: -set_azimuthal_angle_sampling(const float angle_v) +ProjDataInfoCylindrical::set_azimuthal_angle_sampling(const float angle_v) { - azimuthal_angle_sampling = 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) +ProjDataInfoCylindrical::set_num_views(const int new_num_views) { - const float old_azimuthal_angle_range = - this->get_azimuthal_angle_sampling() * this->get_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 +ProjDataInfoCylindrical::allocate_segment_axial_pos_to_ring_pair() const { - segment_axial_pos_to_ring_pair = - VectorWithOffset > > - (get_min_segment_num(), get_max_segment_num()); + 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) + 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)); + 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 @@ -479,117 +441,106 @@ 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 ) + 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)); + 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)); } } void -ProjDataInfoCylindrical:: -set_tof_mash_factor(const int new_num) +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(); + 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) - { - new_min_ring_diff[segment_num] = this->min_ring_diff[segment_num]; - new_max_ring_diff[segment_num] = this->max_ring_diff[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(), - false);// needs to set "swapped" to false given above code -} + 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 +} #if 0 // KT disabled these as untested (and unused) @@ -667,20 +618,20 @@ get_LOR_as_two_points_alt(CartesianCoordinate3D& coord_1, #endif string -ProjDataInfoCylindrical::parameter_info() const +ProjDataInfoCylindrical::parameter_info() const { std::ostringstream s; 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 d46f5cde8..e490da566 100644 --- a/src/buildblock/ProjDataInfoCylindricalArcCorr.cxx +++ b/src/buildblock/ProjDataInfoCylindricalArcCorr.cxx @@ -16,7 +16,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 @@ -37,34 +37,32 @@ using std::endl; using std::ends; using std::string; - START_NAMESPACE_STIR -ProjDataInfoCylindricalArcCorr:: ProjDataInfoCylindricalArcCorr() +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, - 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) - +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); + 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;} - - +{ + bin_size = new_tangential_sampling; +} ProjDataInfo* ProjDataInfoCylindricalArcCorr::clone() const @@ -72,28 +70,23 @@ 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 +ProjDataInfoCylindricalArcCorr::blindly_equals(const root_type* const that_ptr) const { - assert(dynamic_cast(that_ptr) != 0); - return - this->operator==(static_cast(*that_ptr)); + assert(dynamic_cast(that_ptr) != 0); + return this->operator==(static_cast(*that_ptr)); } string -ProjDataInfoCylindricalArcCorr::parameter_info() const +ProjDataInfoCylindricalArcCorr::parameter_info() const { std::ostringstream s; @@ -105,15 +98,13 @@ ProjDataInfoCylindricalArcCorr::parameter_info() const return s.str(); } - Bin -ProjDataInfoCylindricalArcCorr:: -get_bin(const LOR& lor,const double delta_time) const +ProjDataInfoCylindricalArcCorr::get_bin(const LOR& lor, const double delta_time) const { if (delta_time != 0) { - error("TODO NO TOF YET"); + error("TODO NO TOF YET"); } Bin bin; @@ -124,22 +115,20 @@ get_bin(const LOR& lor,const double delta_time) const return bin; } - // first find view - //PW phi-intrinsic_tilt included to get the accurate bin.view_number. - bin.view_num() = round(to_0_2pi(lor_coords.phi()-get_azimuthal_angle_offset()) / get_azimuthal_angle_sampling()); - assert(bin.view_num()>=0); - const bool swap_direction = - bin.view_num() > get_max_view_num(); + // first find view + // PW phi-intrinsic_tilt included to get the accurate bin.view_number. + bin.view_num() = round(to_0_2pi(lor_coords.phi() - get_azimuthal_angle_offset()) / get_azimuthal_angle_sampling()); + assert(bin.view_num() >= 0); + const bool swap_direction = bin.view_num() > get_max_view_num(); if (swap_direction) - bin.view_num()-=get_num_views(); - assert(bin.view_num() get_max_tangential_pos_num()) + 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; @@ -175,63 +164,57 @@ get_bin(const LOR& lor,const double delta_time) const #else // find nearest segment { - const float delta = - (swap_direction - ? lor_coords.z1()-lor_coords.z2() - : lor_coords.z2()-lor_coords.z1() - )/get_ring_spacing(); + const float delta + = (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 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) + bin.set_bin_value(-1); + return bin; + } + if (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; - } + // 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 - 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())) +# 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.set_bin_value(-1); + return bin; } } #endif @@ -240,4 +223,3 @@ get_bin(const LOR& lor,const double delta_time) const return bin; } END_NAMESPACE_STIR - diff --git a/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx b/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx index 62420eb5d..93b2e4916 100644 --- a/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx +++ b/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx @@ -16,7 +16,7 @@ \file \ingroup projdata - \brief Implementation of non-inline functions of class + \brief Implementation of non-inline functions of class stir::ProjDataInfoCylindricalNoArcCorr \author Nikos Efthimiou @@ -43,33 +43,32 @@ using std::pair; using std::vector; START_NAMESPACE_STIR -ProjDataInfoCylindricalNoArcCorr:: -ProjDataInfoCylindricalNoArcCorr() +ProjDataInfoCylindricalNoArcCorr::ProjDataInfoCylindricalNoArcCorr() {} -ProjDataInfoCylindricalNoArcCorr:: -ProjDataInfoCylindricalNoArcCorr(const shared_ptr scanner_sptr, - 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_sptr, - 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(const shared_ptr scanner_sptr, + 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_sptr, 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) { if (!scanner_sptr) error("ProjDataInfoCylindricalNoArcCorr: first argument (scanner_ptr) is zero"); if (num_tangential_poss > scanner_sptr->get_max_num_non_arccorrected_bins()) - error("ProjDataInfoCylindricalNoArcCorr: number of tangential positions exceeds the maximum number of non arc-corrected bins set for the scanner."); + error("ProjDataInfoCylindricalNoArcCorr: number of tangential positions exceeds the maximum number of non arc-corrected bins " + "set for the scanner."); uncompressed_view_tangpos_to_det1det2_initialised = false; det1det2_to_uncompressed_view_tangpos_initialised = false; - if(scanner_sptr->is_tof_ready()) + if (scanner_sptr->is_tof_ready()) set_tof_mash_factor(tof_mash_factor); #ifdef STIR_OPENMP_SAFE_BUT_SLOW this->initialise_uncompressed_view_tangpos_to_det1det2(); @@ -77,25 +76,25 @@ ProjDataInfoCylindricalNoArcCorr(const shared_ptr scanner_sptr, #endif } -ProjDataInfoCylindricalNoArcCorr:: -ProjDataInfoCylindricalNoArcCorr(const shared_ptr scanner_sptr, - 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) - : ProjDataInfoCylindricalNoArcCorr(scanner_sptr, - scanner_sptr ? scanner_sptr->get_effective_ring_radius() : 0.F, // avoid segfault if scanner_sptr==0 - scanner_sptr ? static_cast(_PI/scanner_sptr->get_num_detectors_per_ring()) : 0.F, - num_axial_pos_per_segment, - min_ring_diff_v, max_ring_diff_v, - num_views, num_tangential_poss, - tof_mash_factor) +ProjDataInfoCylindricalNoArcCorr::ProjDataInfoCylindricalNoArcCorr(const shared_ptr scanner_sptr, + 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) + : ProjDataInfoCylindricalNoArcCorr(scanner_sptr, + scanner_sptr ? scanner_sptr->get_effective_ring_radius() + : 0.F, // avoid segfault if scanner_sptr==0 + scanner_sptr ? static_cast(_PI / scanner_sptr->get_num_detectors_per_ring()) : 0.F, + num_axial_pos_per_segment, + min_ring_diff_v, + max_ring_diff_v, + num_views, + num_tangential_poss, + tof_mash_factor) {} - - - ProjDataInfo* ProjDataInfoCylindricalNoArcCorr::clone() const { @@ -103,28 +102,22 @@ ProjDataInfoCylindricalNoArcCorr::clone() const } 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 +ProjDataInfoCylindricalNoArcCorr::blindly_equals(const root_type* const that_ptr) const { - assert(dynamic_cast(that_ptr) != 0); - return - this->operator==(static_cast(*that_ptr)); + assert(dynamic_cast(that_ptr) != 0); + return this->operator==(static_cast(*that_ptr)); } - string -ProjDataInfoCylindricalNoArcCorr::parameter_info() const +ProjDataInfoCylindricalNoArcCorr::parameter_info() const { std::ostringstream s; @@ -135,8 +128,7 @@ ProjDataInfoCylindricalNoArcCorr::parameter_info() const } float -ProjDataInfoCylindricalNoArcCorr:: -get_psi_offset() const +ProjDataInfoCylindricalNoArcCorr::get_psi_offset() const { return this->get_scanner_ptr()->get_intrinsic_azimuthal_tilt(); } @@ -170,72 +162,69 @@ get_psi_offset() 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); #ifndef NDEBUG // check views range from 0 to Pi - //PW Supports intrinsic tilt. + // PW Supports intrinsic tilt. const float v_offset = get_azimuthal_angle_offset(); - assert(fabs(get_phi(Bin(0,0,0,0))-v_offset) < 1.E-4); - assert(fabs(get_phi(Bin(0,get_num_views(),0,0)) - v_offset - _PI) < 1.E-4); + assert(fabs(get_phi(Bin(0, 0, 0, 0)) - v_offset) < 1.E-4); + assert(fabs(get_phi(Bin(0, get_num_views(), 0, 0)) - v_offset - _PI) < 1.E-4); #endif - 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) + 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); + "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[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) + uncompressed_view_tangpos_to_det1det2.grow(0, num_detectors / 2 - 1); + for (int v_num = 0; v_num <= num_detectors / 2 - 1; ++v_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].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) + { + /* + 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; + } } - } - // 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 -#pragma omp atomic write + // 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 +# pragma omp atomic write #endif 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) + if (num_detectors % 2 != 0) { error("Number of detectors per ring should be even but is %d", num_detectors); } @@ -245,115 +234,110 @@ initialise_det1det2_to_uncompressed_view_tangpos() const } #ifndef NDEBUG // check views range from 0 to Pi - //PW Supports intrinsic tilt. + // PW Supports intrinsic tilt. const float v_offset = get_azimuthal_angle_offset(); - assert(fabs(get_phi(Bin(0,0,0,0)) - v_offset) < 1.E-4); - assert(fabs(get_phi(Bin(0,get_max_view_num()+1,0,0)) - v_offset - _PI) < 1.E-4); + assert(fabs(get_phi(Bin(0, 0, 0, 0)) - v_offset) < 1.E-4); + assert(fabs(get_phi(Bin(0, get_max_view_num() + 1, 0, 0)) - v_offset - _PI) < 1.E-4); #endif - //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; + // 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; - - /* 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) - Using the latter interchanges det_num1 and det_num2, and this leaves - the LOR the same in the 2D case. However, in 3D this interchanges the rings - 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) - { - tang_pos_num = num_detectors - tang_pos_num; - swap_detectors = 1; - } - else - { - swap_detectors = 0; - } - } - else - { - view_num -= max_num_views; - if (tang_pos_num >= max_num_views) - { - tang_pos_num -= num_detectors; - swap_detectors = 0; - } - else + det1det2_to_uncompressed_view_tangpos.grow(0, num_detectors - 1); + for (int det1_num = 0; det1_num < num_detectors; ++det1_num) + { + det1det2_to_uncompressed_view_tangpos[det1_num].grow(0, num_detectors - 1); + + for (int det2_num = 0; det2_num < num_detectors; ++det2_num) { - tang_pos_num *= -1; - swap_detectors = 1; + if (det1_num == det2_num) + continue; + /* + This somewhat obscure formula was obtained by inverting the code for + get_det_num_pair_for_view_tangential_pos_num() + This can be simplified (especially all the branching later on), but + as we execute this code only occasionally, it's probably not worth it. + */ + int swap_detectors; + /* + Note for implementation: avoid using % with negative numbers + so add num_detectors before doing modulo 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) + Using the latter interchanges det_num1 and det_num2, and this leaves + the LOR the same in the 2D case. However, in 3D this interchanges the rings + 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) + { + tang_pos_num = num_detectors - tang_pos_num; + swap_detectors = 1; + } + else + { + swap_detectors = 0; + } + } + else + { + view_num -= max_num_views; + if (tang_pos_num >= max_num_views) + { + tang_pos_num -= num_detectors; + swap_detectors = 0; + } + 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].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; } - } - // 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 -#pragma omp atomic write + // 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 +# pragma omp atomic write #endif det1det2_to_uncompressed_view_tangpos_initialised = true; } unsigned int -ProjDataInfoCylindricalNoArcCorr:: -get_num_det_pos_pairs_for_bin(const Bin& bin, bool ignore_non_spatial_dimensions) const +ProjDataInfoCylindricalNoArcCorr::get_num_det_pos_pairs_for_bin(const Bin& bin, bool ignore_non_spatial_dimensions) const { - return - get_num_ring_pairs_for_segment_axial_pos_num(bin.segment_num(), - bin.axial_pos_num())* - get_view_mashing_factor()* - (ignore_non_spatial_dimensions ? 1 : std::max(1,get_tof_mash_factor())); + return get_num_ring_pairs_for_segment_axial_pos_num(bin.segment_num(), bin.axial_pos_num()) * get_view_mashing_factor() + * (ignore_non_spatial_dimensions ? 1 : std::max(1, get_tof_mash_factor())); } void -ProjDataInfoCylindricalNoArcCorr:: -get_all_det_pos_pairs_for_bin(vector >& dps, - const Bin& bin, - bool ignore_non_spatial_dimensions) const +ProjDataInfoCylindricalNoArcCorr::get_all_det_pos_pairs_for_bin(vector>& dps, + const Bin& bin, + bool ignore_non_spatial_dimensions) const { this->initialise_uncompressed_view_tangpos_to_det1det2_if_not_done_yet(); dps.resize(get_num_det_pos_pairs_for_bin(bin, ignore_non_spatial_dimensions)); - const ProjDataInfoCylindrical::RingNumPairs& ring_pairs = - get_all_ring_pairs_for_segment_axial_pos_num(bin.segment_num(), - bin.axial_pos_num()); + const ProjDataInfoCylindrical::RingNumPairs& ring_pairs + = 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); + assert(get_min_view_num() == 0); int min_timing_pos_num = 0; int max_timing_pos_num = 0; @@ -362,23 +346,20 @@ get_all_det_pos_pairs_for_bin(vector >& dps, // not sure how to handle even tof mashing assert(!is_tof_data() || (get_tof_mash_factor() % 2 == 1)); // TODOTOF // we will need to add all (unmashed) timing_pos for the current bin - min_timing_pos_num = bin.timing_pos_num()*get_tof_mash_factor() - (get_tof_mash_factor() / 2); - max_timing_pos_num = bin.timing_pos_num()*get_tof_mash_factor() + (get_tof_mash_factor() / 2); + min_timing_pos_num = bin.timing_pos_num() * get_tof_mash_factor() - (get_tof_mash_factor() / 2); + max_timing_pos_num = bin.timing_pos_num() * get_tof_mash_factor() + (get_tof_mash_factor() / 2); } - 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(); + 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; + 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 (auto rings_iter = ring_pairs.begin(); rings_iter != ring_pairs.end(); ++rings_iter) { - for (int uncompressed_timing_pos_num = min_timing_pos_num; - uncompressed_timing_pos_num <= max_timing_pos_num; + for (int uncompressed_timing_pos_num = min_timing_pos_num; uncompressed_timing_pos_num <= max_timing_pos_num; ++uncompressed_timing_pos_num) { assert(current_dp_num < get_num_det_pos_pairs_for_bin(bin, ignore_non_spatial_dimensions)); @@ -395,14 +376,13 @@ get_all_det_pos_pairs_for_bin(vector >& dps, } Succeeded -ProjDataInfoCylindricalNoArcCorr:: -find_scanner_coordinates_given_cartesian_coordinates(int& det1, int& det2, int& ring1, int& ring2, - const CartesianCoordinate3D& c1, - const CartesianCoordinate3D& c2) const +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(); + 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; @@ -438,61 +418,57 @@ 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()-this->get_psi_offset())/(2.*_PI/num_detectors)), num_detectors); - det2 = modulo(round((cyl_coords.p2().psi()-this->get_psi_offset())/(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() - this->get_psi_offset()) / (2. * _PI / num_detectors)), num_detectors); + det2 = modulo(round((cyl_coords.p2().psi() - this->get_psi_offset()) / (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 +void +ProjDataInfoCylindricalNoArcCorr::find_cartesian_coordinates_of_detection(CartesianCoordinate3D& coord_1, + CartesianCoordinate3D& coord_2, + const Bin& bin) const { - // find detectors + // find detectors DetectionPositionPair<> dpp; get_det_pos_pair_for_bin(dpp, bin); - + /* TODO best to use Scanner::get_coordinate_for_det_pos(). Sadly, the latter is not yet implemented for Cylindrical scanners. */ // find corresponding cartesian coordinates - find_cartesian_coordinates_given_scanner_coordinates(coord_1,coord_2, - dpp.pos1().axial_coord(), dpp.pos2().axial_coord(), - dpp.pos1().tangential_coord(), dpp.pos2().tangential_coord(), + find_cartesian_coordinates_given_scanner_coordinates(coord_1, + coord_2, + dpp.pos1().axial_coord(), + dpp.pos2().axial_coord(), + dpp.pos1().tangential_coord(), + dpp.pos2().tangential_coord(), dpp.timing_pos()); } - 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 int timing_pos_num) const +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 int timing_pos_num) const { - const int num_detectors_per_ring = - get_scanner_ptr()->get_num_detectors_per_ring(); + const int num_detectors_per_ring = get_scanner_ptr()->get_num_detectors_per_ring(); int d1, d2, r1, r2; int tpos = timing_pos_num; @@ -500,20 +476,20 @@ find_cartesian_coordinates_given_scanner_coordinates (CartesianCoordinate3Dinitialise_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; tpos *= -1; - } + } else - { + { d1 = det1; d2 = det2; r1 = Ring_A; r2 = Ring_B; - } + } #if 0 const float df1 = (2.*_PI/num_detectors_per_ring)*(det1); @@ -531,62 +507,51 @@ find_cartesian_coordinates_given_scanner_coordinates (CartesianCoordinate3D cyl_coords(get_scanner_ptr()->get_effective_ring_radius()); - cyl_coords.p1().psi() = to_0_2pi(static_cast((2.*_PI/num_detectors_per_ring)*(d1)) + this->get_psi_offset()); - cyl_coords.p2().psi() = to_0_2pi(static_cast((2.*_PI/num_detectors_per_ring)*(d2)) + this->get_psi_offset()); - 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); + cyl_coords.p1().psi() = to_0_2pi(static_cast((2. * _PI / num_detectors_per_ring) * (d1)) + this->get_psi_offset()); + cyl_coords.p2().psi() = to_0_2pi(static_cast((2. * _PI / num_detectors_per_ring) * (d2)) + this->get_psi_offset()); + 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 if (tpos < 0) std::swap(coord_1, coord_2); } -void -ProjDataInfoCylindricalNoArcCorr:: -find_bin_given_cartesian_coordinates_of_detection(Bin& bin, - const CartesianCoordinate3D& coord_1, - const CartesianCoordinate3D& coord_2) const +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) - { - bin.set_bin_value(-1); - return; - } + + // 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 double delta_time) const +ProjDataInfoCylindricalNoArcCorr::get_bin(const LOR& lor, const double delta_time) const { Bin bin; #ifndef STIR_DEVEL @@ -597,26 +562,24 @@ get_bin(const LOR& lor,const double delta_time) const 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 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()-this->get_psi_offset())/(2.*_PI/num_detectors_per_ring)),num_detectors_per_ring); - const int det2 = modulo(round((cyl_coords.p2().psi()-this->get_psi_offset())/(2.*_PI/num_detectors_per_ring)),num_detectors_per_ring); + const int det1 = modulo(round((cyl_coords.p1().psi() - this->get_psi_offset()) / (2. * _PI / num_detectors_per_ring)), + num_detectors_per_ring); + const int det2 = modulo(round((cyl_coords.p2().psi() - this->get_psi_offset()) / (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()) + 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; @@ -627,7 +590,6 @@ get_bin(const LOR& lor,const double delta_time) const return bin; } - #else LORInAxialAndNoArcCorrSinogramCoordinates lor_coords; if (lor.change_representation(lor_coords, get_ring_radius()) == Succeeded::no) @@ -636,30 +598,28 @@ get_bin(const LOR& lor,const double delta_time) const 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. - //PW Accurate bin view number = phi - intrinsic_tilt. + // PW Accurate bin view number = phi - intrinsic_tilt. bin.view_num() = round(to_0_2pi(lor_coords.phi() - get_azimuthal_angle_offset()) / 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()) + 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 @@ -686,79 +646,71 @@ get_bin(const LOR& lor,const double delta_time) const bin.set_bin_value(-1); return bin; } -#else +# else // find nearest segment { - if (delta_time!=0) + 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(); + const float delta + = (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 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) + bin.set_bin_value(-1); + return bin; + } + if (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; - } + // 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 - 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())) +# 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.set_bin_value(-1); + return bin; } } -#endif +# endif bin.set_bin_value(1); return bin; #endif } - END_NAMESPACE_STIR - diff --git a/src/buildblock/ProjDataInfoGeneric.cxx b/src/buildblock/ProjDataInfoGeneric.cxx old mode 100755 new mode 100644 index 6f166ae41..22cd7efa6 --- a/src/buildblock/ProjDataInfoGeneric.cxx +++ b/src/buildblock/ProjDataInfoGeneric.cxx @@ -26,7 +26,6 @@ \author Michael Roethlisberger */ - #include "stir/ProjDataInfoGeneric.h" #include "stir/LORCoordinates.h" #include @@ -45,21 +44,18 @@ using std::endl; START_NAMESPACE_STIR -ProjDataInfoGeneric:: -ProjDataInfoGeneric() +ProjDataInfoGeneric::ProjDataInfoGeneric() {} - -ProjDataInfoGeneric:: -ProjDataInfoGeneric(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) -{ -} +ProjDataInfoGeneric::ProjDataInfoGeneric(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) +{} #if 0 /*! Default implementation checks common variables. Needs to be overloaded. @@ -78,8 +74,7 @@ blindly_equals(const root_type * const that) const #endif void -ProjDataInfoGeneric:: -set_num_views(const int new_num_views) +ProjDataInfoGeneric::set_num_views(const int new_num_views) { if (new_num_views != get_num_views()) error("ProjDataInfoGeneric::set_num_views not supported"); @@ -96,38 +91,36 @@ set_ring_spacing(float ring_spacing_v) //! warning Find lor from cartesian coordinates of detector pair void -ProjDataInfoGeneric:: -get_LOR(LORInAxialAndNoArcCorrSinogramCoordinates& lor, - const Bin& bin) const +ProjDataInfoGeneric::get_LOR(LORInAxialAndNoArcCorrSinogramCoordinates& lor, const Bin& bin) const { - CartesianCoordinate3D _p1; - CartesianCoordinate3D _p2; - find_cartesian_coordinates_of_detection(_p1, _p2, bin); - - _p1.z()+=z_shift.z(); - _p2.z()+=z_shift.z(); - - LORAs2Points lor_as_2_points(_p1, _p2); - const double R = sqrt(max(square(_p1.x())+square(_p1.y()), square(_p2.x())+square(_p2.y()))); - - lor_as_2_points.change_representation(lor, R); + CartesianCoordinate3D _p1; + CartesianCoordinate3D _p2; + find_cartesian_coordinates_of_detection(_p1, _p2, bin); + + _p1.z() += z_shift.z(); + _p2.z() += z_shift.z(); + + LORAs2Points lor_as_2_points(_p1, _p2); + const double R = sqrt(max(square(_p1.x()) + square(_p1.y()), square(_p2.x()) + square(_p2.y()))); + + lor_as_2_points.change_representation(lor, R); } std::string -ProjDataInfoGeneric::parameter_info() const +ProjDataInfoGeneric::parameter_info() const { std::ostringstream s; s << ProjDataInfo::parameter_info(); // TODOBLOCK Cylindrical has the following which doesn't make sense for Generic, so repeat code - //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 << '(' << get_min_ring_difference(segment_num) << ',' << get_max_ring_difference(segment_num) <<')'; - } + for (int segment_num = get_min_segment_num(); segment_num <= get_max_segment_num(); ++segment_num) + { + s << '(' << get_min_ring_difference(segment_num) << ',' << get_max_ring_difference(segment_num) << ')'; + } s << std::endl; return s.str(); } diff --git a/src/buildblock/ProjDataInfoGenericNoArcCorr.cxx b/src/buildblock/ProjDataInfoGenericNoArcCorr.cxx index 6d2b16abd..6b4ea7de4 100644 --- a/src/buildblock/ProjDataInfoGenericNoArcCorr.cxx +++ b/src/buildblock/ProjDataInfoGenericNoArcCorr.cxx @@ -16,7 +16,7 @@ \ingroup projdata \brief Implementation of non-inline functions of class stir::ProjDataInfoGenericNoArcCorr - + \author Kris Thielemans \author Palak Wadhwa \author Parisa Khateri @@ -41,28 +41,26 @@ using std::endl; using std::ends; START_NAMESPACE_STIR -ProjDataInfoGenericNoArcCorr:: -ProjDataInfoGenericNoArcCorr() +ProjDataInfoGenericNoArcCorr::ProjDataInfoGenericNoArcCorr() {} -ProjDataInfoGenericNoArcCorr:: -ProjDataInfoGenericNoArcCorr(const shared_ptr scanner_sptr, - 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) -: ProjDataInfoGeneric(scanner_sptr, - num_axial_pos_per_segment, - min_ring_diff_v, max_ring_diff_v, - num_views, num_tangential_poss) +ProjDataInfoGenericNoArcCorr::ProjDataInfoGenericNoArcCorr(const shared_ptr scanner_sptr, + 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) + : ProjDataInfoGeneric( + scanner_sptr, num_axial_pos_per_segment, min_ring_diff_v, max_ring_diff_v, num_views, num_tangential_poss) { if (!scanner_sptr) error("ProjDataInfoGenericNoArcCorr: first argument (scanner_ptr) is zero"); if (num_tangential_poss > scanner_sptr->get_max_num_non_arccorrected_bins()) - error("ProjDataInfoGenericNoArcCorr: number of tangential positions exceeds the maximum number of non arc-corrected bins set for the scanner."); + error("ProjDataInfoGenericNoArcCorr: number of tangential positions exceeds the maximum number of non arc-corrected bins set " + "for the scanner."); if (scanner_sptr->get_max_num_views() != num_views) error("ProjDataInfoGenericNoArcCorr: view mashing is not supported"); - + uncompressed_view_tangpos_to_det1det2_initialised = false; det1det2_to_uncompressed_view_tangpos_initialised = false; #ifdef STIR_OPENMP_SAFE_BUT_SLOW @@ -71,14 +69,11 @@ ProjDataInfoGenericNoArcCorr(const shared_ptr scanner_sptr, #endif // find shift between "new" centre-of-scanner and "old" centre-of-first-ring coordinate system - this->z_shift.z()=this->get_scanner_ptr()->get_coordinate_for_det_pos(DetectionPosition<>(0,0,0)).z(); - this->z_shift.y()=0; - this->z_shift.x()=0; + this->z_shift.z() = this->get_scanner_ptr()->get_coordinate_for_det_pos(DetectionPosition<>(0, 0, 0)).z(); + this->z_shift.y() = 0; + this->z_shift.x() = 0; } - - - ProjDataInfo* ProjDataInfoGenericNoArcCorr::clone() const { @@ -86,8 +81,7 @@ ProjDataInfoGenericNoArcCorr::clone() const } bool -ProjDataInfoGenericNoArcCorr:: -operator==(const self_type& that) const +ProjDataInfoGenericNoArcCorr::operator==(const self_type& that) const { if (!base_type::blindly_equals(&that)) return false; @@ -95,16 +89,14 @@ operator==(const self_type& that) const } bool -ProjDataInfoGenericNoArcCorr:: -blindly_equals(const root_type * const that_ptr) const +ProjDataInfoGenericNoArcCorr::blindly_equals(const root_type* const that_ptr) const { - assert(dynamic_cast(that_ptr) != 0); - return - this->operator==(static_cast(*that_ptr)); + assert(dynamic_cast(that_ptr) != 0); + return this->operator==(static_cast(*that_ptr)); } std::string -ProjDataInfoGenericNoArcCorr::parameter_info() const +ProjDataInfoGenericNoArcCorr::parameter_info() const { std::ostringstream s; @@ -149,64 +141,61 @@ ProjDataInfoGenericNoArcCorr::parameter_info() const //! build look-up table for get_view_tangential_pos_num_for_det_num_pair() void -ProjDataInfoGenericNoArcCorr:: -initialise_uncompressed_view_tangpos_to_det1det2() const +ProjDataInfoGenericNoArcCorr::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(); - assert(num_detectors%2 == 0); + const int num_detectors = get_scanner_ptr()->get_num_detectors_per_ring(); + assert(num_detectors % 2 == 0); - const int min_tang_pos_num = -(num_detectors/2)+1; - const int max_tang_pos_num = -(num_detectors/2)+num_detectors; + 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) + 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); + "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[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) + uncompressed_view_tangpos_to_det1det2.grow(0, num_detectors / 2 - 1); + for (int v_num = 0; v_num <= num_detectors / 2 - 1; ++v_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].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) + { + /* + 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; + } } - } - // 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 -#pragma omp atomic write + // 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 +# pragma omp atomic write #endif uncompressed_view_tangpos_to_det1det2_initialised = true; } void -ProjDataInfoGenericNoArcCorr:: -initialise_det1det2_to_uncompressed_view_tangpos() const +ProjDataInfoGenericNoArcCorr::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) + if (num_detectors % 2 != 0) { error("Number of detectors per ring should be even but is %d", num_detectors); } @@ -215,169 +204,156 @@ initialise_det1det2_to_uncompressed_view_tangpos() const error("Minimum view number should currently be zero to be able to use get_view_tangential_pos_num_for_det_num_pair()"); } + // 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; - //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; - - /* 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) - Using the latter interchanges det_num1 and det_num2, and this leaves - the LOR the same in the 2D case. However, in 3D this interchanges the rings - 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) - { - tang_pos_num = num_detectors - tang_pos_num; - swap_detectors = 1; - } - else - { - swap_detectors = 0; - } - } - else - { - view_num -= max_num_views; - if (tang_pos_num >= max_num_views) - { - tang_pos_num -= num_detectors; - swap_detectors = 0; - } - else + det1det2_to_uncompressed_view_tangpos[det1_num].grow(0, num_detectors - 1); + + for (int det2_num = 0; det2_num < num_detectors; ++det2_num) { - tang_pos_num *= -1; - swap_detectors = 1; + if (det1_num == det2_num) + continue; + /* + This somewhat obscure formula was obtained by inverting the code for + get_det_num_pair_for_view_tangential_pos_num() + This can be simplified (especially all the branching later on), but + as we execute this code only occasionally, it's probably not worth it. + */ + int swap_detectors; + /* + Note for implementation: avoid using % with negative numbers + so add num_detectors before doing modulo 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) + Using the latter interchanges det_num1 and det_num2, and this leaves + the LOR the same in the 2D case. However, in 3D this interchanges the rings + 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) + { + tang_pos_num = num_detectors - tang_pos_num; + swap_detectors = 1; + } + else + { + swap_detectors = 0; + } + } + else + { + view_num -= max_num_views; + if (tang_pos_num >= max_num_views) + { + tang_pos_num -= num_detectors; + swap_detectors = 0; + } + 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].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; } - } - // 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 -#pragma omp atomic write + // 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 +# pragma omp atomic write #endif det1det2_to_uncompressed_view_tangpos_initialised = true; } unsigned int -ProjDataInfoGenericNoArcCorr:: -get_num_det_pos_pairs_for_bin(const Bin& bin) const +ProjDataInfoGenericNoArcCorr::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(); + return get_num_ring_pairs_for_segment_axial_pos_num(bin.segment_num(), bin.axial_pos_num()) * get_view_mashing_factor(); } void -ProjDataInfoGenericNoArcCorr:: -get_all_det_pos_pairs_for_bin(std::vector >& dps, - const Bin& bin) const +ProjDataInfoGenericNoArcCorr::get_all_det_pos_pairs_for_bin(std::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 ProjDataInfoGeneric::RingNumPairs& ring_pairs = - get_all_ring_pairs_for_segment_axial_pos_num(bin.segment_num(), - bin.axial_pos_num()); + const ProjDataInfoGeneric::RingNumPairs& ring_pairs + = 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); + 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(); + 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 (ProjDataInfoGeneric::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; - } + 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 (ProjDataInfoGeneric::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(current_dp_num == get_num_det_pos_pairs_for_bin(bin)); } void -ProjDataInfoGenericNoArcCorr:: -find_cartesian_coordinates_of_detection( - CartesianCoordinate3D& coord_1, - CartesianCoordinate3D& coord_2, - const Bin& bin) const +ProjDataInfoGenericNoArcCorr::find_cartesian_coordinates_of_detection(CartesianCoordinate3D& coord_1, + CartesianCoordinate3D& coord_2, + const Bin& bin) const { - // find detectors + // 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); return; } void -ProjDataInfoGenericNoArcCorr:: -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 +ProjDataInfoGenericNoArcCorr::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 { - assert(0<=det1); - assert(det1get_num_detectors_per_ring()); - assert(0<=det2); - assert(det2get_num_detectors_per_ring()); + assert(0 <= det1); + assert(det1 < get_scanner_ptr()->get_num_detectors_per_ring()); + assert(0 <= det2); + assert(det2 < get_scanner_ptr()->get_num_detectors_per_ring()); - DetectionPosition<> det_pos1; - DetectionPosition<> det_pos2; + DetectionPosition<> det_pos1; + DetectionPosition<> det_pos2; det_pos1.tangential_coord() = det1; det_pos2.tangential_coord() = det2; det_pos1.axial_coord() = Ring_A; @@ -389,48 +365,44 @@ find_cartesian_coordinates_given_scanner_coordinates(CartesianCoordinate3D& lor, const double delta_time) const +ProjDataInfoGenericNoArcCorr::get_bin(const LOR& lor, const double delta_time) const { if (delta_time != 0.) error("ProjDataInfoGenericNoArcCorr does not support TOF yet"); Bin bin; - const LORAs2Points & lor_as_2points = dynamic_cast &>(lor); + const LORAs2Points& lor_as_2points = dynamic_cast&>(lor); - CartesianCoordinate3D _p1 = lor_as_2points.p1(); - CartesianCoordinate3D _p2 = lor_as_2points.p2(); + CartesianCoordinate3D _p1 = lor_as_2points.p1(); + CartesianCoordinate3D _p2 = lor_as_2points.p2(); - DetectionPosition<> det_pos1; - DetectionPosition<> det_pos2; + DetectionPosition<> det_pos1; + DetectionPosition<> det_pos2; - if (get_scanner_ptr()->find_detection_position_given_cartesian_coordinate(det_pos1, _p1)==Succeeded::no || - get_scanner_ptr()->find_detection_position_given_cartesian_coordinate(det_pos2, _p2)==Succeeded::no) - { - bin.set_bin_value(-1); - return bin; - } + if (get_scanner_ptr()->find_detection_position_given_cartesian_coordinate(det_pos1, _p1) == Succeeded::no + || get_scanner_ptr()->find_detection_position_given_cartesian_coordinate(det_pos2, _p2) == Succeeded::no) + { + bin.set_bin_value(-1); + return bin; + } DetectionPositionPair<> det_pos_pair; - det_pos_pair.pos1() = det_pos1; - det_pos_pair.pos2() = det_pos2; - - if (get_bin_for_det_pos_pair(bin, det_pos_pair) == 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; - } -} + det_pos_pair.pos1() = det_pos1; + det_pos_pair.pos2() = det_pos2; + if (get_bin_for_det_pos_pair(bin, det_pos_pair) == 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; + } +} END_NAMESPACE_STIR diff --git a/src/buildblock/ProjDataInfoSubsetByView.cxx b/src/buildblock/ProjDataInfoSubsetByView.cxx index 6bc638a97..e23cc182a 100644 --- a/src/buildblock/ProjDataInfoSubsetByView.cxx +++ b/src/buildblock/ProjDataInfoSubsetByView.cxx @@ -29,8 +29,11 @@ ProjDataInfoSubsetByView::ProjDataInfoSubsetByView(const shared_ptrget_scanner_sptr(), VectorWithOffset(full_proj_data_info_sptr->get_min_segment_num(), full_proj_data_info_sptr->get_max_segment_num()), // filled in below - views.size(), full_proj_data_info_sptr->get_num_tangential_poss(), full_proj_data_info_sptr->get_tof_mash_factor()), - org_proj_data_info_sptr(full_proj_data_info_sptr->clone()), view_to_org_view_num(views), + views.size(), + full_proj_data_info_sptr->get_num_tangential_poss(), + full_proj_data_info_sptr->get_tof_mash_factor()), + org_proj_data_info_sptr(full_proj_data_info_sptr->clone()), + view_to_org_view_num(views), org_view_to_view_num(full_proj_data_info_sptr->get_num_views(), -100) // initialise with crazy value { // Check subset isn't empty @@ -69,7 +72,8 @@ ProjDataInfoSubsetByView::ProjDataInfoSubsetByView(const shared_ptrget_min_segment_num(); - segment_num <= full_proj_data_info_sptr->get_max_segment_num(); ++segment_num) + segment_num <= full_proj_data_info_sptr->get_max_segment_num(); + ++segment_num) { this->set_min_axial_pos_num(full_proj_data_info_sptr->get_min_axial_pos_num(segment_num), segment_num); this->set_max_axial_pos_num(full_proj_data_info_sptr->get_max_axial_pos_num(segment_num), segment_num); diff --git a/src/buildblock/ProjDataInterfile.cxx b/src/buildblock/ProjDataInterfile.cxx index c3a3cbc5b..74906390e 100644 --- a/src/buildblock/ProjDataInterfile.cxx +++ b/src/buildblock/ProjDataInterfile.cxx @@ -16,7 +16,7 @@ See STIR/LICENSE.txt for details */ -#include "stir/ProjDataInterfile.h" +#include "stir/ProjDataInterfile.h" #include "stir/utilities.h" #include "stir/IO/interfile.h" #include "stir/error.h" @@ -33,79 +33,79 @@ 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)); + 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()); - } + { + error("ProjDataInterfile: error opening output file %s\n", data_name.c_str()); + } #if 0 delete[] header_name; delete[] data_name; #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/Radionuclide.cxx b/src/buildblock/Radionuclide.cxx index d8ea6bccc..822c4c74c 100644 --- a/src/buildblock/Radionuclide.cxx +++ b/src/buildblock/Radionuclide.cxx @@ -32,67 +32,73 @@ Radionuclide::parameter_info() const s << "Radionuclide: " << this->name << '\n'; s << "Energy " << std::fixed << std::setprecision(12) << this->energy << std::setprecision(5) << '\n'; s << "Half-life: " << std::fixed << std::setprecision(12) << this->half_life << std::setprecision(5) << '\n'; - s << "Branching ratio: " << std::fixed << std::setprecision(12) <branching_ratio << std::setprecision(5)<<'\n'; + s << "Branching ratio: " << std::fixed << std::setprecision(12) << this->branching_ratio << std::setprecision(5) << '\n'; return s.str(); } Radionuclide::Radionuclide() - :name("Unknown"),energy(-1), - branching_ratio(-1), - half_life(-1),modality(ImagingModality::Unknown) + : name("Unknown"), + energy(-1), + branching_ratio(-1), + half_life(-1), + modality(ImagingModality::Unknown) {} - -Radionuclide::Radionuclide(const std::string &rname, float renergy, float rbranching_ratio, float rhalf_life, - ImagingModality rmodality) - :name(rname),energy(renergy), +Radionuclide::Radionuclide( + const std::string& rname, float renergy, float rbranching_ratio, float rhalf_life, ImagingModality rmodality) + : name(rname), + energy(renergy), branching_ratio(rbranching_ratio), - half_life(rhalf_life),modality(rmodality) - {} + half_life(rhalf_life), + modality(rmodality) +{} - std::string - Radionuclide:: get_name()const -{ -// if (name=="Unknown") -// error("Radionuclide is Unknown, If you want to use it, it needs to be defined!"); - return name; +Radionuclide::get_name() const +{ + // if (name=="Unknown") + // error("Radionuclide is Unknown, If you want to use it, it needs to be defined!"); + return name; } -float Radionuclide::get_energy(bool check) const +float +Radionuclide::get_energy(bool check) const { - if (check && energy<=0) - error("Radionuclide energy peak is unset, If you want to use it, it needs to be set!"); - return energy; + if (check && energy <= 0) + error("Radionuclide energy peak is unset, If you want to use it, it needs to be set!"); + return energy; } -float Radionuclide::get_branching_ratio(bool check) const -{ - if (check && branching_ratio<=0) - error("Radionuclide Branching ratio is unset, If you want to use it, it needs to be set!"); - return branching_ratio; +float +Radionuclide::get_branching_ratio(bool check) const +{ + if (check && branching_ratio <= 0) + error("Radionuclide Branching ratio is unset, If you want to use it, it needs to be set!"); + return branching_ratio; } -float Radionuclide::get_half_life(bool check) const +float +Radionuclide::get_half_life(bool check) const { - if (check && half_life<=0) - error("Radionuclide half life is unset, If you want to use it, it needs to be set!"); - return half_life; + if (check && half_life <= 0) + error("Radionuclide half life is unset, If you want to use it, it needs to be set!"); + return half_life; } -ImagingModality Radionuclide::get_modality(bool check) const -{ - if (check && modality.is_unknown()) - error("Radionuclide::modality is Unknown, If you want to use it, it needs to be defined!"); - return modality; +ImagingModality +Radionuclide::get_modality(bool check) const +{ + if (check && modality.is_unknown()) + error("Radionuclide::modality is Unknown, If you want to use it, it needs to be defined!"); + return modality; } -bool -Radionuclide::operator==(const Radionuclide& r) const{ - return (abs(energy - r.energy)<= 1E-1 || (energy<=0 && r.energy <=0)) && - (abs(branching_ratio-r.branching_ratio)<= 1E-1 || (branching_ratio<=0 && r.branching_ratio<=0)) && - (abs(half_life-r.half_life)<=1 || (r.half_life<=0 && r.half_life<=0)) && - (modality==r.modality); +bool +Radionuclide::operator==(const Radionuclide& r) const +{ + return (abs(energy - r.energy) <= 1E-1 || (energy <= 0 && r.energy <= 0)) + && (abs(branching_ratio - r.branching_ratio) <= 1E-1 || (branching_ratio <= 0 && r.branching_ratio <= 0)) + && (abs(half_life - r.half_life) <= 1 || (r.half_life <= 0 && r.half_life <= 0)) && (modality == r.modality); } END_NAMESPACE_STIR diff --git a/src/buildblock/RadionuclideDB.cxx b/src/buildblock/RadionuclideDB.cxx index b99e67305..10557fa6d 100644 --- a/src/buildblock/RadionuclideDB.cxx +++ b/src/buildblock/RadionuclideDB.cxx @@ -3,10 +3,10 @@ \file \ingroup ancillary \brief Implementation of class stir::RadionuclideDB - + \author Daniel Deidda \author Kris Thielemans - + */ /* Copyright (C) 2021, National Physical Laboratory @@ -27,48 +27,45 @@ START_NAMESPACE_STIR -RadionuclideDB:: -RadionuclideDB() +RadionuclideDB::RadionuclideDB() { #ifdef nlohmann_json_FOUND read_from_file(find_STIR_config_file("radionuclide_info.json")); - this->radionuclide_lookup_table_filename=find_STIR_config_file("radionuclide_names.json"); + this->radionuclide_lookup_table_filename = find_STIR_config_file("radionuclide_names.json"); #endif } void -RadionuclideDB:: -read_from_file(const std::string& arg) +RadionuclideDB::read_from_file(const std::string& arg) { #ifdef nlohmann_json_FOUND - this->database_filename = arg; - - //Read Radionuclide file and set JSON member for DB - - std::string s =this->database_filename; - std::ifstream json_file_stream(s); - - if(!json_file_stream) - error("Could not open Json file!"); - + this->database_filename = arg; + + // Read Radionuclide file and set JSON member for DB + + std::string s = this->database_filename; + std::ifstream json_file_stream(s); + + if (!json_file_stream) + error("Could not open Json file!"); + // nlohmann::json radionuclide_json; - json_file_stream >> this->radionuclide_json; + json_file_stream >> this->radionuclide_json; // radionuclide_json.parse(json_file_stream); - // - - if (radionuclide_json.find("nuclides") == radionuclide_json.end()) + // + + if (radionuclide_json.find("nuclides") == radionuclide_json.end()) { error("RadionuclideDB: No or incorrect JSON radionuclide set (could not find \"nuclides\" in file \"" + this->database_filename + "\")"); } #else - error("RadionuclideDB: STIR was compiled without JSON support and therefore cannot read a database."); + error("RadionuclideDB: STIR was compiled without JSON support and therefore cannot read a database."); #endif } -std::string -RadionuclideDB:: -get_radionuclide_name_from_lookup_table(const std::string& rname) const +std::string +RadionuclideDB::get_radionuclide_name_from_lookup_table(const std::string& rname) const { if (rname.empty()) return "default"; @@ -76,72 +73,73 @@ get_radionuclide_name_from_lookup_table(const std::string& rname) const #ifdef nlohmann_json_FOUND if (this->radionuclide_lookup_table_filename.empty()) error("RadionuclideDB: no filename set for look-up table"); - + std::ifstream json_file_stream(this->radionuclide_lookup_table_filename); - + if (!json_file_stream) error("Could not open radionuclide lookup file:'" + this->radionuclide_lookup_table_filename + "'"); - + nlohmann::json table_json; json_file_stream >> table_json; - -// Check that lookup table and database have the same number of elements - if (radionuclide_json["nuclides"].size() != table_json.size()) - error("The lookup table and the radionuclide database do not have the same number of elements. " - "If you added a radionuclide you also need to add the same in the lookup table"); - - for (unsigned int l=0; ldatabase_filename.empty()) error("RadionuclideDB: no filename set for the Radionuclide info"); std::string name = rname; - float keV ; - float h_life ; + float keV; + float h_life; float branching_ratio; - + #ifdef nlohmann_json_FOUND - info("RadionuclideDB: finding record radionuclide: " + rname+ - " in file "+ this->database_filename, 3); + info("RadionuclideDB: finding record radionuclide: " + rname + " in file " + this->database_filename, 3); // convert modality string std::string modality_string; switch (rmodality.get_modality()) { case ImagingModality::PT: - modality_string = "PET"; break; + modality_string = "PET"; + break; case ImagingModality::NM: - modality_string = "nucmed"; break; + modality_string = "nucmed"; + break; default: - warning(std::string("RadionuclideDB::get_radionuclide_from_json called with unknown modality. Returning \"unknown\" radionuclide.")); + warning(std::string( + "RadionuclideDB::get_radionuclide_from_json called with unknown modality. Returning \"unknown\" radionuclide.")); return Radionuclide(); } - //Extract appropriate chunk of JSON file for given nuclide. + // Extract appropriate chunk of JSON file for given nuclide. auto all_nuclides = radionuclide_json["nuclides"]; auto rnuclide_entry = all_nuclides.end(); try { - rnuclide_entry = std::find_if(all_nuclides.begin(), all_nuclides.end(), - [&rname](const nlohmann::json::reference& entry) - { return entry.at("name") == rname; }); + rnuclide_entry = std::find_if(all_nuclides.begin(), all_nuclides.end(), [&rname](const nlohmann::json::reference& entry) { + return entry.at("name") == rname; + }); } catch (...) { @@ -151,7 +149,8 @@ get_radionuclide_from_json(ImagingModality rmodality, const std::string &rname) if (rnuclide_entry == all_nuclides.end()) { - warning(std::string("RadionuclideDB: radionuclide " + rname + " not found in JSON database. Returning \"unknown\" radionuclide.")); + warning(std::string("RadionuclideDB: radionuclide " + rname + + " not found in JSON database. Returning \"unknown\" radionuclide.")); return Radionuclide(); } @@ -168,23 +167,25 @@ get_radionuclide_from_json(ImagingModality rmodality, const std::string &rname) auto decay_entry = decays.end(); try { - decay_entry = std::find_if(decays.begin(), decays.end(), - [&modality_string](const nlohmann::json::reference& entry) - { return entry.at("modality") == modality_string; }); + decay_entry = std::find_if(decays.begin(), decays.end(), [&modality_string](const nlohmann::json::reference& entry) { + return entry.at("modality") == modality_string; + }); } catch (...) { - error("RadionucldeDB: \"modality\" keyword not found for at least one entry of radionuclide " + rname + ". JSON database malformed."); + error("RadionucldeDB: \"modality\" keyword not found for at least one entry of radionuclide " + rname + + ". JSON database malformed."); return Radionuclide(); // add return to avoid compiler warning } - + if (decay_entry == decays.end()) { - warning(std::string("RadionuclideDB: radionuclide " + rname + ": modality " + modality_string + " not found in JSON database. Returning \"unknown\" radionuclide.")); + warning(std::string("RadionuclideDB: radionuclide " + rname + ": modality " + modality_string + + " not found in JSON database. Returning \"unknown\" radionuclide.")); return Radionuclide(); } - //Extract properties for specific nuclide and modality. + // Extract properties for specific nuclide and modality. const auto properties = *decay_entry; info("RadionuclideDB: JSON record found:" + properties.dump(6), 3); @@ -213,11 +214,7 @@ get_radionuclide_from_json(ImagingModality rmodality, const std::string &rname) error("RadionuclideDB: half_life not set for " + rname + " with modality " + modality_string); } - Radionuclide rnuclide(rname, - keV, - branching_ratio, - h_life, - rmodality); + Radionuclide rnuclide(rname, keV, branching_ratio, h_life, rmodality); return rnuclide; @@ -227,16 +224,15 @@ get_radionuclide_from_json(ImagingModality rmodality, const std::string &rname) #endif } -Radionuclide -RadionuclideDB:: -get_radionuclide(ImagingModality rmodality, const std::string& rname) +Radionuclide +RadionuclideDB::get_radionuclide(ImagingModality rmodality, const std::string& rname) { // handle default case if (rname.empty() || rname == "default") { - if (rmodality.get_modality()==ImagingModality::PT) + if (rmodality.get_modality() == ImagingModality::PT) return get_radionuclide(rmodality, "^18^Fluorine"); - else if (rmodality.get_modality()==ImagingModality::NM) + else if (rmodality.get_modality() == ImagingModality::NM) return get_radionuclide(rmodality, "^99m^Technetium"); else { @@ -249,43 +245,39 @@ get_radionuclide(ImagingModality rmodality, const std::string& rname) #ifdef nlohmann_json_FOUND - return get_radionuclide_from_json(rmodality,nuclide_name); + return get_radionuclide_from_json(rmodality, nuclide_name); #else - if(rmodality.get_modality()==ImagingModality::PT){ - if (rname != "^18^Fluorine") - { - warning(std::string("RadioNuclideDB::get_radionuclide: since STIR was compiled without nlohmann-json-dev, We only have information for ^18^Fluorine for the PET modality. Returning \"unknown\" radionuclide.")); - return Radionuclide(); - } - - return Radionuclide("^18^Fluorine", - 511, - 0.9686, - 6584.04, - rmodality); - }else if(rmodality.get_modality()==ImagingModality::NM){ - if (rname != "^99m^Technetium") - { - warning(std::string("RadioNuclideDB::get_radionuclide: since STIR was compiled without nlohmann-json-dev, We only have information for ^99m^Technetium for the NM modality. Returning \"unknown\" radionuclide.")); - return Radionuclide(); - } - - return Radionuclide("^99m^Technetium", - 140.511, - 0.885, - 21624.12, - rmodality); + if (rmodality.get_modality() == ImagingModality::PT) + { + if (rname != "^18^Fluorine") + { + warning(std::string("RadioNuclideDB::get_radionuclide: since STIR was compiled without nlohmann-json-dev, We only have " + "information for ^18^Fluorine for the PET modality. Returning \"unknown\" radionuclide.")); + return Radionuclide(); + } + + return Radionuclide("^18^Fluorine", 511, 0.9686, 6584.04, rmodality); + } + else if (rmodality.get_modality() == ImagingModality::NM) + { + if (rname != "^99m^Technetium") + { + warning(std::string("RadioNuclideDB::get_radionuclide: since STIR was compiled without nlohmann-json-dev, We only have " + "information for ^99m^Technetium for the NM modality. Returning \"unknown\" radionuclide.")); + return Radionuclide(); + } + + return Radionuclide("^99m^Technetium", 140.511, 0.885, 21624.12, rmodality); + } + else + { + warning(std::string("RadioNuclideDB::get_radionuclide: unknown modality. Returning \"unknown\" radionuclide.")); + return Radionuclide(); } - else - { - warning(std::string("RadioNuclideDB::get_radionuclide: unknown modality. Returning \"unknown\" radionuclide.")); - return Radionuclide(); - } #endif } END_NAMESPACE_STIR - diff --git a/src/buildblock/RelatedViewgrams.cxx b/src/buildblock/RelatedViewgrams.cxx index 7a5ef3c25..96692db48 100644 --- a/src/buildblock/RelatedViewgrams.cxx +++ b/src/buildblock/RelatedViewgrams.cxx @@ -27,7 +27,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; @@ -35,10 +35,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 @@ -47,135 +47,101 @@ 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()) + 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() - ); + 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()) + if (*this->get_symmetries_ptr() != *other.get_symmetries_ptr()) { - explanation = - str(format("Differing symmetries") - ); + explanation = str(format("Differing symmetries")); return false; } - if (this->get_basic_view_num() != - other.get_basic_view_num()) + 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() - ); + 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()) + 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() - ); + 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()) + 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() - ); + 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 +template +bool +RelatedViewgrams::operator==(const self_type& that) const { - return - this->has_same_characteristics(that) && - std::equal(this->begin(), this->end(), that.begin()); + 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; @@ -183,12 +149,11 @@ operator*= (const elemT f) } /*! \warning: this uses division according to elemT (i.e. no rounding or so) */ -template +template RelatedViewgrams& -RelatedViewgrams:: -operator/= (const elemT f) +RelatedViewgrams::operator/=(const elemT f) { - assert(f!=0); + assert(f != 0); for (iterator iter = begin(); iter != end(); ++iter) *iter /= f; @@ -197,9 +162,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; @@ -208,170 +172,155 @@ 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 +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(); + 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; - } + { + *max_iter = iter->find_max(); + ++iter; + ++max_iter; + } return max_per_viewgram.find_max(); } template -elemT -RelatedViewgrams:: -find_min() const +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(); + 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; - } + { + *min_iter = iter->find_min(); + ++iter; + ++min_iter; + } return min_per_viewgram.find_min(); } - template -void -RelatedViewgrams::fill(const elemT &n) +void +RelatedViewgrams::fill(const elemT& n) { - for (iterator iter = begin(); iter != end(); ++iter) + 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) - { - 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()); - } + 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()); + } pdi_ptr->set_min_tangential_pos_num(range[ax_min].get_min_index()); 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) - { - iter->grow(range); - *iter = Viewgram(*iter, pdi_shared_ptr, - iter->get_view_num(), iter->get_segment_num(),iter->get_timing_pos_num()); - } + 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->get_timing_pos_num()); + } check_state(); } -/* +/* TODO #include "stir/zoom.h" @@ -391,13 +340,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 2d6ca4905..7cd38d7ee 100644 --- a/src/buildblock/SSRB.cxx +++ b/src/buildblock/SSRB.cxx @@ -39,134 +39,101 @@ 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 * +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 - ) + 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 (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) + "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"); + "type ProjDataInfoCylindrical\n"); } - ProjDataInfoCylindrical * out_proj_data_info_sptr = - dynamic_cast - (in_proj_data_info_sptr->clone()); + 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); - if (num_views_to_combine>1) + 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); + if (num_views_to_combine > 1) { - const float offset = in_proj_data_info_sptr->get_azimuthal_angle_offset() + - in_proj_data_info_sptr->get_azimuthal_angle_sampling() * (num_views_to_combine-1)/2.F; + const float offset = in_proj_data_info_sptr->get_azimuthal_angle_offset() + + in_proj_data_info_sptr->get_azimuthal_angle_sampling() * (num_views_to_combine - 1) / 2.F; out_proj_data_info_sptr->set_azimuthal_angle_offset(offset); } // 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; + 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) + 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); + 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); - 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 + // 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)) + 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"); + "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); + 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) { - 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); @@ -174,7 +141,7 @@ SSRB(const ProjDataInfo& in_proj_data_info, return out_proj_data_info_sptr; } -void +void SSRB(const string& output_filename, const ProjData& in_proj_data, const int num_segments_to_combine, @@ -182,60 +149,48 @@ SSRB(const string& output_filename, 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 - ) + 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); + 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"); + 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()); + 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)) - { - error("SSRB works only on segments with proj_data_info of " - "type ProjDataInfoCylindrical\n"); - } - const shared_ptr out_proj_data_info_sptr = - dynamic_pointer_cast - (out_proj_data.get_proj_data_info_sptr()); + { + error("SSRB works only on segments with proj_data_info of " + "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)) - { - error("SSRB works only on segments with proj_data_info of " - "type ProjDataInfoCylindrical\n"); - } - - const int num_views_to_combine = - in_proj_data.get_num_views()/ out_proj_data.get_num_views(); + { + error("SSRB works only on segments with proj_data_info of " + "type ProjDataInfoCylindrical\n"); + } + 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(); + 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 @@ -244,96 +199,87 @@ SSRB(ProjData& out_proj_data, { // 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); - } - } + 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; - // 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 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; - 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; + 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]; - 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); + 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); - } + out_proj_data.set_sinogram(out_sino); + } } } } diff --git a/src/buildblock/Scanner.cxx b/src/buildblock/Scanner.cxx index 6efbc8ca8..a66b5c3d4 100644 --- a/src/buildblock/Scanner.cxx +++ b/src/buildblock/Scanner.cxx @@ -55,22 +55,14 @@ 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) - : _already_setup(false) + : _already_setup(false) { // set_params parameters: @@ -98,7 +90,6 @@ Scanner::Scanner(Type scanner_type) // int num_detector_layers_v // - /* for CTI scanners (at least upto 966): before arc-correction, central_bin_size ~= ring_radius* pi/num_detectors @@ -110,496 +101,939 @@ Scanner::Scanner(Type scanner_type) 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, 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, - 1, 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, 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, - 1, 0.F, 0.F); - break; - - case E953: - - 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, - 1, 0.F, 0.F); - break; - - case E921: - - 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, - 1, 0.F, 0.F); - break; - - case E925: - - 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, - 1, 0.F, 0.F); - break; - - - case E961: + case E931: + + // KT 25/01/2002 corrected ring_spacing + 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, + 1, + 0.F, + 0.F); + // 16 BUCKETS per ring in TWO rings - i.e. 32 buckets in total - 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, - 1, 0.F, 0.F); - break; + break; - case E962: + case E951: + + 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, + 1, + 0.F, + 0.F); + break; - 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, - 1, 0.F, 0.F); - break; + case E953: + + 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, + 1, + 0.F, + 0.F); + break; - case E966: + case E921: + + 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, + 1, + 0.F, + 0.F); + 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, - 1, 0.F, 0.F); - break; + case E925: + + 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, + 1, + 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, 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, - 1, 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. - break; + case E961: + + 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, + 1, + 0.F, + 0.F); + 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 - // 9th crystal where the counts are zero. - 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, - 1, 0.F, 0.F); // TODO bucket/singles info incorrect? 224 buckets in total, but not sure how distributed - break; + case E962: + + 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, + 1, + 0.F, + 0.F); + 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 E966: + + 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, + 1, + 0.F, + 0.F); + break; - case Siemens_mCT: - // 13x13 blocks, 1 virtual "crystal" along axial and transaxial direction, 48 blocks along the ring, 4 blocks in axial direction - // TOF info from Rausch et al., EJNMMI Phys 2, 26 (2015). https://doi.org/10.1186/s40658-015-0132-1 - 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, - // 312ps width of bins - 13, 4.056*1000/13, 555.F - ); // TODO singles info incorrect - // energy: 435-650 - break; + case E1080: + // data added by Robert Barnett, Westmead Hospital, Sydney + 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, + 1, + 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. + break; - case Siemens_Vision_600: - // 8x38 blocks of size 10x20. With virtual crystals 10x21 (confirmed from norm.n.hdr) - // Siemens uses 50 views (why??) - // Vision number of TOF bins seems always 33. However, the sinogram headers say this is with TOF mashing factor 8, - // so we create the scanner with 33*8 possible TOF bins, and rely on InterfileHeaderSiemens - // to create a ProjDataInfo with mashing 8 - set_params( - Siemens_Vision_600, // type - string_list("Siemens Vision 600", "Vision 600", "1208"), // names - 80, // rings - 520, // max n non-arc-corr bins - 520, // default n arc-corr bins - 21*38, // num detector per ring - 410.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*8, // max n timing position - 143.231/8, // timing position bin size - 214.F // timing resolution - ); - break; - - case RPT: - - 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, - 1, 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; + 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 + // 9th crystal where the counts are zero. + 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, + 1, + 0.F, + 0.F); // TODO bucket/singles info incorrect? 224 buckets in total, but not sure how distributed + break; - case RATPET: + 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; - 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, - 1, 0.F, 0.F); // HR block, 4 buckets per ring + case Siemens_mCT: + // 13x13 blocks, 1 virtual "crystal" along axial and transaxial direction, 48 blocks along the ring, 4 blocks in axial + // direction TOF info from Rausch et al., EJNMMI Phys 2, 26 (2015). https://doi.org/10.1186/s40658-015-0132-1 + 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, + // 312ps width of bins + 13, + 4.056 * 1000 / 13, + 555.F); // TODO singles info incorrect + // energy: 435-650 + break; - // Default 7.0mm average interaction depth. - // 8 x 0 crystals per singles unit because not known - // although likely transaxial_blocks_per_bucket*transaxial_crystals_per_block - break; + case Siemens_Vision_600: + // 8x38 blocks of size 10x20. With virtual crystals 10x21 (confirmed from norm.n.hdr) + // Siemens uses 50 views (why??) + // Vision number of TOF bins seems always 33. However, the sinogram headers say this is with TOF mashing factor 8, + // so we create the scanner with 33*8 possible TOF bins, and rely on InterfileHeaderSiemens + // to create a ProjDataInfo with mashing 8 + set_params(Siemens_Vision_600, // type + string_list("Siemens Vision 600", "Vision 600", "1208"), // names + 80, // rings + 520, // max n non-arc-corr bins + 520, // default n arc-corr bins + 21 * 38, // num detector per ring + 410.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 * 8, // max n timing position + 143.231 / 8, // timing position bin size + 214.F // timing resolution + ); + break; - case PANDA: + case RPT: + + 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, + 1, + 0.F, + 0.F); - 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, - 1, 0.F, 0.F); - break; + // Default 7.0mm average interaction depth. + // This 7mm taken off the inner ring radius so that the effective radius remains 380mm + break; - case nanoPET: + case RATPET: + + 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, + 1, + 0.F, + 0.F); // HR block, 4 buckets per ring - 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, - 1, 0.F, 0.F); + // Default 7.0mm average interaction depth. + // 8 x 0 crystals per singles unit because not known + // although likely transaxial_blocks_per_bucket*transaxial_crystals_per_block 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, - 0.0F, 511.F, - 1, 0.F, 0.F); + 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, + 0.0F, + 511.F, + 1, + 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, + 0.0F, + 511.F, + 1, + 0.F, + 0.F); + break; - case Advance: + 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, + 0.0F, + 511.F, + 1, + 0.F, + 0.F); + break; - // 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, - 0.0F, 511.F, - 1, 0.F, 0.F); - break; + case Advance: + + // 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, + 0.0F, + 511.F, + 1, + 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, - 0.0F, 511.F, - 1, 0.F, 0.F); - break; - case DiscoveryST: - - // 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, - 0.0F, 511.F, - 1, 0.F, 0.F);// TODO not sure about sign of view_offset - 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, + 0.0F, + 511.F, + 1, + 0.F, + 0.F); + break; + case DiscoveryST: + + // 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, + 0.0F, + 511.F, + 1, + 0.F, + 0.F); // TODO not sure about sign of view_offset + break; - case DiscoverySTE: + 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, // TODO not sure about sign of view_offset + 0.22F, // energy resolution + 511.F, + 1, + 0.F, + 0.F); + break; - 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 - 0.22F, // energy resolution - 511.F, - 1, 0.F, 0.F); - 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, + 0.0F, + 511.F, + 1, + 0.F, + 0.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, - 0.0F, 511.F, - 1, 0.F, 0.F);// TODO not sure about sign of view_offset - 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, + 0.0F, + 511.F, + 1, + 0.F, + 0.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, - 0.0F, 511.F, - 1, 0.F, 0.F); - 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)(13.02), + (float)(390.0F)); + 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)(13.02), - (float)(390.0F) ); - break; + case Discovery690: + // same as 710 + 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, + 0.0F, + 511.F, + (short int)(55), + (float)(89.0F), + (float)(550.0F)); + break; - case Discovery690: - // same as 710 - 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, - 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, - 0.0944F, // energy resolution from Hsu et al. 2017 - 511.F, - (short int)(0), - (float)(0), //TODO - (float)(0) ); - 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, + 0.0944F, // energy resolution from Hsu et al. 2017 + 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, - 0.0944F, // energy resolution from Hsu et al. 2017 - 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, + 0.0944F, // energy resolution from Hsu et al. 2017 + 511.F, + (short int)(0), + (float)(0), // TODO + (float)(0)); + break; case DiscoveryMI5ring: // This is the 5-ring DMI // as above, but one extra block // Hsu et al. 2017 JNM // crystal size 3.95 x 5.3 x 25 - set_params(DiscoveryMI5ring, string_list("GE Discovery MI 5 rings", "Discovery MI5", "Discovery MI"), // needs to include last value as used by GE in RDF files + set_params(DiscoveryMI5ring, + string_list("GE Discovery MI 5 rings", + "Discovery MI5", + "Discovery MI"), // needs to include last value as used by GE in RDF files 45, 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 - 5, 4, - 9, 4, - 1, 1, + 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 + 5, + 4, + 9, + 4, + 1, + 1, 1, 0.0944F, // energy resolution from Hsu et al. 2017 511.F, (short int)(0), - (float)(0), //TODO + (float)(0), // TODO (float)(0)); break; - case HZLR: - - 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, - 1, 0.F, 0.F); - // Default 7.0mm average interaction depth. - // crystals per singles unit etc unknown - break; - - case HRRT: + case HZLR: + + 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, + 1, + 0.F, + 0.F); + // Default 7.0mm average interaction depth. + // crystals per singles unit etc unknown + break; - 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, - 1, 0.F, 0.F); // added by Dylan Togane - // warning: used 7.0mm average interaction depth. - // crystals per singles unit etc unknown - break; + case HRRT: + + 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, + 1, + 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 - 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. - This creates problems for the current version of STIR as the current - 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, 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, - 1, 0.F, 0.F); - 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 + 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. + This creates problems for the current version of STIR as the current + 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, + 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, + 1, + 0.F, + 0.F); + break; #if 0 case Vereos: @@ -612,194 +1046,263 @@ Scanner::Scanner(Type scanner_type) break; #endif - 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 - 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, - 0.0F, 511.F, - 1, 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, - 0.F, 0.F, 0.F, 0.F, 0.F, - 0, 0, 0, 0, 0, 0, 0, - 0.0F, 511.F, - 1, 0.F, 0.F); + 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 + 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, + 0.0F, + 511.F, + 1, + 0.F, + 0.F); + break; - break; + case HiDAC: // all of these don't make any sense for the HiDAC + 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, 1, 0.F, 0.F); - case SAFIRDualRingPrototype: - set_params(SAFIRDualRingPrototype, string_list("SAFIRDualRingPrototype"), - 16, //num_rings_v - 150, //max_num_non_arccorrected_bins_v, - 150, //default_num_arccorrected_bins_v, - 180, //num_detectors_per_ring_v - 64.05, // inner_ring_radius_v - 5, //average_depth_of_interaction_v - 2.2, //ring_spacing_v - 1.1, //bin_size_v - 0, //intrinsic_tilt_v - 2, //num_axial_blocks_per_bucket_v - 1, //num_transaxial_blocks_per_bucket_v - 8, //num_axial_crystals_per_block_v - 15, //num_transaxial_crystals_per_block_v - 1, //num_axial_crystals_per_singles_unit_v - 1, //num_transaxial_crystals_per_singles_unit_v - 1, //num_detector_layers_v - -1, //energy_resolution_v - -1, //reference_energy_v - (short int)1, 0.F, 0.F, // non-TOF - "", //scanner_geometry_v - 2.2, //axial_crystal_spacing_v - 2.2, //transaxial_crystal_spacing_v - 18.1, //axial_block_spacing_v - 33.6, //transaxial_block_spacing_v - ""//crystal_map_file_name_v - ); - break; - - case UPENN_5rings: - set_params(UPENN_5rings, string_list("UPENN_5rings"), - (40+16)*5, - 331, 331, - 576+18, - 382.0F, 7.0F, - 3.9655, 2.0F, - static_cast(0), - 7, // int num_axial_blocks_per_bucket_v, - 4, // int num_transaxial_blocks_per_bucket_v, - 8, // int num_axial_crystals_per_block_v, - 8, // int num_transaxial_crystals_per_block_v, - 8*7, // int num_axial_crystals_per_singles_unit_v, - 8 * 4, // +1 gap // int num_transaxial_crystals_per_singles_unit_v, - 1, - 0.109F, 511.F - #ifdef STIR_TOF - , - (short int)(512), - (float)(19.53125), - (float)(272.55F) - #endif -); - break; + break; -case UPENN_6rings: - set_params(UPENN_6rings, string_list("UPENN_6rings"), - (40+16)*6, - 331, 331, - 576+18, - 382.0F, 7.0F, - 3.9655, 2.02035F, - static_cast(0), - 7 * 6, // int num_axial_blocks_per_bucket_v, - 1, // int num_transaxial_blocks_per_bucket_v, - 8, // int num_axial_crystals_per_block_v, - 33, // int num_transaxial_crystals_per_block_v, - 8, // int num_axial_crystals_per_singles_unit_v, - 33, //int num_transaxial_crystals_per_singles_unit_v, - 1, - 0.109F, 511.F - #ifdef STIR_TOF - , - (short int)(512), - (float)(19.53125), - (float)(272.55F) - #endif -); - break; + case SAFIRDualRingPrototype: + set_params(SAFIRDualRingPrototype, + string_list("SAFIRDualRingPrototype"), + 16, // num_rings_v + 150, // max_num_non_arccorrected_bins_v, + 150, // default_num_arccorrected_bins_v, + 180, // num_detectors_per_ring_v + 64.05, // inner_ring_radius_v + 5, // average_depth_of_interaction_v + 2.2, // ring_spacing_v + 1.1, // bin_size_v + 0, // intrinsic_tilt_v + 2, // num_axial_blocks_per_bucket_v + 1, // num_transaxial_blocks_per_bucket_v + 8, // num_axial_crystals_per_block_v + 15, // num_transaxial_crystals_per_block_v + 1, // num_axial_crystals_per_singles_unit_v + 1, // num_transaxial_crystals_per_singles_unit_v + 1, // num_detector_layers_v + -1, // energy_resolution_v + -1, // reference_energy_v + (short int)1, + 0.F, + 0.F, // non-TOF + "", // scanner_geometry_v + 2.2, // axial_crystal_spacing_v + 2.2, // transaxial_crystal_spacing_v + 18.1, // axial_block_spacing_v + 33.6, // transaxial_block_spacing_v + "" // crystal_map_file_name_v + ); + break; - case UPENN_5rings_no_gaps: - set_params(UPENN_5rings_no_gaps, string_list("UPENN_5rings_no_gaps"), - 40*5, - 301, 301, - 576, - 382.0F, 7.0F, - 3.9655, 2.08349F, - static_cast(0), - 7 * 5, // int num_axial_blocks_per_bucket_v, - 4, // int num_transaxial_blocks_per_bucket_v, - 8, // int num_axial_crystals_per_block_v, - 8, // int num_transaxial_crystals_per_block_v, - 8, // int num_axial_crystals_per_singles_unit_v, - 8 * 4, // int num_transaxial_crystals_per_singles_unit_v, - 1, - 0.109F, 511.F - #ifdef STIR_TOF - , - (short int)(512), - (float)(19.53125), - (float)(272.55F) - #endif -); - break; + case UPENN_5rings: + set_params(UPENN_5rings, + string_list("UPENN_5rings"), + (40 + 16) * 5, + 331, + 331, + 576 + 18, + 382.0F, + 7.0F, + 3.9655, + 2.0F, + static_cast(0), + 7, // int num_axial_blocks_per_bucket_v, + 4, // int num_transaxial_blocks_per_bucket_v, + 8, // int num_axial_crystals_per_block_v, + 8, // int num_transaxial_crystals_per_block_v, + 8 * 7, // int num_axial_crystals_per_singles_unit_v, + 8 * 4, // +1 gap // int num_transaxial_crystals_per_singles_unit_v, + 1, + 0.109F, + 511.F +#ifdef STIR_TOF + , + (short int)(512), + (float)(19.53125), + (float)(272.55F) +#endif + ); + break; - case UPENN_6rings_no_gaps: - set_params(UPENN_6rings_no_gaps, string_list("UPENN_6rings_no_gaps"), - 40 * 6, - 321, 321, - 576, - 382.0F, 7.0F, - 3.9655, 2.08F, - static_cast(0), - 5 * 6, // int num_axial_blocks_per_bucket_v, - 4, // int num_transaxial_blocks_per_bucket_v, - 8, // int num_axial_crystals_per_block_v, - 8, // int num_transaxial_crystals_per_block_v, - 8, // int num_axial_crystals_per_singles_unit_v, - 8, // int num_transaxial_crystals_per_singles_unit_v, - 1, - 0.109F, 511.F - #ifdef STIR_TOF - , - (short int)(512), - (float)(19.53125), - (float)(272.55F) - #endif -); - break; - - case User_defined_scanner: // zlong, 08-04-2004, Userdefined support + case UPENN_6rings: + set_params(UPENN_6rings, + string_list("UPENN_6rings"), + (40 + 16) * 6, + 331, + 331, + 576 + 18, + 382.0F, + 7.0F, + 3.9655, + 2.02035F, + static_cast(0), + 7 * 6, // int num_axial_blocks_per_bucket_v, + 1, // int num_transaxial_blocks_per_bucket_v, + 8, // int num_axial_crystals_per_block_v, + 33, // int num_transaxial_crystals_per_block_v, + 8, // int num_axial_crystals_per_singles_unit_v, + 33, // int num_transaxial_crystals_per_singles_unit_v, + 1, + 0.109F, + 511.F +#ifdef STIR_TOF + , + (short int)(512), + (float)(19.53125), + (float)(272.55F) +#endif + ); + break; - 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, - 1, 0.F, 0.F); + case UPENN_5rings_no_gaps: + set_params(UPENN_5rings_no_gaps, + string_list("UPENN_5rings_no_gaps"), + 40 * 5, + 301, + 301, + 576, + 382.0F, + 7.0F, + 3.9655, + 2.08349F, + static_cast(0), + 7 * 5, // int num_axial_blocks_per_bucket_v, + 4, // int num_transaxial_blocks_per_bucket_v, + 8, // int num_axial_crystals_per_block_v, + 8, // int num_transaxial_crystals_per_block_v, + 8, // int num_axial_crystals_per_singles_unit_v, + 8 * 4, // int num_transaxial_crystals_per_singles_unit_v, + 1, + 0.109F, + 511.F +#ifdef STIR_TOF + , + (short int)(512), + (float)(19.53125), + (float)(272.55F) +#endif + ); + break; - break; + case UPENN_6rings_no_gaps: + set_params(UPENN_6rings_no_gaps, + string_list("UPENN_6rings_no_gaps"), + 40 * 6, + 321, + 321, + 576, + 382.0F, + 7.0F, + 3.9655, + 2.08F, + static_cast(0), + 5 * 6, // int num_axial_blocks_per_bucket_v, + 4, // int num_transaxial_blocks_per_bucket_v, + 8, // int num_axial_crystals_per_block_v, + 8, // int num_transaxial_crystals_per_block_v, + 8, // int num_axial_crystals_per_singles_unit_v, + 8, // int num_transaxial_crystals_per_singles_unit_v, + 1, + 0.109F, + 511.F +#ifdef STIR_TOF + , + (short int)(512), + (float)(19.53125), + (float)(272.55F) +#endif + ); + break; - default: - // 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, - 1, 0.F, 0.F); + case User_defined_scanner: // zlong, 08-04-2004, Userdefined support + + 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, + 1, + 0.F, + 0.F); - break; + break; - } + default: + // 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, + 1, + 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, +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, + 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, @@ -814,17 +1317,23 @@ Scanner::Scanner(Type type_v, const list& list_of_names_v, float axial_block_spacing_v, float transaxial_block_spacing_v, const std::string& crystal_map_file_name_v) -: _already_setup(false) + : _already_setup(false) { - set_params(type_v, list_of_names_v, num_rings_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, + 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, @@ -841,14 +1350,21 @@ Scanner::Scanner(Type type_v, const list& list_of_names_v, crystal_map_file_name_v); } -Scanner::Scanner(Type type_v, const string& name, - int num_detectors_per_ring_v, int num_rings_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, + 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, @@ -863,17 +1379,23 @@ Scanner::Scanner(Type type_v, const string& name, float axial_block_spacing_v, float transaxial_block_spacing_v, const std::string& crystal_map_file_name_v) - : _already_setup(false) + : _already_setup(false) { - set_params(type_v, string_list(name), num_rings_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, + 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, @@ -891,66 +1413,69 @@ Scanner::Scanner(Type type_v, const string& name, } 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, - short int max_num_of_timing_poss_v, - float size_timing_pos_v, - float timing_resolution_v, - const string& scanner_geometry_v, - float axial_crystal_spacing_v, - float transaxial_crystal_spacing_v, - float axial_block_spacing_v, - float transaxial_block_spacing_v, - const std::string& crystal_map_file_name_v) +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, + short int max_num_of_timing_poss_v, + float size_timing_pos_v, + float timing_resolution_v, + const string& scanner_geometry_v, + float axial_crystal_spacing_v, + float transaxial_crystal_spacing_v, + float axial_block_spacing_v, + float transaxial_block_spacing_v, + const std::string& crystal_map_file_name_v) { type = type_v; list_of_names = list_of_names_v; - num_rings = num_rings_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; + 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; 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; - + axial_crystal_spacing = axial_crystal_spacing_v; transaxial_crystal_spacing = transaxial_crystal_spacing_v; axial_block_spacing = axial_block_spacing_v; transaxial_block_spacing = transaxial_block_spacing_v; - + crystal_map_file_name = crystal_map_file_name_v; if (scanner_geometry_v == "") @@ -961,22 +1486,25 @@ set_params(Type type_v,const list& list_of_names_v, set_up(); } -void Scanner::set_scanner_geometry(const std::string& new_scanner_geometry) +void +Scanner::set_scanner_geometry(const std::string& new_scanner_geometry) { scanner_geometry = new_scanner_geometry; - _already_setup = false; + _already_setup = false; } -void Scanner::set_up() +void +Scanner::set_up() { if (scanner_geometry == "Generic") { - if (!this->detector_map_sptr){ - if (crystal_map_file_name == "") - error("Scanner: scanner_geometry=Generic needs a crystal map"); - - read_detectormap_from_file(crystal_map_file_name); - } + if (!this->detector_map_sptr) + { + if (crystal_map_file_name == "") + error("Scanner: scanner_geometry=Generic needs a crystal map"); + + read_detectormap_from_file(crystal_map_file_name); + } } else { @@ -996,42 +1524,41 @@ void Scanner::set_up() } void -Scanner:: -set_detector_map( const DetectorCoordinateMap::det_pos_to_coord_type& coord_map ) +Scanner::set_detector_map(const DetectorCoordinateMap::det_pos_to_coord_type& coord_map) { this->detector_map_sptr.reset(new DetectorCoordinateMap(coord_map)); - if ((unsigned)num_detectors_per_ring != detector_map_sptr->get_num_tangential_coords() || - (unsigned)num_rings != detector_map_sptr->get_num_axial_coords() || - (unsigned)num_detector_layers != detector_map_sptr->get_num_radial_coords()) - error("Scanner:set_detector_map: inconsistent number of detectors"); + if ((unsigned)num_detectors_per_ring != detector_map_sptr->get_num_tangential_coords() + || (unsigned)num_rings != detector_map_sptr->get_num_axial_coords() + || (unsigned)num_detector_layers != detector_map_sptr->get_num_radial_coords()) + error("Scanner:set_detector_map: inconsistent number of detectors"); } void -Scanner:: -initialise_max_FOV_radius() { +Scanner::initialise_max_FOV_radius() +{ if (!this->detector_map_sptr) - { - // for cylindrical scanners, all detectors have the same distance from the rotational axis - max_FOV_radius = inner_ring_radius; - } + { + // for cylindrical scanners, all detectors have the same distance from the rotational axis + max_FOV_radius = inner_ring_radius; + } else - { - // for other geometries, loop through all detectors and set the radius to the largest found distance - max_FOV_radius = inner_ring_radius; - for (auto tangential_pos = 0U; tangential_pos < detector_map_sptr->get_num_tangential_coords(); tangential_pos++) - for (auto axial_pos = 0U; axial_pos < detector_map_sptr->get_num_axial_coords(); axial_pos++) - for (auto radial_pos = 0U; radial_pos < detector_map_sptr->get_num_radial_coords(); radial_pos++) { - auto coord = detector_map_sptr->get_coordinate_for_det_pos(stir::DetectionPosition<>(tangential_pos, axial_pos, radial_pos)); - const auto detector_radius = sqrt(coord.x() * coord.x() + coord.y() * coord.y()) - average_depth_of_interaction; - max_FOV_radius = fmax(max_FOV_radius, detector_radius); + // for other geometries, loop through all detectors and set the radius to the largest found distance + max_FOV_radius = inner_ring_radius; + for (auto tangential_pos = 0U; tangential_pos < detector_map_sptr->get_num_tangential_coords(); tangential_pos++) + for (auto axial_pos = 0U; axial_pos < detector_map_sptr->get_num_axial_coords(); axial_pos++) + for (auto radial_pos = 0U; radial_pos < detector_map_sptr->get_num_radial_coords(); radial_pos++) + { + auto coord = detector_map_sptr->get_coordinate_for_det_pos( + stir::DetectionPosition<>(tangential_pos, axial_pos, radial_pos)); + const auto detector_radius = sqrt(coord.x() * coord.x() + coord.y() * coord.y()) - average_depth_of_interaction; + max_FOV_radius = fmax(max_FOV_radius, detector_radius); + } } - } } void -Scanner:: -read_detectormap_from_file( const std::string& filename ) +Scanner::read_detectormap_from_file(const std::string& filename) { this->detector_map_sptr.reset(new DetectorCoordinateMap(filename)); } @@ -1039,10 +1566,9 @@ read_detectormap_from_file( const std::string& filename ) /*! \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 +Scanner::get_num_virtual_axial_crystals_per_block() const { - switch(get_type()) + switch (get_type()) { case E1080: case Siemens_mCT: @@ -1055,10 +1581,9 @@ get_num_virtual_axial_crystals_per_block() const /*! \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 +Scanner::get_num_virtual_transaxial_crystals_per_block() const { - switch(get_type()) + switch (get_type()) { case E1080: case Siemens_mCT: @@ -1073,214 +1598,218 @@ get_num_virtual_transaxial_crystals_per_block() const } /*! \todo Can currently only set to hard-wired values. Otherwise calls error() */ void -Scanner:: -set_num_virtual_axial_crystals_per_block(int val) +Scanner::set_num_virtual_axial_crystals_per_block(int val) { - //num_virtual_axial_crystals_per_block = 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) +Scanner::set_num_virtual_transaxial_crystals_per_block(int val) { - //num_virtual_transaxial_crystals_per_block = 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 +Succeeded +Scanner::check_consistency() const { - if (intrinsic_tilt<-_PI || intrinsic_tilt>_PI) + 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()); + 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(); - // exclusion of generic as 'get_num_transaxial_crystals_per_block()' is sometimes false for asymmetric detectors and not important for generic - if ( dets_per_ring != get_num_detectors_per_ring() && scanner_geometry != "Generic") - { - warning("Scanner %s: inconsistent transaxial block info", - this->get_name().c_str()); - return Succeeded::no; - } + const int dets_per_ring = get_num_transaxial_blocks() * get_num_transaxial_crystals_per_block(); + // exclusion of generic as 'get_num_transaxial_crystals_per_block()' is sometimes false for asymmetric detectors and not + // important for generic + if (dets_per_ring != get_num_detectors_per_ring() && scanner_geometry != "Generic") + { + 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()); + 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(); - // exclusion of generic as 'get_num_transaxial_blocks_per_bucket()' is sometimes false for asymmetric detectors and not important for generic - if ( blocks_per_ring != get_num_transaxial_blocks() && scanner_geometry != "Generic") - { - warning("Scanner %s: inconsistent transaxial block/bucket info", - this->get_name().c_str()); - return Succeeded::no; - } + const int blocks_per_ring = get_num_transaxial_buckets() * get_num_transaxial_blocks_per_bucket(); + // exclusion of generic as 'get_num_transaxial_blocks_per_bucket()' is sometimes false for asymmetric detectors and not + // important for generic + if (blocks_per_ring != get_num_transaxial_blocks() && scanner_geometry != "Generic") + { + 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()); + 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(); - - // exclusion of generic as 'get_num_axial_crystals_per_block()' is sometimes false for asymmetric detectors and not important for generic - if ( dets_axial != (get_num_rings() + get_num_virtual_axial_crystals_per_block()) && scanner_geometry != "Generic") - { - 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; - } + const int dets_axial = get_num_axial_blocks() * get_num_axial_crystals_per_block(); + + // exclusion of generic as 'get_num_axial_crystals_per_block()' is sometimes false for asymmetric detectors and not + // important for generic + if (dets_axial != (get_num_rings() + get_num_virtual_axial_crystals_per_block()) && scanner_geometry != "Generic") + { + 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()); + 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(); - // exclusion of generic as 'get_num_axial_blocks_per_bucket()' is sometimes false for asymmetric detectors and not important for generic - if ( blocks_axial != get_num_axial_blocks() && scanner_geometry != "Generic") - { - warning("Scanner %s: inconsistent axial block/bucket info", - this->get_name().c_str()); - return Succeeded::no; - } + const int blocks_axial = get_num_axial_buckets() * get_num_axial_blocks_per_bucket(); + // exclusion of generic as 'get_num_axial_blocks_per_bucket()' is sometimes false for asymmetric detectors and not + // important for generic + if (blocks_axial != get_num_axial_blocks() && scanner_geometry != "Generic") + { + 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()); + 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_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()); + 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; - } + 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; + } } } - + if (get_scanner_geometry() == "BlocksOnCylindrical") - {//! Check consistency of axial and transaxial spacing for block geometry - if (get_axial_crystal_spacing()*get_num_axial_crystals_per_block() > get_axial_block_spacing()) - { - warning("Scanner %s: inconsistent axial spacing:\n" + { //! Check consistency of axial and transaxial spacing for block geometry + if (get_axial_crystal_spacing() * get_num_axial_crystals_per_block() > get_axial_block_spacing()) + { + warning( + "Scanner %s: inconsistent axial spacing:\n" "\taxial_crystal_spacing %f muliplied by num_axial_crystals_per_block %d should fit into axial_block_spacing %f", - this->get_name().c_str(), - get_axial_crystal_spacing(), get_num_axial_crystals_per_block(), get_axial_block_spacing()); - return Succeeded::no; + this->get_name().c_str(), + get_axial_crystal_spacing(), + get_num_axial_crystals_per_block(), + get_axial_block_spacing()); + return Succeeded::no; } - if (get_transaxial_crystal_spacing()*get_num_transaxial_crystals_per_block() > get_transaxial_block_spacing()) + if (get_transaxial_crystal_spacing() * get_num_transaxial_crystals_per_block() > get_transaxial_block_spacing()) { warning("Scanner %s: inconsistent transaxial spacing:\n" - "\ttransaxial_crystal_spacing %f muliplied by num_transaxial_crystals_per_block %d should fit into transaxial_block_spacing %f", - this->get_name().c_str(), - get_transaxial_crystal_spacing(), get_num_transaxial_crystals_per_block(), get_transaxial_block_spacing()); + "\ttransaxial_crystal_spacing %f muliplied by num_transaxial_crystals_per_block %d should fit into " + "transaxial_block_spacing %f", + this->get_name().c_str(), + get_transaxial_crystal_spacing(), + get_num_transaxial_crystals_per_block(), + get_transaxial_block_spacing()); return Succeeded::no; } - - if (round(get_transaxial_block_spacing()*get_num_transaxial_blocks_per_bucket()*1000.0)/1000.0 - < round (2*inner_ring_radius*tan(_PI/2/get_num_transaxial_buckets())*1000.0)/1000.0) - { - warning("Scanner %s: inconsistent transaxial spacing:\n" - "\ttransaxial_block_spacing %f muliplied by num_transaxial_blocks_per_bucket %d should fit into a polygon that encircles a cylinder with inner_ring_radius %f", - this->get_name().c_str(), - get_transaxial_block_spacing(), get_num_transaxial_blocks_per_bucket(), get_inner_ring_radius()); - return Succeeded::no; - } - else if (get_scanner_geometry() == "Generic") - { //! Check if the crystal map is correct and given - if (get_crystal_map_file_name() == "") - { - warning("No crystal map is provided. The scanner geometry Generic needs it! Please provide one."); - return Succeeded::no; - } - else - { - std::ifstream crystal_map(get_crystal_map_file_name()); - if( !crystal_map) + + if (round(get_transaxial_block_spacing() * get_num_transaxial_blocks_per_bucket() * 1000.0) / 1000.0 + < round(2 * inner_ring_radius * tan(_PI / 2 / get_num_transaxial_buckets()) * 1000.0) / 1000.0) { - warning("No correct crystal map provided. Please check the file name."); + warning("Scanner %s: inconsistent transaxial spacing:\n" + "\ttransaxial_block_spacing %f muliplied by num_transaxial_blocks_per_bucket %d should fit into a polygon that " + "encircles a cylinder with inner_ring_radius %f", + this->get_name().c_str(), + get_transaxial_block_spacing(), + get_num_transaxial_blocks_per_bucket(), + get_inner_ring_radius()); return Succeeded::no; } - } + else if (get_scanner_geometry() == "Generic") + { //! Check if the crystal map is correct and given + if (get_crystal_map_file_name() == "") + { + warning("No crystal map is provided. The scanner geometry Generic needs it! Please provide one."); + return Succeeded::no; + } + else + { + std::ifstream crystal_map(get_crystal_map_file_name()); + if (!crystal_map) + { + warning("No correct crystal map provided. Please check the file name."); + return Succeeded::no; + } + } + } } - - } if (this->energy_resolution > 20.F) { warning("Scanner: energy resolution is a ratio (FWHM/reference_energy) and expected to be less than 1 " - "(although we allow up to 20 to denote no energy information), but it is set to " + - std::to_string(this->energy_resolution)); + "(although we allow up to 20 to denote no energy information), but it is set to " + + std::to_string(this->energy_resolution)); return Succeeded::no; } @@ -1289,12 +1818,11 @@ check_consistency() const const auto w = this->get_coincidence_window_width_in_ps(); const auto r = this->get_timing_resolution(); const auto w_mm = this->get_coincidence_window_width_in_mm(); - const auto FOV_D = this->get_max_FOV_radius()*2; + const auto FOV_D = this->get_max_FOV_radius() * 2; if ((w < 10.F) || (w > 10000.F)) { - warning("Scanner: coincidence window width is expected to be around 4500ps but is " + - std::to_string(w)); + warning("Scanner: coincidence window width is expected to be around 4500ps but is " + std::to_string(w)); return Succeeded::no; } if (this->get_max_num_timing_poss() > 1) @@ -1302,16 +1830,18 @@ check_consistency() const // TOF-capable if (w < r) { - warning("Scanner: coincidence window width in ps is expected to be smaller than the timing resolution for a TOF scanner,\n" - "but they are " + - std::to_string(w) + " and " + std::to_string(r) + " resp."); + warning("Scanner: coincidence window width in ps is expected to be smaller than the timing resolution for a TOF " + "scanner,\n" + "but they are " + + std::to_string(w) + " and " + std::to_string(r) + " resp."); return Succeeded::no; } - if ((w_mm > 2*FOV_D) || (w_mm < FOV_D/2)) + if ((w_mm > 2 * FOV_D) || (w_mm < FOV_D / 2)) { - warning("Scanner: coincidence window width in mm is expected to be of the order of the FOV diameter for a TOF scanner,\n" - "but they are " + - std::to_string(w_mm) + " and " + std::to_string(FOV_D) + " resp."); + warning("Scanner: coincidence window width in mm is expected to be of the order of the FOV diameter for a TOF " + "scanner,\n" + "but they are " + + std::to_string(w_mm) + " and " + std::to_string(FOV_D) + " resp."); return Succeeded::no; } } @@ -1324,72 +1854,61 @@ check_consistency() const 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; + return fabs(a - b) <= std::min(fabs(a), fabs(b)) * 10E-4; } bool -Scanner::operator ==(const Scanner& scanner) const +Scanner::operator==(const Scanner& scanner) const { -if (!close_enough(energy_resolution, scanner.energy_resolution) && - !close_enough(reference_energy, scanner.reference_energy)) + 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); - - 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) && - close_enough(axial_crystal_spacing, scanner.axial_crystal_spacing) && - close_enough(transaxial_crystal_spacing, scanner.transaxial_crystal_spacing) && - close_enough(axial_block_spacing, scanner.axial_block_spacing) && - close_enough(transaxial_block_spacing, scanner.transaxial_block_spacing) && - (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) + && close_enough(axial_crystal_spacing, scanner.axial_crystal_spacing) + && close_enough(transaxial_crystal_spacing, scanner.transaxial_crystal_spacing) + && close_enough(axial_block_spacing, scanner.axial_block_spacing) + && close_enough(transaxial_block_spacing, scanner.transaxial_block_spacing) + && (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); - } + { + 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;} - +{ + return list_of_names; +} const string& Scanner::get_name() const { - return *(list_of_names.begin()); - + return *(list_of_names.begin()); } string @@ -1397,90 +1916,77 @@ Scanner::parameter_info() const { // warning: these should match the parsing keywords in InterfilePDFSHeader std::ostringstream s; - 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_intrinsic_azimuthal_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'; + << " Distance between rings (cm) := " << get_ring_spacing() / 10 << '\n' + << " Default bin size (cm) := " << get_default_bin_size() / 10. << '\n' + << " View offset (degrees) := " << get_intrinsic_azimuthal_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'; - } + { + s << " Energy resolution := " << get_energy_resolution() << '\n'; + s << " Reference energy (in keV) := " << get_reference_energy() << '\n'; + } if (is_tof_ready()) - { - s << " Maximum number of (unmashed) TOF time bins := " << get_max_num_timing_poss() << '\n'; - s << " Size of unmashed TOF time bins (ps) := " << get_size_of_timing_pos() << '\n'; - s << " TOF timing resolution (ps) := " << get_timing_resolution() << '\n'; - } + { + s << " Maximum number of (unmashed) TOF time bins := " << get_max_num_timing_poss() << '\n'; + s << " Size of unmashed TOF time bins (ps) := " << get_size_of_timing_pos() << '\n'; + s << " TOF 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'; - - //block and generic geometry 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'; + + // block and generic geometry description if (crystal_map_file_name != "") - s << " Name of crystal map := " - << get_crystal_map_file_name() << '\n'; + s << " Name of crystal map := " << get_crystal_map_file_name() << '\n'; if (get_scanner_geometry() != "") - { - s << " Scanner geometry (BlocksOnCylindrical/Cylindrical/Generic) := " - <=0) - s << " Distance between crystals in axial direction (cm) := " - << get_axial_crystal_spacing()/10 << '\n'; - if (get_transaxial_crystal_spacing() >=0) - s << " Distance between crystals in transaxial direction (cm) := " - << get_transaxial_crystal_spacing()/10 << '\n'; - if (get_axial_block_spacing() >=0) - s << " Distance between blocks in axial direction (cm) := " - << get_axial_block_spacing()/10 << '\n'; - if (get_transaxial_block_spacing() >=0) - s << " Distance between blocks in transaxial direction (cm) := " - << get_transaxial_block_spacing()/10 << '\n'; + { + s << " Scanner geometry (BlocksOnCylindrical/Cylindrical/Generic) := " << get_scanner_geometry() << '\n'; + } + if (get_axial_crystal_spacing() >= 0) + s << " Distance between crystals in axial direction (cm) := " << get_axial_crystal_spacing() / 10 << '\n'; + if (get_transaxial_crystal_spacing() >= 0) + s << " Distance between crystals in transaxial direction (cm) := " << get_transaxial_crystal_spacing() / 10 << '\n'; + if (get_axial_block_spacing() >= 0) + s << " Distance between blocks in axial direction (cm) := " << get_axial_block_spacing() / 10 << '\n'; + if (get_transaxial_block_spacing() >= 0) + s << " Distance between blocks in transaxial direction (cm) := " << get_transaxial_block_spacing() / 10 << '\n'; s << "End scanner parameters:=\n"; return s.str(); } -string Scanner::list_names() const +string +Scanner::list_names() const { std::ostringstream s; auto iterator = list_of_names.begin(); s << *iterator; ++iterator; - while(iterator!=list_of_names.end()) - { - s << " , " << *iterator ; - ++iterator; - } + while (iterator != list_of_names.end()) + { + s << " , " << *iterator; + ++iterator; + } return s.str(); } @@ -1488,16 +1994,16 @@ 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, @@ -1506,20 +2012,20 @@ Scanner* Scanner::ask_parameters() if (scanner_ptr->type != Unknown_scanner && scanner_ptr->type != User_defined_scanner) { if (!scanner_ptr->has_energy_information()) - warning("Energy information not set, which is needed in scatter simulation. If you need it, set" - "\n Energy Resolution :=\n Reference energy (in keV)\t:=" - "\nmanually in your interfile header before 'end scanner parameters:='."); - - //This is needed for finding effective central bin size, because it is different for different geometries. - const string ScannerGeometry = - ask_string("Enter the scanner geometry ( BlocksOnCylindrical / Cylindrical / Generic ) :", "Cylindrical"); + warning("Energy information not set, which is needed in scatter simulation. If you need it, set" + "\n Energy Resolution :=\n Reference energy (in keV)\t:=" + "\nmanually in your interfile header before 'end scanner parameters:='."); + + // This is needed for finding effective central bin size, because it is different for different geometries. + const string ScannerGeometry + = ask_string("Enter the scanner geometry ( BlocksOnCylindrical / Cylindrical / Generic ) :", "Cylindrical"); if (ScannerGeometry == "Generic") - { - string CrystalMapFileName = ask_string("Enter the name of the crystal map: ", ""); - scanner_ptr->set_crystal_map_file_name(CrystalMapFileName); - } - + { + string CrystalMapFileName = ask_string("Enter the name of the crystal map: ", ""); + scanner_ptr->set_crystal_map_file_name(CrystalMapFileName); + } + // will also read detector-map from file scanner_ptr->set_scanner_geometry(ScannerGeometry); @@ -1532,184 +2038,168 @@ Scanner* Scanner::ask_parameters() 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,16,8); - int TransaxialCrystalsPerBlock = - ask_num("Enter number of transaxial crystals per block: ",0,16,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); - - 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 (as FWHM/reference_energy) of the scanner (expected to be less than 1): ", 0.0f, 20.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); - - const string ScannerGeometry = - ask_string("Enter the scanner geometry ( BlocksOnCylindrical / Cylindrical / Generic ) :", "Cylindrical"); - - float AxialCrystalSpacing= - ask_num("Enter crystal spacing in axial direction (in mm): ",0.F,30.F,6.75F); - float TransaxialCrystalSpacing= - ask_num("Enter crystal spacing in transaxial direction (in mm): ",0.F,30.F,6.75F); - float AxialBlockSpacing= - ask_num("Enter block spacing in axial direction (in mm): ",0.F,360.F,54.F); - float TransaxialBlockSpacing= - ask_num("Enter block spacing in transaxial direction (in mm): ",0.F,360.F,54.F); - - string crystal_map_file_name = ""; - if (ScannerGeometry == "Generic") { - crystal_map_file_name = - ask_string("Enter the name of the crystal map: ", ""); - } - + 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, 16, 8); + int TransaxialCrystalsPerBlock = ask_num("Enter number of transaxial crystals per block: ", 0, 16, 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); + + 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 (as FWHM/reference_energy) of the scanner (expected to be less than 1): ", + 0.0f, + 20.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); + + const string ScannerGeometry + = ask_string("Enter the scanner geometry ( BlocksOnCylindrical / Cylindrical / Generic ) :", "Cylindrical"); + + float AxialCrystalSpacing = ask_num("Enter crystal spacing in axial direction (in mm): ", 0.F, 30.F, 6.75F); + float TransaxialCrystalSpacing = ask_num("Enter crystal spacing in transaxial direction (in mm): ", 0.F, 30.F, 6.75F); + float AxialBlockSpacing = ask_num("Enter block spacing in axial direction (in mm): ", 0.F, 360.F, 54.F); + float TransaxialBlockSpacing = ask_num("Enter block spacing in transaxial direction (in mm): ", 0.F, 360.F, 54.F); + + string crystal_map_file_name = ""; + if (ScannerGeometry == "Generic") + { + crystal_map_file_name = ask_string("Enter the name of the crystal map: ", ""); + } + 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, - ScannerGeometry, - TransaxialCrystalSpacing, - AxialCrystalSpacing, - AxialBlockSpacing, - TransaxialBlockSpacing, - crystal_map_file_name); - - if (scanner_ptr->check_consistency()==Succeeded::yes || - !ask("Ask questions again?",true)) - return scanner_ptr; + 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, + ScannerGeometry, + TransaxialCrystalSpacing, + AxialCrystalSpacing, + AxialBlockSpacing, + TransaxialBlockSpacing, + crystal_map_file_name); + + if (scanner_ptr->check_consistency() == Succeeded::yes || !ask("Ask questions again?", true)) + return scanner_ptr; delete scanner_ptr; } // infinite loop } - - -Scanner * +Scanner* Scanner::get_scanner_from_name(const string& name) { - Scanner * scanner_ptr; + Scanner* scanner_ptr; - const string matching_name = - standardise_interfile_keyword(name); - Type type= E931; + 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; - } + { + 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; + } - // we didn't find it yet - delete scanner_ptr; - // tricky business to find next type - int int_type = type; - ++int_type; - type = static_cast(int_type); - } + // we didn't find it yet + delete scanner_ptr; + // tricky business to find next type + int int_type = type; + ++int_type; + type = static_cast(int_type); + } // it's not in the list return new Scanner(Unknown_scanner); } - -string Scanner:: list_all_names() +string +Scanner::list_all_names() { std::ostringstream s; - Type type= E931; + Type type = E931; while (type != Unknown_scanner) - { - Scanner scanner(type); - // tricky business to find next type - type = static_cast(static_cast(type)+1); - if (scanner.get_type() == User_defined_scanner) - continue; - s << scanner.list_names() << '\n'; - } + { + Scanner scanner(type); + // tricky business to find next type + type = static_cast(static_cast(type) + 1); + if (scanner.get_type() == User_defined_scanner) + continue; + s << scanner.list_names() << '\n'; + } return s.str(); } -std::list Scanner::get_names_of_predefined_scanners() +std::list +Scanner::get_names_of_predefined_scanners() { std::list ret; - Type type= E931; + Type type = E931; while (type != Unknown_scanner) - { - Scanner scanner(type); - // tricky business to find next type - type = static_cast(static_cast(type)+1); - if (scanner.get_type() == User_defined_scanner) - continue; - ret.push_back(scanner.get_name()); - } + { + Scanner scanner(type); + // tricky business to find next type + type = static_cast(static_cast(type) + 1); + if (scanner.get_type() == User_defined_scanner) + continue; + ret.push_back(scanner.get_name()); + } return ret; } -float Scanner::get_coincidence_window_width_in_ps() const +float +Scanner::get_coincidence_window_width_in_ps() const { const auto w = this->get_size_of_timing_pos(); if (this->is_tof_ready()) return this->get_max_num_timing_poss() * w; // presumably non-TOF - if (w>0) + if (w > 0) return w; error("Scanner coincidence window currently unknown. Sorry"); return 0.F; // to avoid compiler warning diff --git a/src/buildblock/Segment.cxx b/src/buildblock/Segment.cxx index a7628fa6a..d0dc81f9e 100644 --- a/src/buildblock/Segment.cxx +++ b/src/buildblock/Segment.cxx @@ -30,71 +30,49 @@ 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() - ); + 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()) + 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() - ); + 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()) + 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() - ); + 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()) + 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() - ); + 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 952d6a4a1..3905b213f 100644 --- a/src/buildblock/SegmentBySinogram.cxx +++ b/src/buildblock/SegmentBySinogram.cxx @@ -29,103 +29,91 @@ START_NAMESPACE_STIR - - template -SegmentBySinogram :: -SegmentBySinogram(const Array<3,elemT>& v, - const shared_ptr& pdi_ptr, - const SegmentIndices& ind) - : - Segment(pdi_ptr, ind), - Array<3,elemT>(v) +SegmentBySinogram::SegmentBySinogram(const Array<3, elemT>& v, + const shared_ptr& pdi_ptr, + const SegmentIndices& ind) + : Segment(pdi_ptr, ind), + 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(ind.segment_num())); - assert( get_max_axial_pos_num() == pdi_ptr->get_max_axial_pos_num(ind.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()); + 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(ind.segment_num())); + assert(get_max_axial_pos_num() == pdi_ptr->get_max_axial_pos_num(ind.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 SegmentIndices& ind) - : - Segment(pdi_ptr, ind), - Array<3,elemT>(IndexRange3D(pdi_ptr->get_min_axial_pos_num(ind.segment_num()), - pdi_ptr->get_max_axial_pos_num(ind.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 SegmentIndices& ind) + : Segment(pdi_ptr, ind), + Array<3, elemT>(IndexRange3D(pdi_ptr->get_min_axial_pos_num(ind.segment_num()), + pdi_ptr->get_max_axial_pos_num(ind.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 Array<3,elemT>& v, - const shared_ptr& pdi_sptr, - int segment_num, int timing_pos_num) - : - SegmentBySinogram(v, pdi_sptr, SegmentIndices(segment_num, timing_pos_num)) +SegmentBySinogram::SegmentBySinogram(const Array<3, elemT>& v, + const shared_ptr& pdi_sptr, + int segment_num, + int timing_pos_num) + : SegmentBySinogram(v, pdi_sptr, SegmentIndices(segment_num, timing_pos_num)) {} template -SegmentBySinogram:: -SegmentBySinogram(const shared_ptr& pdi_sptr, - const int segment_num, const int t_num) - : - SegmentBySinogram(pdi_sptr, SegmentIndices(segment_num, t_num)) +SegmentBySinogram::SegmentBySinogram(const shared_ptr& pdi_sptr, + const int segment_num, + const int t_num) + : SegmentBySinogram(pdi_sptr, SegmentIndices(segment_num, t_num)) {} template -SegmentBySinogram:: -SegmentBySinogram(const SegmentByView& s_v ) - - : Segment(s_v.get_proj_data_info_sptr()->create_shared_clone(), - s_v.get_segment_indices()), - 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())) +SegmentBySinogram::SegmentBySinogram(const SegmentByView& s_v) + + : Segment(s_v.get_proj_data_info_sptr()->create_shared_clone(), s_v.get_segment_indices()), + 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++) + + 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 +template +bool +SegmentBySinogram::operator==(const Segment& that) const { - return - this->has_same_characteristics(that) && - Array<3,elemT>::operator==(static_cast(that)); + return this->has_same_characteristics(that) && Array<3, elemT>::operator==(static_cast(that)); } - template -Viewgram +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... - // 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(), this->get_timing_pos_num()); + 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(), 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]; + 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]; } /*! @@ -133,14 +121,13 @@ SegmentBySinogram::set_viewgram(const Viewgram& viewgram) 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(); @@ -150,29 +137,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 7e5dd443e..06e20b2b7 100644 --- a/src/buildblock/SegmentByView.cxx +++ b/src/buildblock/SegmentByView.cxx @@ -28,117 +28,100 @@ START_NAMESPACE_STIR - template -SegmentByView:: -SegmentByView(const Array<3,elemT>& v, - const shared_ptr& pdi_ptr, - const SegmentIndices& ind) - : - Segment(pdi_ptr, ind), - Array<3,elemT>(v) +SegmentByView::SegmentByView(const Array<3, elemT>& v, + const shared_ptr& pdi_ptr, + const SegmentIndices& ind) + : Segment(pdi_ptr, ind), + 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(ind.segment_num())); - assert( get_max_axial_pos_num() == pdi_ptr->get_max_axial_pos_num(ind.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()); - + 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(ind.segment_num())); + assert(get_max_axial_pos_num() == pdi_ptr->get_max_axial_pos_num(ind.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 SegmentIndices& ind) - : - Segment(pdi_ptr, ind), - Array<3,elemT>(IndexRange3D(pdi_ptr->get_min_view_num(), - pdi_ptr->get_max_view_num(), - pdi_ptr->get_min_axial_pos_num(ind.segment_num()), - pdi_ptr->get_max_axial_pos_num(ind.segment_num()), - pdi_ptr->get_min_tangential_pos_num(), - pdi_ptr->get_max_tangential_pos_num())) +SegmentByView::SegmentByView(const shared_ptr& pdi_ptr, const SegmentIndices& ind) + : Segment(pdi_ptr, ind), + Array<3, elemT>(IndexRange3D(pdi_ptr->get_min_view_num(), + pdi_ptr->get_max_view_num(), + pdi_ptr->get_min_axial_pos_num(ind.segment_num()), + pdi_ptr->get_max_axial_pos_num(ind.segment_num()), + pdi_ptr->get_min_tangential_pos_num(), + pdi_ptr->get_max_tangential_pos_num())) {} template -SegmentByView:: -SegmentByView(const Array<3,elemT>& v, - const shared_ptr& pdi_sptr, - const int segment_num, const int t_num) - : - SegmentByView(v, pdi_sptr, SegmentIndices(segment_num, t_num)) +SegmentByView::SegmentByView(const Array<3, elemT>& v, + const shared_ptr& pdi_sptr, + const int segment_num, + const int t_num) + : SegmentByView(v, pdi_sptr, SegmentIndices(segment_num, t_num)) {} template -SegmentByView:: -SegmentByView(const shared_ptr& pdi_sptr, - const int segment_num, const int t_num) - : SegmentByView(pdi_sptr, SegmentIndices(segment_num, t_num)) +SegmentByView::SegmentByView(const shared_ptr& pdi_sptr, const int segment_num, const int t_num) + : SegmentByView(pdi_sptr, SegmentIndices(segment_num, t_num)) {} template SegmentByView::SegmentByView(const SegmentBySinogram& s_s) - : Segment(s_s.get_proj_data_info_sptr()->create_shared_clone(), - s_s.get_segment_indices()), - 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_indices()), + 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 +template +bool +SegmentByView::operator==(const Segment& that) const { - return - this->has_same_characteristics(that) && - Array<3,elemT>::operator==(static_cast(that)); + return this->has_same_characteristics(that) && Array<3, elemT>::operator==(static_cast(that)); } template -Sinogram +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(), this->get_timing_pos_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]; + 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 @@ -148,18 +131,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); } /*! @@ -167,9 +149,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); } @@ -180,5 +161,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 639b61cf3..360ecf7a7 100644 --- a/src/buildblock/SeparableArrayFunctionObject.cxx +++ b/src/buildblock/SeparableArrayFunctionObject.cxx @@ -26,39 +26,34 @@ 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 +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 + // 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)); + 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()); } } @@ -72,7 +67,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 @@ -80,7 +75,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()); @@ -92,26 +87,20 @@ do_it(Array& out_array, const Array& #endif template -bool -SeparableArrayFunctionObject:: -is_trivial() const +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; + 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 74a5acce8..6bb7be33f 100644 --- a/src/buildblock/SeparableCartesianMetzImageFilter.cxx +++ b/src/buildblock/SeparableCartesianMetzImageFilter.cxx @@ -24,49 +24,38 @@ 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 +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); + // assert(consistency_check(in_density) == Succeeded::yes); + metz_filter(out_density, in_density); } #if 0 @@ -96,49 +85,48 @@ 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"); @@ -147,25 +135,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; @@ -174,6 +158,3 @@ SeparableCartesianMetzImageFilter::registered_name = template class SeparableCartesianMetzImageFilter; END_NAMESPACE_STIR - - - diff --git a/src/buildblock/SeparableConvolutionImageFilter.cxx b/src/buildblock/SeparableConvolutionImageFilter.cxx index 951ab40b0..822a5ae3b 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 */ @@ -28,208 +28,165 @@ 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 auto coefficients_iter = filter_coefficients.begin(); auto parsing_iter = filter_coefficients_for_parsing.begin(); - for (; - parsing_iter != filter_coefficients_for_parsing.end(); - ++parsing_iter, ++coefficients_iter) + 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); + 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. auto coefficients_elem_iter = coefficients_iter->begin(); auto 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); + 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) +SeparableConvolutionImageFilter::SeparableConvolutionImageFilter() + : filter_coefficients_for_parsing(3) { - set_defaults(); + set_defaults(); } - template -SeparableConvolutionImageFilter:: -SeparableConvolutionImageFilter( - const VectorWithOffset< VectorWithOffset >& - filter_coefficients) - : - filter_coefficients_for_parsing(filter_coefficients.get_length()), - filter_coefficients(filter_coefficients) +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 + 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 auto coefficients_iter = filter_coefficients.begin(); auto parsing_iter = filter_coefficients_for_parsing.begin(); - for (; - parsing_iter != filter_coefficients_for_parsing.end(); - ++parsing_iter, ++coefficients_iter) + 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; + 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]; + 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]; } - } template VectorWithOffset> -SeparableConvolutionImageFilter:: -get_filter_coefficients() +SeparableConvolutionImageFilter::get_filter_coefficients() { return filter_coefficients; } -template +template void -SeparableConvolutionImageFilter:: -set_filter_coefficients(const VectorWithOffset>& v) +SeparableConvolutionImageFilter::set_filter_coefficients(const VectorWithOffset>& v) { filter_coefficients = v; } template VectorWithOffset -SeparableConvolutionImageFilter:: -get_filter_coefficients(const int axis) +SeparableConvolutionImageFilter::get_filter_coefficients(const int axis) { return filter_coefficients[axis]; } -template +template void -SeparableConvolutionImageFilter:: -set_filter_coefficients(const int axis, const VectorWithOffset& v) +SeparableConvolutionImageFilter::set_filter_coefficients(const int axis, const VectorWithOffset& v) { filter_coefficients[axis] = v; } template Succeeded -SeparableConvolutionImageFilter:: -virtual_set_up(const DiscretisedDensity<3,elemT>& density) +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) + 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); + } + 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 +SeparableConvolutionImageFilter::virtual_apply(DiscretisedDensity<3, elemT>& out_density, + const DiscretisedDensity<3, elemT>& in_density) const { - filter(out_density,in_density); + 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 4c8c01327..edd75dcdc 100644 --- a/src/buildblock/SeparableGaussianArrayFilter.cxx +++ b/src/buildblock/SeparableGaussianArrayFilter.cxx @@ -44,130 +44,122 @@ using std::iostream; using std::cerr; using std::endl; - START_NAMESPACE_STIR template -SeparableGaussianArrayFilter:: -SeparableGaussianArrayFilter() -:fwhms(0),max_kernel_sizes(0) +SeparableGaussianArrayFilter::SeparableGaussianArrayFilter() + : fwhms(0), + max_kernel_sizes(0) { - for (int i=1;i<=num_dimensions;i++) + 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) + : fwhms(fwhms_v), + max_kernel_sizes(max_kernel_sizes_v) { - construct_filter(normalise); + construct_filter(normalise); } - template void -SeparableGaussianArrayFilter:: -construct_filter(bool normalise) +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); - + for (int i = 1; i <= num_dimensions; i++) { - std::stringstream ss; - ss << "Gaussian filter dim[" << i << "] =" << filter_coefficients; - info(ss.str(), 2); - } + VectorWithOffset filter_coefficients; + calculate_coefficients(filter_coefficients, max_kernel_sizes[i], fwhms[i], normalise); - this->all_1d_array_filters[i-1]. - reset(new ArrayFilter1DUsingConvolution(filter_coefficients)); + { + 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)); + } } -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) - { + if (standard_deviation == 0) + { filter_coefficients.recycle(); return; - } + } - int kernel_length = max_kernel_sizes/2; - if (max_kernel_sizes<0) + int kernel_length = max_kernel_sizes / 2; + if (max_kernel_sizes < 0) { - const double ZERO_TOL= 0.000001; // consistent with other files + 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)); + 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.grow(-kernel_length, kernel_length); - filter_coefficients[0] = static_cast(1/sqrt(2*_PI)/standard_deviation); + 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)); - } + 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 + // normalisation: rescaled to dc =1 -if (normalise) + if (normalise) { - double sum = 0.; - for (int i =filter_coefficients.get_min_index();i<=filter_coefficients.get_max_index();i++) + double sum = 0.; + for (int i = filter_coefficients.get_min_index(); i <= filter_coefficients.get_max_index(); i++) { - sum +=double (filter_coefficients[i]); + sum += double(filter_coefficients[i]); } - for (int i =filter_coefficients.get_min_index();i<=filter_coefficients.get_max_index();i++) + for (int i = filter_coefficients.get_min_index(); i <= filter_coefficients.get_max_index(); i++) { - filter_coefficients[i] /= sum; + 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 a673e7103..1aa78626a 100644 --- a/src/buildblock/SeparableGaussianImageFilter.cxx +++ b/src/buildblock/SeparableGaussianImageFilter.cxx @@ -28,154 +28,129 @@ 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; } - - 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() +SeparableGaussianImageFilter::get_normalised_filter() { - return normalise; + 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() +SeparableGaussianImageFilter::set_defaults() { - base_type::set_defaults(); - fwhms.fill(0); - max_kernel_sizes.fill(-1); - normalise = true; - + base_type::set_defaults(); + fwhms.fill(0); + max_kernel_sizes.fill(-1); + normalise = true; } template void -SeparableGaussianImageFilter:: -initialise_keymap() +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"); + 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) +SeparableGaussianImageFilter::set_fwhms(const BasicCoordinate& arg) { - fwhms = BasicCoordinate(arg); + fwhms = BasicCoordinate(arg); } template void -SeparableGaussianImageFilter:: -set_max_kernel_sizes(const BasicCoordinate< num_dimensions,int>& arg) +SeparableGaussianImageFilter::set_max_kernel_sizes(const BasicCoordinate& arg) { - max_kernel_sizes = 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 afbc3f8f2..4906536ce 100644 --- a/src/buildblock/SeparableMetzArrayFilter.cxx +++ b/src/buildblock/SeparableMetzArrayFilter.cxx @@ -37,32 +37,26 @@ 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); @@ -70,168 +64,166 @@ SeparableMetzArrayFilter 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) - { - 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)); - - } + + 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; 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) -{ - +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); - - /* 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); - - /* build gaussian */ - 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=1;i<(Res/2);i++) { - fftdata[Res-(Res/2)+i].real(filter[i-1]); - } - /* FFT to frequency space */ - fourier(fftdata); - - /* Build Metz */ - N++; - - int cutoff=(int) (sampling_interval*Res/(2*MmPerVox)); - //cerr< 0.0F) { - elemT xreal = fftdata[i].real(); - elemT ximg = fftdata[i].imag(); - elemT zabs2= xreal*xreal+ximg*ximg; - filter[i]=0.0; // use this loop to clear the array for later - - - //MJ 26/05/99 cut off the filter - if(stretch>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)--; - - } - - + + // 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); + + /* 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); + + /* build gaussian */ + 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 = 1; i < (Res / 2); i++) + { + fftdata[Res - (Res / 2) + i].real(filter[i - 1]); + } + + /* FFT to frequency space */ + fourier(fftdata); + + /* 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; 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){ @@ -239,36 +231,33 @@ void build_metz(VectorWithOffset& kernel, } #endif - 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; - } - - else{ - //VectorWithOffset kernel(1);//=new elemT[1]; - kernel.grow(0,0); - //*kernel=1.0F; - //kernel_length=1L; - kernel[0] = 1.F; - kernel_length=1; - - //return kernel; - } + 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; + } + + else + { + // VectorWithOffset kernel(1);//=new elemT[1]; + kernel.grow(0, 0); + //*kernel=1.0F; + // kernel_length=1L; + kernel[0] = 1.F; + 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 95230e78c..47f40b9da 100644 --- a/src/buildblock/Sinogram.cxx +++ b/src/buildblock/Sinogram.cxx @@ -28,102 +28,76 @@ #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()) + 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() - ); + 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()) + 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() - ); + 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()) + 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() - ); + 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()) + 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() - ); + 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 +template +bool +Sinogram::operator==(const self_type& that) const { - return - this->has_same_characteristics(that) && - base_type::operator==(that); + 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; @@ -131,17 +105,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); } /*! @@ -149,9 +122,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 ec93898c9..d3bfd4dfe 100644 --- a/src/buildblock/TextWriter.cxx +++ b/src/buildblock/TextWriter.cxx @@ -6,22 +6,25 @@ aTextWriter* TextWriterHandle::information_channel_; aTextWriter* TextWriterHandle::warning_channel_; aTextWriter* TextWriterHandle::error_channel_; -void writeText(const char* text, OUTPUT_CHANNEL channel) { +void +writeText(const char* text, OUTPUT_CHANNEL channel) +{ #if defined(STIR_OPENMP) - #pragma omp critical(TEXTWRITER) +# pragma omp critical(TEXTWRITER) #endif { 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); - } + 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); + } } } diff --git a/src/buildblock/ThresholdMinToSmallPositiveValueDataProcessor.cxx b/src/buildblock/ThresholdMinToSmallPositiveValueDataProcessor.cxx index 74bcc13a8..18c596f44 100644 --- a/src/buildblock/ThresholdMinToSmallPositiveValueDataProcessor.cxx +++ b/src/buildblock/ThresholdMinToSmallPositiveValueDataProcessor.cxx @@ -20,94 +20,74 @@ #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 625780a10..5fd8e277c 100644 --- a/src/buildblock/TimeFrameDefinitions.cxx +++ b/src/buildblock/TimeFrameDefinitions.cxx @@ -9,11 +9,11 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup buildblock \brief Implementation of class stir::TimeFrameDefinitions - + \author Kris Thielemans */ @@ -21,8 +21,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" @@ -46,118 +46,106 @@ using std::ifstream; START_NAMESPACE_STIR - double -TimeFrameDefinitions:: -get_start_time(unsigned int frame_num) const +TimeFrameDefinitions::get_start_time(unsigned int frame_num) const { if (frame_num > frame_times.size()) - throw std::runtime_error("TimeFrameDefinitions: asked for frame " + std::to_string(frame_num) - + ", but only " + std::to_string(frame_times.size()) + " frames present."); - return frame_times[frame_num-1].first; + throw std::runtime_error("TimeFrameDefinitions: asked for frame " + std::to_string(frame_num) + ", but only " + + std::to_string(frame_times.size()) + " frames present."); + return frame_times[frame_num - 1].first; } double -TimeFrameDefinitions:: -get_end_time(unsigned int frame_num) const +TimeFrameDefinitions::get_end_time(unsigned int frame_num) const { if (frame_num > frame_times.size()) - throw std::runtime_error("TimeFrameDefinitions: asked for frame " + std::to_string(frame_num) - + ", but only " + std::to_string(frame_times.size()) + " frames present."); - return frame_times[frame_num-1].second; + throw std::runtime_error("TimeFrameDefinitions: asked for frame " + std::to_string(frame_num) + ", but only " + + std::to_string(frame_times.size()) + " frames present."); + return frame_times[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 +unsigned int +TimeFrameDefinitions::get_time_frame_num(const double start_time, const double end_time) const { - assert(end_time >=start_time); + assert(end_time >= start_time); if (this->get_num_frames() == 0) throw std::runtime_error("TimeFrameDefinitions::get_time_frame_num called, but not time frames defined for this data."); - for (unsigned int i = 1; i <=this->get_num_frames(); i++) + 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; - } + 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)) + 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); + 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); + if (!hdr.parse(filename.c_str(), false)) // silent parsing + { + error(boost::format("Parsing of Interfile header failed for file '%s'") % filename); + } + *this = hdr.get_exam_info().time_frame_definitions; } - *this = hdr.get_exam_info().time_frame_definitions; - } - else - read_fdef_file(filename); + else + read_fdef_file(filename); #if 0 cerr << "Frame definitions:\n{"; @@ -172,122 +160,120 @@ 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) - { - 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 - // (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; + 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 + // (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 (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) +TimeFrameDefinitions::TimeFrameDefinitions(const vector>& frame_times) + : frame_times(frame_times) { - if (get_num_frames()==0) + 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) + 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); + 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)); + 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) + 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]; + 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) +TimeFrameDefinitions::set_time_frame(const int frame_num, const double start, const double end) { if (frame_num > frame_times.size()) - throw std::runtime_error("TimeFrameDefinitions::set_time_frame called for frame " + std::to_string(frame_num) - + ", but only " + std::to_string(frame_times.size()) + " frames present."); - frame_times.at(frame_num-1).first = start; - frame_times.at(frame_num-1).second = end; + throw std::runtime_error("TimeFrameDefinitions::set_time_frame called for frame " + std::to_string(frame_num) + ", but only " + + std::to_string(frame_times.size()) + " frames present."); + 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; + return this->_gate_sequence[num - 1].second; } unsigned int -TimeGateDefinitions:: -get_gate_num(unsigned int num) const +TimeGateDefinitions::get_gate_num(unsigned int num) const { - return this->_gate_sequence[num-1].first; + 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::TimeGateDefinitions(const string& gdef_filename) { - TimeGateDefinitions::read_gdef_file(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"; + 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) @@ -92,57 +83,48 @@ read_gdef_file(const string& gdef_filename) in >> gate_num >> duration; if (!in) break; - if (gate_num<0 || (gate_num>0 && duration<0)) + 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); + "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 (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) + 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; + 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) + 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]; + 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]; } } diff --git a/src/buildblock/TruncateToCylindricalFOVImageProcessor.cxx b/src/buildblock/TruncateToCylindricalFOVImageProcessor.cxx index b1388526d..f816e4ab4 100644 --- a/src/buildblock/TruncateToCylindricalFOVImageProcessor.cxx +++ b/src/buildblock/TruncateToCylindricalFOVImageProcessor.cxx @@ -23,15 +23,11 @@ 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"); @@ -39,69 +35,54 @@ initialise_keymap() 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; this->_truncate_rim = 0; } - - 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, this->_truncate_rim, this->_strictly_less_than_radius); +{ + truncate_rim(density, this->_truncate_rim, 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; @@ -110,6 +91,3 @@ TruncateToCylindricalFOVImageProcessor() template class TruncateToCylindricalFOVImageProcessor; END_NAMESPACE_STIR - - - diff --git a/src/buildblock/Verbosity.cxx b/src/buildblock/Verbosity.cxx index bb72c00ab..28894b283 100644 --- a/src/buildblock/Verbosity.cxx +++ b/src/buildblock/Verbosity.cxx @@ -23,23 +23,26 @@ 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::Verbosity() +{ _verbosity_level = 2; }; -int Verbosity::get() +int +Verbosity::get() { - if (!_instance) // Only allow one instance of class to be generated. + if (!_instance) // Only allow one instance of class to be generated. _instance = new Verbosity; return _instance->_verbosity_level; } -void Verbosity::set(int level) +void +Verbosity::set(int level) { - if (!_instance) // Only allow one instance of class to be generated. + 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 c5559c750..77f24e014 100644 --- a/src/buildblock/Viewgram.cxx +++ b/src/buildblock/Viewgram.cxx @@ -27,88 +27,63 @@ #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()) + 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() - ); + 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()) + 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() - ); + 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()) + 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() - ); + 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()) + 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() - ); + 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 +template +bool +Viewgram::operator==(const self_type& that) const { - return - this->has_same_characteristics(that) && - base_type::operator==(that); + 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); } @@ -118,18 +93,17 @@ 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()); @@ -139,24 +113,20 @@ 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 a4ee7315d..2bfb2e54e 100644 --- a/src/buildblock/VoxelsOnCartesianGrid.cxx +++ b/src/buildblock/VoxelsOnCartesianGrid.cxx @@ -11,11 +11,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 \author Parisa Khateri @@ -52,67 +52,55 @@ 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 + { + // the case of cylindrical data - 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 + z_sampling = proj_data_info_cyl_ptr->get_ring_spacing() / 2; - // 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); + // for 'span>1' case, we take z_size = number of sinograms in segment 0 + // for 'span==1' case, we take 2*num_rings-1 - 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 (const ProjDataInfoBlocksOnCylindrical* - proj_data_info_blk_ptr = - dynamic_cast(proj_data_info_ptr)) - { - // the case of BlocksOnCylindrical data + // 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); - z_sampling = proj_data_info_blk_ptr->get_ring_spacing()/2; + 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 (const ProjDataInfoBlocksOnCylindrical* proj_data_info_blk_ptr + = dynamic_cast(proj_data_info_ptr)) + { + // the case of BlocksOnCylindrical data - // for 'span>1' case, we take z_size = number of sinograms in segment 0 - // for 'span==1' case, we take 2*num_rings-1 + z_sampling = proj_data_info_blk_ptr->get_ring_spacing() / 2; - // first check if we have segment 0 - assert(proj_data_info_blk_ptr->get_min_segment_num() <= 0); - assert(proj_data_info_blk_ptr->get_max_segment_num() >= 0); + // for 'span>1' case, we take z_size = number of sinograms in segment 0 + // for 'span==1' case, we take 2*num_rings-1 - if (z_size<0) - z_size = - proj_data_info_blk_ptr->get_max_ring_difference(0) > - proj_data_info_blk_ptr->get_min_ring_difference(0) - ? proj_data_info_blk_ptr->get_num_axial_poss(0) - : 2*proj_data_info_blk_ptr->get_num_axial_poss(0) - 1; - } - else if (const ProjDataInfoGeneric* - proj_data_info_gen_ptr = - dynamic_cast(proj_data_info_ptr)) + // first check if we have segment 0 + assert(proj_data_info_blk_ptr->get_min_segment_num() <= 0); + assert(proj_data_info_blk_ptr->get_max_segment_num() >= 0); + + if (z_size < 0) + z_size = proj_data_info_blk_ptr->get_max_ring_difference(0) > proj_data_info_blk_ptr->get_min_ring_difference(0) + ? proj_data_info_blk_ptr->get_num_axial_poss(0) + : 2 * proj_data_info_blk_ptr->get_num_axial_poss(0) - 1; + } + else if (const ProjDataInfoGeneric* proj_data_info_gen_ptr = dynamic_cast(proj_data_info_ptr)) { // the case of Generic data - z_sampling = proj_data_info_gen_ptr->get_ring_spacing()/2; + z_sampling = proj_data_info_gen_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 @@ -121,151 +109,124 @@ static void find_sampling_and_z_size( assert(proj_data_info_gen_ptr->get_min_segment_num() <= 0); assert(proj_data_info_gen_ptr->get_max_segment_num() >= 0); - if (z_size<0) - z_size = - proj_data_info_gen_ptr->get_max_ring_difference(0) > - proj_data_info_gen_ptr->get_min_ring_difference(0) - ? proj_data_info_gen_ptr->get_num_axial_poss(0) - : 2*proj_data_info_gen_ptr->get_num_axial_poss(0) - 1; + if (z_size < 0) + z_size = proj_data_info_gen_ptr->get_max_ring_difference(0) > proj_data_info_gen_ptr->get_min_ring_difference(0) + ? proj_data_info_gen_ptr->get_num_axial_poss(0) + : 2 * proj_data_info_gen_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)); - - if (z_size<0) - z_size = proj_data_info_ptr->get_num_axial_poss(0); - } + { + // 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)); + + 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(); + 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)); + 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); + "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); + 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) +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); + 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) +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); + 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 +template VoxelsOnCartesianGrid::VoxelsOnCartesianGrid(const ProjDataInfo& proj_data_info, - const float zoom, + 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, - 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, +template +VoxelsOnCartesianGrid::VoxelsOnCartesianGrid(const shared_ptr& exam_info_sptr_v, const ProjDataInfo& proj_data_info, - const float zoom, + 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, - 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, +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); + 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 @@ -274,73 +235,68 @@ 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) + if (sizes.x() == -1 || sizes.y() == -1) { std::vector radii; - for (int view=0; view=2*FOVradius_in_pixs+1 - const float FOVradius_in_mm = - *std::max_element(radii.begin(), radii.end()); - - 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; + const float FOVradius_in_mm = *std::max_element(radii.begin(), radii.end()); + + 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 (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(), - this->get_grid_spacing()); + 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 @@ -349,41 +305,38 @@ 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* 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 +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()) - ); + 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 +template +void VoxelsOnCartesianGrid::set_plane(const PixelsOnCartesianGrid& plane, const int z) { assert(this->get_min_x() == plane.get_min_x()); @@ -393,18 +346,18 @@ 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 +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 */ @@ -419,18 +372,16 @@ 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; @@ -438,10 +389,9 @@ get_min_indices() const 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; @@ -540,13 +490,14 @@ 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 >; -} +namespace stir +{ +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 2b127cb32..577f0b1a4 100644 --- a/src/buildblock/buildblock_registries.cxx +++ b/src/buildblock/buildblock_registries.cxx @@ -17,7 +17,7 @@ \brief File that registers all stir::RegisterObject children in buildblock \author Kris Thielemans - + */ #include "stir/SeparableCartesianMetzImageFilter.h" @@ -30,7 +30,7 @@ #include "stir/NonseparableConvolutionUsingRealDFTImageFilter.h" #include "stir/TruncateToCylindricalFOVImageProcessor.h" #ifdef HAVE_JSON -#include "stir/HUToMuImageProcessor.h" +# include "stir/HUToMuImageProcessor.h" #endif START_NAMESPACE_STIR @@ -40,9 +40,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 f84b7c642..af513cec8 100644 --- a/src/buildblock/centre_of_gravity.cxx +++ b/src/buildblock/centre_of_gravity.cxx @@ -9,15 +9,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" @@ -28,7 +27,6 @@ using std::min; using std::max; - START_NAMESPACE_STIR template @@ -37,116 +35,103 @@ 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; } template 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) + 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) + 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); + 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) +find_centre_of_gravity_in_mm_per_plane(VectorWithOffset>& 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++) - { - 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]; - } - allCoG[z].z() = static_cast(z); - allCoG[z] = image.get_physical_coordinates_for_indices(allCoG[z]); - } + 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]; + } + allCoG[z].z() = static_cast(z); + allCoG[z] = image.get_physical_coordinates_for_indices(allCoG[z]); + } } 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); + 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 @@ -154,8 +139,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 26319f9f7..122756174 100644 --- a/src/buildblock/date_time_functions.cxx +++ b/src/buildblock/date_time_functions.cxx @@ -8,9 +8,9 @@ */ /*! - \file + \file \ingroup date_time - + \brief Functions for date-time conversions \author Kris Thielemans @@ -27,7 +27,8 @@ START_NAMESPACE_STIR -int time_zone_offset_in_secs() +int +time_zone_offset_in_secs() { static bool first_run = true; static int tz_offset; @@ -37,23 +38,24 @@ int time_zone_offset_in_secs() 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"; + // 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)); + 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 @@ -63,8 +65,8 @@ 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; @@ -89,16 +91,16 @@ time_t unix_epoch_time_t() 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 @@ -119,11 +121,9 @@ parse_DICOM_TZ(const std::string& tz, const bool silent) 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); + 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; @@ -145,21 +145,24 @@ 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()); @@ -175,7 +178,7 @@ 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.size() > 0) { if (fraction[0] != '.') error("DICOM DT '" + str + "' is ill-formed for the fractional seconds"); @@ -190,42 +193,38 @@ double DICOM_datetime_to_secs_since_Unix_epoch(const std::string& str_org, bool } } } - 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) +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; + 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) { // 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; } @@ -236,30 +235,24 @@ Interfile_datetime_to_DICOM(const DateTimeStrings& dt) 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) +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); + 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) +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)); + 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 2a4a298d6..19abe6d18 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 @@ -27,37 +27,36 @@ #include #include - #include "stir/TextWriter.h" /* Warning: vsnprintf is only ISO C99. So your compiler might not have it. 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; + 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; - } + { + 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; throw std::runtime_error(msg); diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index 1b8b0cb25..da2a04ea7 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -6,11 +6,11 @@ This file is part of STIR. SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details */ /*! -\file +\file \ingroup projdata \brief Implementation of functions to extension of direct sinograms in view direction @@ -33,12 +33,14 @@ START_NAMESPACE_STIR /* This function takes symmetries into account to extend segments in any direction. However, it needs testing if it works for non-direct sinograms. */ -Array<3,float> -extend_segment(const SegmentBySinogram& segment, const int view_extension, - const int axial_extension, const int tangential_extension) +Array<3, float> +extend_segment(const SegmentBySinogram& segment, + const int view_extension, + const int axial_extension, + const int tangential_extension) { - Array<3,float> out(segment); - BasicCoordinate<3,int> min_dim, max_dim; + Array<3, float> out(segment); + BasicCoordinate<3, int> min_dim, max_dim; min_dim[1] = segment.get_min_index() - axial_extension; min_dim[2] = segment[0].get_min_index() - view_extension; min_dim[3] = segment[0][0].get_min_index() - tangential_extension; @@ -49,23 +51,25 @@ extend_segment(const SegmentBySinogram& segment, const int view_extension // fill the axial extensions with the same entries from the border for (int axial_edge = 0; axial_edge < axial_extension; axial_edge++) - { - out[min_dim[1] + axial_edge] = out[min_dim[1] + axial_extension]; - out[max_dim[1] - axial_edge] = out[max_dim[1] - axial_extension]; - } + { + out[min_dim[1] + axial_edge] = out[min_dim[1] + axial_extension]; + out[max_dim[1] - axial_edge] = out[max_dim[1] - axial_extension]; + } // check, whether the projection data cover 180° or 360° bool flip_views = false; bool extend_without_wrapping = false; - float min_phi=_PI, max_phi=-_PI; - for (auto view = segment.get_proj_data_info_sptr()->get_min_view_num(); view <= segment.get_proj_data_info_sptr()->get_max_view_num(); view++) - { - auto phi = segment.get_proj_data_info_sptr()->get_phi(Bin(0, view, 0, 0)); - if (phi < min_phi) - min_phi = phi; - if (phi > max_phi) - max_phi = phi; - } + float min_phi = _PI, max_phi = -_PI; + for (auto view = segment.get_proj_data_info_sptr()->get_min_view_num(); + view <= segment.get_proj_data_info_sptr()->get_max_view_num(); + view++) + { + auto phi = segment.get_proj_data_info_sptr()->get_phi(Bin(0, view, 0, 0)); + if (phi < min_phi) + min_phi = phi; + if (phi > max_phi) + max_phi = phi; + } const auto phi_range = max_phi - min_phi; const auto average_phi_sampling = phi_range / (segment.get_proj_data_info_sptr()->get_num_views() - 1); // check if 360 or 180 degrees @@ -73,62 +77,70 @@ extend_segment(const SegmentBySinogram& segment, const int view_extension if (abs(phi_range - 2 * _PI) < 5 * average_phi_sampling) flip_views = false; // if views cover 360°, we can simply wrap around else if ((abs(phi_range - _PI) < 5 * average_phi_sampling) && (segment.get_segment_num() == 0)) - flip_views = true; // if views cover 180°, the tangential positions need to be flipped + flip_views = true; // if views cover 180°, the tangential positions need to be flipped else - { - extend_without_wrapping = true; - warning("Extending ProjData by wrapping only works for view coverage of 180° or 360°. Instead, just extending with nearest neighbour."); - } + { + extend_without_wrapping = true; + warning("Extending ProjData by wrapping only works for view coverage of 180° or 360°. Instead, just extending with nearest " + "neighbour."); + } // fill the view extensions by wrapping around for (int view_edge = 0; view_edge < view_extension; view_edge++) - { - for (int axial_pos = min_dim[1]; axial_pos <= max_dim[1]; axial_pos++) { - if (extend_without_wrapping) - { - out[axial_pos][min_dim[2] + view_edge] = out[axial_pos][min_dim[2] + view_extension]; - out[axial_pos][max_dim[2] - view_extension] = out[axial_pos][max_dim[2] - view_extension]; - } - else if (flip_views) - { - const int sym_dim = std::min(abs(min_dim[3]), max_dim[3]); - for (int tang_pos = -sym_dim; tang_pos <= sym_dim; tang_pos++) + for (int axial_pos = min_dim[1]; axial_pos <= max_dim[1]; axial_pos++) { - out[axial_pos][min_dim[2] + view_edge][tang_pos] = out[axial_pos][max_dim[2] - 2 * view_extension + view_edge + 1][-tang_pos]; - out[axial_pos][max_dim[2] - view_extension + 1 + view_edge][tang_pos] = out[axial_pos][min_dim[2] + view_extension + view_edge][-tang_pos]; - } - for (int tang_pos = min_dim[3]; tang_pos < -sym_dim; tang_pos++) - { // fill in asymmetric tangential positions at the end by just picking the nearest existing element - out[axial_pos][min_dim[2] + view_edge][tang_pos] = out[axial_pos][max_dim[2] - 2 * view_extension + view_edge + 1][sym_dim]; - out[axial_pos][max_dim[2] - view_extension + 1 + view_edge][tang_pos] = out[axial_pos][min_dim[2] + view_extension + view_edge][sym_dim]; - } - for (int tang_pos = max_dim[3]; tang_pos > sym_dim; tang_pos--) - { // fill in asymmetric tangential positions at the end by just picking the nearest existing element - out[axial_pos][min_dim[2] + view_edge][tang_pos] = out[axial_pos][max_dim[2] - 2 * view_extension + view_edge + 1][-sym_dim]; - out[axial_pos][max_dim[2] - view_extension + 1 + view_edge][tang_pos] = out[axial_pos][min_dim[2] + view_extension + view_edge][-sym_dim]; + if (extend_without_wrapping) + { + out[axial_pos][min_dim[2] + view_edge] = out[axial_pos][min_dim[2] + view_extension]; + out[axial_pos][max_dim[2] - view_extension] = out[axial_pos][max_dim[2] - view_extension]; + } + else if (flip_views) + { + const int sym_dim = std::min(abs(min_dim[3]), max_dim[3]); + for (int tang_pos = -sym_dim; tang_pos <= sym_dim; tang_pos++) + { + out[axial_pos][min_dim[2] + view_edge][tang_pos] + = out[axial_pos][max_dim[2] - 2 * view_extension + view_edge + 1][-tang_pos]; + out[axial_pos][max_dim[2] - view_extension + 1 + view_edge][tang_pos] + = out[axial_pos][min_dim[2] + view_extension + view_edge][-tang_pos]; + } + for (int tang_pos = min_dim[3]; tang_pos < -sym_dim; tang_pos++) + { // fill in asymmetric tangential positions at the end by just picking the nearest existing element + out[axial_pos][min_dim[2] + view_edge][tang_pos] + = out[axial_pos][max_dim[2] - 2 * view_extension + view_edge + 1][sym_dim]; + out[axial_pos][max_dim[2] - view_extension + 1 + view_edge][tang_pos] + = out[axial_pos][min_dim[2] + view_extension + view_edge][sym_dim]; + } + for (int tang_pos = max_dim[3]; tang_pos > sym_dim; tang_pos--) + { // fill in asymmetric tangential positions at the end by just picking the nearest existing element + out[axial_pos][min_dim[2] + view_edge][tang_pos] + = out[axial_pos][max_dim[2] - 2 * view_extension + view_edge + 1][-sym_dim]; + out[axial_pos][max_dim[2] - view_extension + 1 + view_edge][tang_pos] + = out[axial_pos][min_dim[2] + view_extension + view_edge][-sym_dim]; + } + } + else + { + out[axial_pos][min_dim[2] + view_edge] = out[axial_pos][max_dim[2] - 2 * view_extension + view_edge + 1]; + out[axial_pos][max_dim[2] - view_extension + 1 + view_edge] + = out[axial_pos][min_dim[2] + view_extension + view_edge]; + } } - } - else - { - out[axial_pos][min_dim[2] + view_edge] = out[axial_pos][max_dim[2] - 2 * view_extension + view_edge + 1]; - out[axial_pos][max_dim[2] - view_extension + 1 + view_edge] = out[axial_pos][min_dim[2] + view_extension + view_edge]; - } } - } // fill tangential extension with same entries than boundary for (int tang_edge = 0; tang_edge < tangential_extension; tang_edge++) - { - for (int axial_pos = min_dim[1]; axial_pos <= max_dim[1]; axial_pos++) { - for (int view = min_dim[2]; view <= max_dim[2]; view++) - { - out[axial_pos][view][min_dim[3] + tang_edge] = out[axial_pos][view][min_dim[3] + tangential_extension]; - out[axial_pos][view][max_dim[3] - tang_edge] = out[axial_pos][view][max_dim[3] - tangential_extension]; - } + for (int axial_pos = min_dim[1]; axial_pos <= max_dim[1]; axial_pos++) + { + for (int view = min_dim[2]; view <= max_dim[2]; view++) + { + out[axial_pos][view][min_dim[3] + tang_edge] = out[axial_pos][view][min_dim[3] + tangential_extension]; + out[axial_pos][view][max_dim[3] - tang_edge] = out[axial_pos][view][max_dim[3] - tangential_extension]; + } + } } - } return out; } diff --git a/src/buildblock/find_STIR_config.cxx b/src/buildblock/find_STIR_config.cxx index f1bbf9c8a..031edde87 100644 --- a/src/buildblock/find_STIR_config.cxx +++ b/src/buildblock/find_STIR_config.cxx @@ -23,41 +23,44 @@ START_NAMESPACE_STIR -std::string find_STIR_config_file(const std::string& filename){ - - std::string dir; - dir = get_STIR_config_dir(); - // TODO this might be dangerous on Windows but seems to work - const std::string name = (dir+"/"+filename); - std::ifstream file(name); - if (!file) - error("find_STIR_config_file could not open " + name + "\nYou can set the STIR_CONFIG_DIR environment variable to help."); - if (file.peek() == std::ifstream::traits_type::eof()) - error("find_STIR_config_file error opening file for reading (non-existent or empty file). Filename:\n'" + name + "'"); - return name; +std::string +find_STIR_config_file(const std::string& filename) +{ + std::string dir; + dir = get_STIR_config_dir(); + // TODO this might be dangerous on Windows but seems to work + const std::string name = (dir + "/" + filename); + std::ifstream file(name); + if (!file) + error("find_STIR_config_file could not open " + name + "\nYou can set the STIR_CONFIG_DIR environment variable to help."); + if (file.peek() == std::ifstream::traits_type::eof()) + error("find_STIR_config_file error opening file for reading (non-existent or empty file). Filename:\n'" + name + "'"); + return name; } -std::string get_STIR_config_dir() +std::string +get_STIR_config_dir() { - const char * var = std::getenv("STIR_CONFIG_DIR"); + const char* var = std::getenv("STIR_CONFIG_DIR"); if (var) return var; else return STIR_CONFIG_DIR; } - -std::string get_STIR_doc_dir() -{ - const char * var = std::getenv("STIR_DOC_DIR"); +std::string +get_STIR_doc_dir() +{ + const char* var = std::getenv("STIR_DOC_DIR"); if (var) return var; else return STIR_DOC_DIR; } -std::string get_STIR_examples_dir() +std::string +get_STIR_examples_dir() { return get_STIR_doc_dir() + "/examples"; // hopefully works on Windows } diff --git a/src/buildblock/find_fwhm_in_image.cxx b/src/buildblock/find_fwhm_in_image.cxx index 4b9c97a6e..d2634965c 100644 --- a/src/buildblock/find_fwhm_in_image.cxx +++ b/src/buildblock/find_fwhm_in_image.cxx @@ -22,7 +22,7 @@ #include "stir/assign_to_subregion.h" #include "stir/extract_line.h" #include "stir/error.h" -#include +#include #include using namespace std; @@ -32,274 +32,256 @@ 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, +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); +{ + 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; + 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); + + 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); + 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); + } + 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()); + 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 ; -} + return list_res_index; +} -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) { - 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("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 fff1f5164..6643cda7b 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,45 +182,40 @@ 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; + return (char*)str; str++; } return 0; @@ -231,17 +223,17 @@ my_index (str, chr) /* 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 +244,38 @@ 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,25 +286,23 @@ 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. */ @@ -320,19 +310,17 @@ exchange (argv) { /* We must extend the array. The user plays games with us and presents new arguments. */ - char *new_str = malloc (top + 1); + 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); + 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 +# endif while (top > middle && middle > bottom) { @@ -348,7 +336,7 @@ exchange (argv) 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); + SWAP_FLAGS(bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; @@ -365,7 +353,7 @@ exchange (argv) tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; - SWAP_FLAGS (bottom + i, middle + i); + SWAP_FLAGS(bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; @@ -380,14 +368,14 @@ 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,7 +385,7 @@ _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. */ @@ -416,35 +404,31 @@ _getopt_initialize (argc, argv, optstring) else ordering = PERMUTE; -#if defined _LIBC && defined USE_NONOPTION_FLAGS - if (posixly_correct == NULL - && argc == __libc_argc && argv == __libc_argv) +# 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') + 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); + 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); + __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); + memset(__mempcpy(__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; -#endif +# endif return optstring; } @@ -506,13 +490,13 @@ _getopt_initialize (argc, argv, optstring) 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; +_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] == ':') @@ -526,22 +510,22 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) if (optind == 0 || !__getopt_initialized) { if (optind == 0) - optind = 1; /* Don't scan ARGV[0], the program name. */ - optstring = _getopt_initialize (argc, argv, optstring); + 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 + /* 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') { @@ -560,7 +544,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); + exchange((char**)argv); else if (last_nonopt != optind) first_nonopt = optind; @@ -577,12 +561,12 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) 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], "--")) + if (optind != argc && !strcmp(argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); + exchange((char**)argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; @@ -616,8 +600,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) /* 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,28 +618,25 @@ _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]))))) + 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; + 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. */ ; + /* 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 (!strncmp(p->name, nextchar, nameend - nextchar)) { - if ((unsigned int) (nameend - nextchar) - == (unsigned int) strlen (p->name)) + if ((unsigned int)(nameend - nextchar) == (unsigned int)strlen(p->name)) { /* Exact match found. */ pfound = p; @@ -670,10 +650,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) pfound = p; indfound = option_index; } - else if (long_only - || pfound->has_arg != p->has_arg - || pfound->flag != p->flag - || pfound->val != p->val) + 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; } @@ -682,24 +659,22 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) { if (print_errors) { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; +# 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); + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); else - fputs (buf, stderr); + fputs(buf, stderr); - free (buf); -#else - fprintf (stderr, _("%s: option `%s' is ambiguous\n"), - argv[0], argv[optind]); -#endif + free(buf); +# else + fprintf(stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); +# endif } - nextchar += strlen (nextchar); + nextchar += strlen(nextchar); optind++; optopt = 0; return '?'; @@ -719,49 +694,58 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) { if (print_errors) { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; -#endif +# 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 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 + argv[0], + pfound->name); +# endif } else { /* +option or -option */ -#if defined _LIBC && defined USE_IN_LIBIO - __asprintf (&buf, _("\ +# 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); +# if defined _LIBC && defined USE_IN_LIBIO + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); else - fputs (buf, stderr); + fputs(buf, stderr); - free (buf); -#endif + free(buf); +# endif } - nextchar += strlen (nextchar); + nextchar += strlen(nextchar); optopt = pfound->val; return '?'; @@ -775,31 +759,27 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) { if (print_errors) { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; - __asprintf (&buf, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); + __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); + 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 + fputs(buf, stderr); + + free(buf); +# else + fprintf(stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); +# endif } - nextchar += strlen (nextchar); + nextchar += strlen(nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } - nextchar += strlen (nextchar); + nextchar += strlen(nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) @@ -814,48 +794,43 @@ _getopt_internal (argc, argv, optstring, longopts, longind, 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 (!long_only || argv[optind][1] == '-' || my_index(optstring, *nextchar) == NULL) { if (print_errors) { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; -#endif +# 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 +# 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 + __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); +# if defined _LIBC && defined USE_IN_LIBIO + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); else - fputs (buf, stderr); + fputs(buf, stderr); - free (buf); -#endif + free(buf); +# endif } - nextchar = (char *) ""; + nextchar = (char*)""; optind++; optopt = 0; return '?'; @@ -866,7 +841,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) { 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') @@ -876,38 +851,36 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) { if (print_errors) { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; -#endif +# 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 +# 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 + __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); +# if defined _LIBC && defined USE_IN_LIBIO + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); else - fputs (buf, stderr); + fputs(buf, stderr); - free (buf); -#endif + free(buf); +# endif } optopt = c; return '?'; @@ -915,9 +888,9 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) /* 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; + char* nameend; + const struct option* p; + const struct option* pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; @@ -936,22 +909,20 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) if (print_errors) { /* 1003.2 specifies the format of this message. */ -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; - __asprintf (&buf, _("%s: option requires an argument -- %c\n"), - argv[0], c); + __asprintf(&buf, _("%s: option requires an argument -- %c\n"), argv[0], c); - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); else - fputs (buf, stderr); + fputs(buf, stderr); - free (buf); -#else - fprintf (stderr, _("%s: option requires an argument -- %c\n"), - argv[0], c); -#endif + free(buf); +# else + fprintf(stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); +# endif } optopt = c; if (optstring[0] == ':') @@ -969,14 +940,14 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) table of longopts. */ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; + /* 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 (!strncmp(p->name, nextchar, nameend - nextchar)) { - if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + if ((unsigned int)(nameend - nextchar) == strlen(p->name)) { /* Exact match found. */ pfound = p; @@ -998,24 +969,22 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) { if (print_errors) { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; - __asprintf (&buf, _("%s: option `-W %s' is ambiguous\n"), - argv[0], argv[optind]); + __asprintf(&buf, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); else - fputs (buf, stderr); + fputs(buf, stderr); - free (buf); -#else - fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), - argv[0], argv[optind]); -#endif + free(buf); +# else + fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); +# endif } - nextchar += strlen (nextchar); + nextchar += strlen(nextchar); optind++; return '?'; } @@ -1032,27 +1001,31 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) { if (print_errors) { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; - __asprintf (&buf, _("\ + __asprintf(&buf, + _("\ %s: option `-W %s' doesn't allow an argument\n"), - argv[0], pfound->name); + argv[0], + pfound->name); - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); else - fputs (buf, stderr); + fputs(buf, stderr); - free (buf); -#else - fprintf (stderr, _("\ + free(buf); +# else + fprintf(stderr, + _("\ %s: option `-W %s' doesn't allow an argument\n"), - argv[0], pfound->name); -#endif + argv[0], + pfound->name); +# endif } - nextchar += strlen (nextchar); + nextchar += strlen(nextchar); return '?'; } } @@ -1064,30 +1037,30 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) { if (print_errors) { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; - __asprintf (&buf, _("\ + __asprintf(&buf, + _("\ %s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); + argv[0], + argv[optind - 1]); - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); + 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 + fputs(buf, stderr); + + free(buf); +# else + fprintf(stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); +# endif } - nextchar += strlen (nextchar); + nextchar += strlen(nextchar); return optstring[0] == ':' ? ':' : '?'; } } - nextchar += strlen (nextchar); + nextchar += strlen(nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) @@ -1097,8 +1070,8 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) } return pfound->val; } - nextchar = NULL; - return 'W'; /* Let the application handle it. */ + nextchar = NULL; + return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { @@ -1129,24 +1102,20 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) if (print_errors) { /* 1003.2 specifies the format of this message. */ -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; +# if defined _LIBC && defined USE_IN_LIBIO + char* buf; - __asprintf (&buf, - _("%s: option requires an argument -- %c\n"), - argv[0], c); + __asprintf(&buf, _("%s: option requires an argument -- %c\n"), argv[0], c); - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); + 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 + fputs(buf, stderr); + + free(buf); +# else + fprintf(stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); +# endif } optopt = c; if (optstring[0] == ':') @@ -1166,34 +1135,30 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) } int -getopt (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; +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); + return _getopt_internal(argc, argv, optstring, (const struct option*)0, (int*)0, 0); } -#endif /* Not ELIDE_CODE. */ - +# 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; +main(argc, argv) +int argc; +char** argv; { int c; int digit_optind = 0; @@ -1202,7 +1167,7 @@ main (argc, argv) { int this_option_optind = optind ? optind : 1; - c = getopt (argc, argv, "abc:d:0123456789"); + c = getopt(argc, argv, "abc:d:0123456789"); if (c == -1) break; @@ -1219,42 +1184,42 @@ main (argc, argv) case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); + printf("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; - printf ("option %c\n", c); + printf("option %c\n", c); break; case 'a': - printf ("option a\n"); + printf("option a\n"); break; case 'b': - printf ("option b\n"); + printf("option b\n"); break; case 'c': - printf ("option c with value `%s'\n", optarg); + printf("option c with value `%s'\n", optarg); break; case '?': break; default: - printf ("?? getopt returned character code 0%o ??\n", c); + printf("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { - printf ("non-option ARGV-elements: "); + printf("non-option ARGV-elements: "); while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); + 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 35eeaf6b2..8699cfa3b 100644 --- a/src/buildblock/interfile_keyword_functions.cxx +++ b/src/buildblock/interfile_keyword_functions.cxx @@ -24,44 +24,43 @@ using namespace std; START_NAMESPACE_STIR -string +string standardise_interfile_keyword(const string& keyword) { - string::size_type cp =0; //current index - char const * const white_space = " \t_!"; - + 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,' '); - previous_was_white_space = true; - } - // else: skip this white space character + 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])))); + previous_was_white_space = false; + } + ++cp; } - else - { - kw.append(1,static_cast(tolower(static_cast(keyword[cp])))); - previous_was_white_space = false; - } - ++cp; - } return kw; } - END_NAMESPACE_STIR diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index f4a9e768f..060e8aa35 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -40,83 +40,75 @@ START_NAMESPACE_STIR 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. - 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) - { +/* 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. +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 @@ -130,177 +122,174 @@ 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"); - 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()); + 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); + } +} - make_non_interleaved_segment(out_segment, in_segment); - return out_segment; - } +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; +} } // end namespace detail_interpolate_projdata - using namespace detail_interpolate_projdata; -Succeeded +Succeeded interpolate_projdata(ProjData& proj_data_out, - const ProjData& proj_data_in, const BSpline::BSplineType these_types, + const ProjData& proj_data_in, + const BSpline::BSplineType these_types, const bool remove_interleaving) { - 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); + 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); return Succeeded::yes; } -Succeeded +Succeeded interpolate_projdata(ProjData& proj_data_out, const ProjData& proj_data_in, - const BasicCoordinate<3, BSpline::BSplineType> & these_types, + const BasicCoordinate<3, BSpline::BSplineType>& these_types, const bool remove_interleaving) { - 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)"); } - + // 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) + 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"); } // initialise interpolator BSpline::BSplinesRegularGrid<3, float, float> proj_data_interpolator(these_types); - for (int k=proj_data_out_info.get_min_tof_pos_num(); - k<=proj_data_out_info.get_max_tof_pos_num(); ++k) - { - SegmentBySinogram segment = remove_interleaving ? - make_non_interleaved_segment(*(make_non_interleaved_proj_data_info(proj_data_in_info)), proj_data_in.get_segment_by_sinogram(0,k)) : - proj_data_in.get_segment_by_sinogram(0,k); - - std::function (const BasicCoordinate<3, int>&)> index_converter; - if (proj_data_in_info.get_scanner_sptr()->get_scanner_geometry()=="Cylindrical") - { // for Cylindrical, spacing is regular in all directions, which makes mapping trivial - // especially in view direction, extending by 5 leads to much smaller artifacts - proj_data_interpolator.set_coef(extend_segment(segment, 5, 5, 5)); - - BasicCoordinate<3, double> offset, step; - // out_index * step + 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)); - // offset in 'in' index units - offset[1] = (proj_data_out_info.get_m(Bin(0, 0, 0, 0)) - proj_data_in_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)); - offset[2] = (proj_data_out_info.get_phi(Bin(0, 0, 0, 0)) - proj_data_in_info.get_phi(Bin(0, 0, 0, 0))) / 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; - - // define a function to translate indices in the output proj data to indices in input proj data - index_converter = [&proj_data_out_info, offset, step](const BasicCoordinate<3, int>& index_out) - -> BasicCoordinate<3, double> - { - // translate to indices in input proj data - BasicCoordinate<3, double> index_in; - for (auto dim = 1; dim <= 3; dim++) - index_in[dim] = index_out[dim] * step[dim] + offset[dim]; - - return index_in; - }; - } - else - { // for BlocksOnCylindrical, views and tangential positions are not subsampled and can be mapped 1:1 - if (proj_data_in_info.get_num_tangential_poss() != proj_data_out_info.get_num_tangential_poss()) + for (int k = proj_data_out_info.get_min_tof_pos_num(); k <= proj_data_out_info.get_max_tof_pos_num(); ++k) { - error("Interpolation of BlocksOnCylindrical scanners assumes that number of tangential positions " - "is the same in the downsampled scanner."); + SegmentBySinogram segment + = remove_interleaving ? make_non_interleaved_segment(*(make_non_interleaved_proj_data_info(proj_data_in_info)), + proj_data_in.get_segment_by_sinogram(0, k)) + : proj_data_in.get_segment_by_sinogram(0, k); + + std::function(const BasicCoordinate<3, int>&)> index_converter; + if (proj_data_in_info.get_scanner_sptr()->get_scanner_geometry() == "Cylindrical") + { // for Cylindrical, spacing is regular in all directions, which makes mapping trivial + // especially in view direction, extending by 5 leads to much smaller artifacts + proj_data_interpolator.set_coef(extend_segment(segment, 5, 5, 5)); + + BasicCoordinate<3, double> offset, step; + // out_index * step + 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)); + // offset in 'in' index units + offset[1] = (proj_data_out_info.get_m(Bin(0, 0, 0, 0)) - proj_data_in_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)); + offset[2] + = (proj_data_out_info.get_phi(Bin(0, 0, 0, 0)) - proj_data_in_info.get_phi(Bin(0, 0, 0, 0))) / 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; + + // define a function to translate indices in the output proj data to indices in input proj data + index_converter + = [&proj_data_out_info, offset, step](const BasicCoordinate<3, int>& index_out) -> BasicCoordinate<3, double> { + // translate to indices in input proj data + BasicCoordinate<3, double> index_in; + for (auto dim = 1; dim <= 3; dim++) + index_in[dim] = index_out[dim] * step[dim] + offset[dim]; + + return index_in; + }; + } + else + { // for BlocksOnCylindrical, views and tangential positions are not subsampled and can be mapped 1:1 + if (proj_data_in_info.get_num_tangential_poss() != proj_data_out_info.get_num_tangential_poss()) + { + error("Interpolation of BlocksOnCylindrical scanners assumes that number of tangential positions " + "is the same in the downsampled scanner."); + } + if (proj_data_in_info.get_num_views() != proj_data_out_info.get_num_views()) + { + error("Interpolation of BlocksOnCylindrical scanners assumes that number of views " + "is the same in the downsampled scanner."); + } + + // only extending in axial direction - an extension of 2 was found to be sufficient + proj_data_interpolator.set_coef(extend_segment(segment, 0, 2, 0)); + + auto m_offset = proj_data_in_info.get_m(Bin(0, 0, 0, 0)); + auto m_sampling = proj_data_in_info.get_sampling_in_m(Bin(0, 0, 0, 0)); + + // confirm that proj_data_in has equidistant sampling in m + for (auto axial_pos = proj_data_in_info.get_min_axial_pos_num(0); + axial_pos <= proj_data_in_info.get_max_axial_pos_num(0); + axial_pos++) + { + if (abs(m_sampling - proj_data_in_info.get_sampling_in_m(Bin(0, 0, axial_pos, 0))) > 1E-4) + error("input projdata to interpolate_projdata are not equidistantly sampled in m."); + } + + // define a function to translate indices in the output proj data to indices in input proj data + index_converter = [&proj_data_out_info, m_offset, m_sampling]( + const BasicCoordinate<3, int>& index_out) -> BasicCoordinate<3, double> { + // translate index on output to coordinate + auto bin + = Bin(0 /* segment */, index_out[2] /* view */, index_out[1] /* axial pos */, index_out[3] /* tangential pos */); + auto out_m = proj_data_out_info.get_m(bin); + + // translate to indices in input proj data + BasicCoordinate<3, double> index_in; + index_in[1] = (out_m - m_offset) / m_sampling; + index_in[2] = index_out[2]; + index_in[3] = index_out[3]; + + return index_in; + }; + } + + SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0, false, k); + sample_function_using_index_converter(sino_3D_out, proj_data_interpolator, index_converter); + + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + return Succeeded::no; } - if (proj_data_in_info.get_num_views() != proj_data_out_info.get_num_views()) - { - error("Interpolation of BlocksOnCylindrical scanners assumes that number of views " - "is the same in the downsampled scanner."); - } - - // only extending in axial direction - an extension of 2 was found to be sufficient - proj_data_interpolator.set_coef(extend_segment(segment, 0, 2, 0)); - - auto m_offset = proj_data_in_info.get_m(Bin(0, 0, 0, 0)); - auto m_sampling = proj_data_in_info.get_sampling_in_m(Bin(0, 0, 0, 0)); - - // confirm that proj_data_in has equidistant sampling in m - for (auto axial_pos = proj_data_in_info.get_min_axial_pos_num(0); axial_pos <= proj_data_in_info.get_max_axial_pos_num(0); axial_pos++) - { - if (abs(m_sampling - proj_data_in_info.get_sampling_in_m(Bin(0, 0, axial_pos, 0))) > 1E-4) - error("input projdata to interpolate_projdata are not equidistantly sampled in m."); - } - - // define a function to translate indices in the output proj data to indices in input proj data - index_converter = [&proj_data_out_info, m_offset, m_sampling](const BasicCoordinate<3, int>& index_out) - -> BasicCoordinate<3, double> - { - // translate index on output to coordinate - auto bin = Bin(0 /* segment */, index_out[2] /* view */, index_out[1] /* axial pos */, index_out[3] /* tangential pos */); - auto out_m = proj_data_out_info.get_m(bin); - - // translate to indices in input proj data - BasicCoordinate<3, double> index_in; - index_in[1] = (out_m - m_offset) / m_sampling; - index_in[2] = index_out[2]; - index_in[3] = index_out[3]; - - return index_in; - }; - } - - SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0,false, k); - sample_function_using_index_converter(sino_3D_out, proj_data_interpolator, index_converter); - - if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) - return Succeeded::no; - } return Succeeded::yes; } diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index 3c1633cb3..bf63b790a 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -68,19 +68,22 @@ inverse_SSRB(ProjData& proj_data_4D, const ProjData& proj_data_3D) ++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) + out_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(out_segment_num); + ++out_ax_pos_num) { - for (int k=proj_data_4D.get_proj_data_info_sptr()->get_min_tof_pos_num(); - k<=proj_data_4D.get_proj_data_info_sptr()->get_max_tof_pos_num(); ++k) - { - sino_4D = proj_data_4D.get_empty_sinogram(out_ax_pos_num, out_segment_num, false, k); - const float out_m = proj_data_4D_info_sptr->get_m(Bin(out_segment_num, 0, out_ax_pos_num, 0)); + for (int k = proj_data_4D.get_proj_data_info_sptr()->get_min_tof_pos_num(); + k <= proj_data_4D.get_proj_data_info_sptr()->get_max_tof_pos_num(); + ++k) + { + sino_4D = proj_data_4D.get_empty_sinogram(out_ax_pos_num, out_segment_num, false, k); + const float out_m = proj_data_4D_info_sptr->get_m(Bin(out_segment_num, 0, out_ax_pos_num, 0)); - // Go through all direct sinograms to check which pair are closest. - bool sinogram_set = false; - 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) - { + // Go through all direct sinograms to check which pair are closest. + bool sinogram_set = false; + 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) + { // for the first slice there is no previous const auto distance_to_previous = in_ax_pos_num == proj_data_3D.get_min_axial_pos_num(0) ? std::numeric_limits::max() @@ -94,7 +97,7 @@ inverse_SSRB(ProjData& proj_data_4D, const ProjData& proj_data_3D) { if (distance_to_current <= 1E-4) { - sino_3D_1 = proj_data_3D.get_sinogram(in_ax_pos_num, 0,false, k); + sino_3D_1 = proj_data_3D.get_sinogram(in_ax_pos_num, 0, false, k); sino_4D += sino_3D_1; } else if (distance_to_previous < distance_to_next) @@ -124,7 +127,7 @@ inverse_SSRB(ProjData& proj_data_4D, const ProjData& proj_data_3D) { // it is logically not possible to get here error("no matching sinogram found for segment %d and axial pos %d", out_segment_num, out_ax_pos_num); } - } + } } } return Succeeded::yes; diff --git a/src/buildblock/line.cxx b/src/buildblock/line.cxx index 3556e4d53..4045686d7 100644 --- a/src/buildblock/line.cxx +++ b/src/buildblock/line.cxx @@ -26,227 +26,232 @@ 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() +string +Line::get_keyword() { - // keyword stops at either := or an index [] + // 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() +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; + 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) +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; + 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) +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; -} + 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(double& i) +int +Line::get_param(unsigned long& i) { - string s; - int r; - - r=get_param(s); - if(r==LINE_OK) - i=atof(s.c_str()); - - return r; -} + string s; + int r; + r = get_param(s); + if (r == LINE_OK) + // TODO not unsigned now + i = atol(s.c_str()); + return r; +} -int Line::get_param(vector& v) +int +Line::get_param(double& i) { - 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; + string s; + int r; + + r = get_param(s); + if (r == LINE_OK) + i = atof(s.c_str()); + + 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) +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; + 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) +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; + 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) +Line& +Line::operator=(const char* ch) { - string::operator=(ch); - return *this; + string::operator=(ch); + return *this; } END_NAMESPACE_STIR diff --git a/src/buildblock/linear_regression.cxx b/src/buildblock/linear_regression.cxx index df08f85ff..3a4a2fb09 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 @@ -26,36 +26,35 @@ START_NAMESPACE_STIR -namespace detail { - - // see linear_regression.inl for more info +namespace detail +{ +// 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, @@ -63,59 +62,56 @@ 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); + chi_square = static_cast(Syy - square(scale) * Stt - square(Sy) / S); - if (chi_square<0) + 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; + 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; } - 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/multiply_crystal_factors.cxx b/src/buildblock/multiply_crystal_factors.cxx index a9e3415a8..70013ce0d 100644 --- a/src/buildblock/multiply_crystal_factors.cxx +++ b/src/buildblock/multiply_crystal_factors.cxx @@ -30,130 +30,124 @@ START_NAMESPACE_STIR // declaration of local function that does the work template -void multiply_crystal_factors_help(ProjData& proj_data, - const TProjDataInfo& proj_data_info, - const Array<2,float>& efficiencies, float global_factor) +void +multiply_crystal_factors_help(ProjData& proj_data, + const TProjDataInfo& proj_data_info, + const Array<2, float>& efficiencies, + float global_factor) { // we will duplicate TOF sinograms, so need to divide with their number such that // total remains preserved global_factor /= proj_data.get_num_tof_poss(); - const auto non_tof_proj_data_info_sptr = - std::dynamic_pointer_cast(proj_data_info.create_non_tof_clone()); + const auto non_tof_proj_data_info_sptr = std::dynamic_pointer_cast(proj_data_info.create_non_tof_clone()); Bin 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 = - non_tof_proj_data_info_sptr->get_empty_sinogram(SinogramIndices(bin)); + 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 = non_tof_proj_data_info_sptr->get_empty_sinogram(SinogramIndices(bin)); #ifdef STIR_OPENMP # if _OPENMP >= 200711 -# pragma omp parallel for collapse(2) // OpenMP 3.1 +# pragma omp parallel for collapse(2) // OpenMP 3.1 # else -# pragma omp parallel for // older versions +# pragma omp parallel for // older versions # endif #endif - for (int view_num = proj_data.get_min_view_num(); - view_num <= proj_data.get_max_view_num(); - ++ view_num) - { - for (int tangential_pos_num = proj_data.get_min_tangential_pos_num(); - tangential_pos_num <= proj_data.get_max_tangential_pos_num(); - ++tangential_pos_num) - { - // Construct bin with appropriate values - // Sadly cannot be done in the loops above for OpenMP 2.0 compatibility - Bin parallel_bin(bin); - parallel_bin.view_num() = view_num; - parallel_bin.tangential_pos_num() = tangential_pos_num; - - std::vector > det_pos_pairs; - non_tof_proj_data_info_sptr->get_all_det_pos_pairs_for_bin(det_pos_pairs, parallel_bin); // using the default argument to ignore TOF here - float result = 0.F; - for (unsigned int i=0; i= 201012 -# pragma omp atomic update -# else -# pragma omp critical(STIRMULTIPLYCRYSTALFACTORS) + for (int view_num = proj_data.get_min_view_num(); view_num <= proj_data.get_max_view_num(); ++view_num) + { + for (int tangential_pos_num = proj_data.get_min_tangential_pos_num(); + tangential_pos_num <= proj_data.get_max_tangential_pos_num(); + ++tangential_pos_num) + { + // Construct bin with appropriate values + // Sadly cannot be done in the loops above for OpenMP 2.0 compatibility + Bin parallel_bin(bin); + parallel_bin.view_num() = view_num; + parallel_bin.tangential_pos_num() = tangential_pos_num; + + std::vector> det_pos_pairs; + non_tof_proj_data_info_sptr->get_all_det_pos_pairs_for_bin( + det_pos_pairs, parallel_bin); // using the default argument to ignore TOF here + float result = 0.F; + for (unsigned int i = 0; i < det_pos_pairs.size(); ++i) { -# endif + const auto& p1 = det_pos_pairs[i].pos1(); + const auto& p2 = det_pos_pairs[i].pos2(); + result += efficiencies[p1.axial_coord()][p1.tangential_coord()] + * efficiencies[p2.axial_coord()][p2.tangential_coord()]; + } +#if defined(STIR_OPENMP) +# if _OPENMP >= 201012 +# pragma omp atomic update +# else +# pragma omp critical(STIRMULTIPLYCRYSTALFACTORS) + { +# endif #endif - // Use += such that the "atomic update" pragma compiles (OpenMP 3.0). - // Presumably with OpenMP 3.1 we could use "atomic write" - sinogram[parallel_bin.view_num()][parallel_bin.tangential_pos_num()] += result * global_factor; + // Use += such that the "atomic update" pragma compiles (OpenMP 3.0). + // Presumably with OpenMP 3.1 we could use "atomic write" + sinogram[parallel_bin.view_num()][parallel_bin.tangential_pos_num()] += result * global_factor; #if defined(STIR_OPENMP) && _OPENMP < 201012 - } + } #endif - } - } - // now set sinogram, a bit complicated for TOF as we replicate - if (proj_data.get_num_tof_poss() == 1) - { - proj_data.set_sinogram(sinogram); - } - else - { - 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()) - { - // construct TOF sinogram with same values as the non-TOF sinogram, - // but appropriate meta-data. - const Sinogram tof_sinogram(sinogram, proj_data.get_proj_data_info_sptr(), SinogramIndices(bin)); - proj_data.set_sinogram(tof_sinogram); - } - } - } - - } + } + } + // now set sinogram, a bit complicated for TOF as we replicate + if (proj_data.get_num_tof_poss() == 1) + { + proj_data.set_sinogram(sinogram); + } + else + { + 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()) + { + // construct TOF sinogram with same values as the non-TOF sinogram, + // but appropriate meta-data. + const Sinogram tof_sinogram(sinogram, proj_data.get_proj_data_info_sptr(), SinogramIndices(bin)); + proj_data.set_sinogram(tof_sinogram); + } + } + } +} } -void multiply_crystal_factors(ProjData& proj_data, const Array<2,float>& efficiencies, const float global_factor) +void +multiply_crystal_factors(ProjData& proj_data, const Array<2, float>& efficiencies, const float global_factor) { - if (proj_data.get_proj_data_info_sptr()->get_scanner_ptr()->get_scanner_geometry()=="Cylindrical") + if (proj_data.get_proj_data_info_sptr()->get_scanner_ptr()->get_scanner_geometry() == "Cylindrical") { - auto proj_data_info_ptr = - dynamic_cast - (proj_data.get_proj_data_info_sptr().get()); + auto proj_data_info_ptr + = dynamic_cast(proj_data.get_proj_data_info_sptr().get()); - if (proj_data_info_ptr == 0) + if (proj_data_info_ptr == 0) { - error("Can only process not arc-corrected data\n"); + error("Can only process not arc-corrected data\n"); } - multiply_crystal_factors_help(proj_data, *proj_data_info_ptr, efficiencies, global_factor); + multiply_crystal_factors_help(proj_data, *proj_data_info_ptr, efficiencies, global_factor); } - else + else { - auto proj_data_info_ptr = - dynamic_cast - (proj_data.get_proj_data_info_sptr().get()); + auto proj_data_info_ptr + = dynamic_cast(proj_data.get_proj_data_info_sptr().get()); - if (proj_data_info_ptr == 0) + if (proj_data_info_ptr == 0) { - error("Can only process not arc-corrected data\n"); + error("Can only process not arc-corrected data\n"); } - multiply_crystal_factors_help(proj_data, *proj_data_info_ptr, efficiencies, global_factor); + multiply_crystal_factors_help(proj_data, *proj_data_info_ptr, efficiencies, global_factor); } } -template void multiply_crystal_factors_help -(ProjData&, const ProjDataInfoCylindricalNoArcCorr&, const Array<2,float>&, const float ); -template void multiply_crystal_factors_help -(ProjData&, const ProjDataInfoBlocksOnCylindricalNoArcCorr&, const Array<2,float>&, const float ); +template void +multiply_crystal_factors_help(ProjData&, const ProjDataInfoCylindricalNoArcCorr&, const Array<2, float>&, const float); +template void +multiply_crystal_factors_help(ProjData&, const ProjDataInfoBlocksOnCylindricalNoArcCorr&, const Array<2, float>&, const float); END_NAMESPACE_STIR diff --git a/src/buildblock/num_threads.cxx b/src/buildblock/num_threads.cxx index a601560ed..479f48084 100644 --- a/src/buildblock/num_threads.cxx +++ b/src/buildblock/num_threads.cxx @@ -13,7 +13,7 @@ \brief Implementation of functions related to setting/getting the number of threads - \author Kris Thielemans + \author Kris Thielemans */ #include "stir/num_threads.h" @@ -25,12 +25,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(); @@ -39,11 +40,12 @@ 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 (num_threads == 0) { if (!already_set_once) { @@ -55,26 +57,27 @@ void set_num_threads(const int num_threads) #ifdef STIR_OPENMP omp_set_num_threads(num_threads); - if (omp_get_max_threads()==1) + 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) + 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) + if (getenv("OMP_NUM_THREADS") != NULL) { - default_num_threads=atoi(getenv("OMP_NUM_THREADS")); + default_num_threads = atoi(getenv("OMP_NUM_THREADS")); } return default_num_threads; #else @@ -82,10 +85,10 @@ int get_default_num_threads() #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 2bb54dd85..5978f49a0 100644 --- a/src/buildblock/overlap_interpolate.cxx +++ b/src/buildblock/overlap_interpolate.cxx @@ -24,9 +24,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 @@ -44,7 +44,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. @@ -56,7 +56,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: @@ -77,16 +77,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). @@ -99,298 +99,270 @@ 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()) - { - out_data = in_data; - return; - } - - 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); - - // 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 (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(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]; + out_data = in_data; + return; + } + + 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); + + // 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; + } + + 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 - { - /* - Set out_data[x2] according to - - T V1; // bin value at x1 - 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 - */ - 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]; - } - + } + 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 + 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 + */ + 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; - } - }// End of for x2 - - } + + // advance 'in' bin + x1++; + diff_between_right_edges += zoom; + } + } // 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; - - // 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); - - // 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; - - // 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. - // If so, will first subtract the contribution of the 'in' bin that - // 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() ) + // 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; + + // 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); + + // 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; + + // 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. + // If so, will first subtract the contribution of the 'in' bin that + // lies outside the 'out' bin. In the loop later, this part of the + // 'in' bin will be added again. { - out_data[x2] = in_data[x1]; - out_data[x2] *= static_cast(diff_between_left_edges); + 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; + } } - 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]; - } - 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) - { - // set rest of out_data to 0 - for (x2++; - x2 <= out_data.get_max_index(); - x2++) - 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]; + } + 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) + { + // set rest of out_data to 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 b5e98712a..b8c25a788 100644 --- a/src/buildblock/recon_array_functions.cxx +++ b/src/buildblock/recon_array_functions.cxx @@ -3,10 +3,10 @@ /* Copyright (C) 2000 PARAPET partners Copyright (C) 2000- 2011, Hammersmith Imanet Ltd - This file is part of STIR. - + This file is part of STIR. + SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license - + See STIR/LICENSE.txt for details */ /*! @@ -17,11 +17,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" @@ -43,159 +43,157 @@ START_NAMESPACE_STIR const float SMALL_NUM = 0.000001F; - // AZ 07/10/99: added -void truncate_rim(Viewgram& viewgram, const int rim_truncation_sino) +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--; + 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 r = rs; r <= re; r++) { - for(int b=bs;b& seg, const int rim_truncation_sino) +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) +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& 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); - + + // 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; - } + 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; - } + 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 */) +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 + + 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 #if 0 // old version if(denominator[r][b]<=small_value || @@ -215,138 +213,136 @@ 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) + result += sub_result; } - 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) +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; - - } - + + 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; + } } -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) +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(); + + 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, @@ -357,85 +353,73 @@ 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); - } - result += sub_result; - } + 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()) + + 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; + 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) + 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) ); + 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()) + 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" + 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(), + bin.segment_num(), + bin.axial_pos_num(), total_in_denominator[bin.segment_num()][bin.axial_pos_num()], denominator_sinogram.sum(), - default_scale - ); + 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()]; + 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 dfdd3c396..602e56b71 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 @@ -37,99 +37,98 @@ 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') - << "]: "; + cerr << "\n" << str << " [Y/N D:" << (default_value ? 'Y' : 'N') << "]: "; std::getline(std::cin, input); - if (input.size()==0) - return default_value; + 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"; - } - } + { + 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) +FILE*& +open_read_binary(FILE*& fptr, const string& name) { - fptr = fopen(name.c_str(), "rb"); + fptr = fopen(name.c_str(), "rb"); if (ferror(fptr)) - { error("Error opening file %s\n", name.c_str()); } + { + error("Error opening file %s\n", name.c_str()); + } return fptr; } -FILE*& open_write_binary(FILE*& fptr, - const string& name) +FILE*& +open_write_binary(FILE*& fptr, const string& name) { - fptr = fopen(name.c_str(), "wb"); + fptr = fopen(name.c_str(), "wb"); if (ferror(fptr)) - { error("Error opening file %s\n", name.c_str()); } + { + 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* +find_filename(const char* const filename_with_directory) { - const char * name; + 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 @@ -138,40 +137,36 @@ 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)); + 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) +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; + 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; @@ -180,8 +175,7 @@ get_directory_name(char *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)); + string dir_name = filename_with_directory.substr(0, find_pos_of_filename(filename_with_directory)); if (dir_name.empty()) dir_name = "."; return dir_name; @@ -190,10 +184,8 @@ get_directory_name(const string& filename_with_directory) 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); + 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 @@ -213,19 +205,15 @@ char *add_extension(char *file_in_directory_name, } #endif -string& -add_extension(string& file_in_directory_name, - const string& extension) +string& +add_extension(string& file_in_directory_name, const string& extension) { - string::size_type pos = - find_pos_of_extension(file_in_directory_name); + 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 @@ -244,43 +232,37 @@ char *replace_extension(char *file_in_directory_name, } #endif -string& -replace_extension(string& file_in_directory_name, - const string& extension) +string& +replace_extension(string& file_in_directory_name, const string& extension) { - string::size_type pos = - find_pos_of_extension(file_in_directory_name); + 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 @@ -288,48 +270,40 @@ 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()); + 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) +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) + 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 - { - // peel of the ][ pair - *end_of_new_name = '\0'; - strcat(new_name, filename_with_directory+1); - } + { + // peel of the ][ pair + *end_of_new_name = '\0'; + 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__) @@ -339,7 +313,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__) @@ -347,7 +321,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; @@ -355,117 +329,95 @@ 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) - { - cerr << prompt; - 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); + while (file_in_directory_name.size() == 0) + { + cerr << prompt; + 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); } -char * -ask_filename_with_extension(char *file_in_directory_name, - const string& prompt, - const string& 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); + 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) +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); + 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()); } + { + 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) +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; + 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)]; + char* memory = new char[static_cast(file_size)]; if (memory == 0) - { error("Not enough memory\n"); } + { + 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) + while (to_read != 0) { - const streamsize this_read_size = - std::min(to_read, chunk_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; + const streamsize this_read_size = std::min(to_read, chunk_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 318711f20..5a7fd8204 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 @@ -32,29 +32,29 @@ 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; + 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: " << 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 7fe498615..783d9400c 100644 --- a/src/buildblock/zoom.cxx +++ b/src/buildblock/zoom.cxx @@ -9,7 +9,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup buildblock \brief Implementations of the stir::zoom functions @@ -28,13 +28,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" @@ -92,200 +92,168 @@ 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) + 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) return; - - 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()); - if ( new_proj_data_info_arccorr_sptr==0) + 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()); + + 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); + + 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 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()); - ProjDataInfoCylindricalArcCorr* new_proj_data_info_arccorr_sptr = - dynamic_cast(new_proj_data_info_sptr.get()); - if ( new_proj_data_info_arccorr_sptr==0) + 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()); + + 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(), - false, - in_view.get_timing_pos_num()); - - zoom_viewgram(out_view, in_view, - x_offset_in_mm, y_offset_in_mm); + + 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); 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_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()); - const shared_ptr out_proj_data_info_arccorr_sptr = - dynamic_pointer_cast(out_view.get_proj_data_info_sptr()); + const shared_ptr in_proj_data_info_arccorr_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()); - 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) + 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) 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) + 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"); } @@ -293,155 +261,136 @@ 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, +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); + 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, +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 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()) + 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); + 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); + 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()); + 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); + + 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, +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); + 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, +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); + 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) + - (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() - ) + 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())); - - 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++) + 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++) 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,34 +401,30 @@ zoom_image(VoxelsOnCartesianGrid &image_out, switch (zoom_options.get_scaling_option()) { - case ZoomOptions::preserve_values: - { - scale_image = zoom_x*zoom_y*zoom_z; + case ZoomOptions::preserve_values: { + scale_image = zoom_x * zoom_y * zoom_z; break; } - case ZoomOptions::preserve_projections: + case ZoomOptions::preserve_projections: { - scale_image = zoom_y*zoom_z; + scale_image = zoom_y * zoom_z; break; } - case ZoomOptions::preserve_sum: - { + 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, +zoom_image(PixelsOnCartesianGrid& image2D_out, + const PixelsOnCartesianGrid& image2D_in, const ZoomOptions zoom_options) { image2D_out.set_exam_info(image2D_in.get_exam_info()); @@ -487,64 +432,49 @@ zoom_image(PixelsOnCartesianGrid &image2D_out, 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() - ) - { - image2D_out = image2D_in; - return; - } + 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; + case ZoomOptions::preserve_values: { + scale_image = zoom_x * zoom_y; break; } - case ZoomOptions::preserve_projections: + case ZoomOptions::preserve_projections: { - scale_image = zoom_y; + scale_image = zoom_y; break; } - case ZoomOptions::preserve_sum: - { + 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/SinglesRates.cxx b/src/data_buildblock/SinglesRates.cxx index 0372797c0..00b719d12 100644 --- a/src/data_buildblock/SinglesRates.cxx +++ b/src/data_buildblock/SinglesRates.cxx @@ -24,86 +24,65 @@ 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 int singles_bin_index, - const double start_time, const double end_time) const +SinglesRates::get_singles_rate(const int singles_bin_index, const double start_time, const double end_time) const { - return static_cast(get_singles(singles_bin_index, start_time, end_time)/(end_time-start_time)); + return static_cast(get_singles(singles_bin_index, start_time, end_time) / (end_time - start_time)); } 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)); } float -SinglesRates:: -get_singles(const DetectionPosition<>& det_pos, - const double start_time, const double end_time) const +SinglesRates::get_singles(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(singles_bin_index, start_time, end_time)); + return (get_singles(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 98635b1f1..c9545fddf 100644 --- a/src/data_buildblock/SinglesRatesForTimeFrames.cxx +++ b/src/data_buildblock/SinglesRatesForTimeFrames.cxx @@ -23,56 +23,43 @@ START_NAMESPACE_STIR -SinglesRatesForTimeFrames:: -SinglesRatesForTimeFrames() +SinglesRatesForTimeFrames::SinglesRatesForTimeFrames() {} - -float -SinglesRatesForTimeFrames:: -get_singles(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(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(const int singles_bin_index, - const unsigned time_frame_num, - const float new_singles) +void +SinglesRatesForTimeFrames::set_singles(const int singles_bin_index, const unsigned time_frame_num, const float new_singles) { this->_singles[time_frame_num][singles_bin_index] = new_singles; } - float -SinglesRatesForTimeFrames:: -get_singles(const int singles_bin_index, - const double start_time, - const double end_time) const +SinglesRatesForTimeFrames::get_singles(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); + 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(singles_bin_index, frame_number)); + return (get_singles(singles_bin_index, frame_number)); } -unsigned int -SinglesRatesForTimeFrames::get_num_frames() const { - return(this->_time_frame_defs.get_num_frames()); +unsigned int +SinglesRatesForTimeFrames::get_num_frames() const +{ + 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:: @@ -98,5 +85,3 @@ get_frame_end(unsigned int frame_number) const { #endif END_NAMESPACE_STIR - - diff --git a/src/data_buildblock/SinglesRatesForTimeSlices.cxx b/src/data_buildblock/SinglesRatesForTimeSlices.cxx index 7016c59ef..3f06e8b67 100644 --- a/src/data_buildblock/SinglesRatesForTimeSlices.cxx +++ b/src/data_buildblock/SinglesRatesForTimeSlices.cxx @@ -28,149 +28,134 @@ #include #include - - START_NAMESPACE_STIR - const double MAX_INTERVAL_DIFFERENCE = 0.05; // 5% max difference. // Constructor -SinglesRatesForTimeSlices:: -SinglesRatesForTimeSlices() +SinglesRatesForTimeSlices::SinglesRatesForTimeSlices() {} - // Generate a FramesSinglesRate - containing the average rates // for a frame begining at start_time and ending at end_time. FrameSinglesRates -SinglesRatesForTimeSlices:: -get_rates_for_frame(double start_time, - double end_time) const { +SinglesRatesForTimeSlices::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) { - average_singles_rates[singles_bin] = get_singles_rate(singles_bin, start_time, end_time); - } - + 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 = get_slice_start_time(start_slice); 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 -SinglesRatesForTimeSlices:: -get_end_time_slice_index(double t) const { +SinglesRatesForTimeSlices::get_end_time_slice_index(double t) const +{ int slice_index = 0; // Start with an initial estimate. - if ( _singles_time_interval != 0 ) { - slice_index = static_cast(floor(t / _singles_time_interval)); - } - - if ( slice_index >= _num_time_slices ) { - slice_index = _num_time_slices - 1; - } + if (_singles_time_interval != 0) + { + slice_index = static_cast(floor(t / _singles_time_interval)); + } + 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 ) { - - // Check forwards. - while( slice_index < _num_time_slices - 1 && - _times[slice_index] < t ) { - slice_index++; - } + if (_times[slice_index] < t) + { - } else { + // Check forwards. + 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 ) { - slice_index--; + // Check backwards. + 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 -SinglesRatesForTimeSlices:: -get_start_time_slice_index(double t) const { +SinglesRatesForTimeSlices::get_start_time_slice_index(double t) const +{ int slice_index = 0; // Start with an initial estimate. - if ( _singles_time_interval != 0 ) { - slice_index = std::max(0,static_cast(floor((t-_times[0]) / _singles_time_interval))); - } - - if ( slice_index >= _num_time_slices ) { - slice_index = _num_time_slices - 1; - } + if (_singles_time_interval != 0) + { + slice_index = std::max(0, static_cast(floor((t - _times[0]) / _singles_time_interval))); + } + 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 ) { - - // Check forwards. - while( slice_index < _num_time_slices - 1 && - _times[slice_index] <= t ) { - slice_index++; - } + if (_times[slice_index] < t) + { - } else { + // Check forwards. + 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 ) { - slice_index--; + // Check backwards. + while (slice_index > 0 && _times[slice_index - 1] > t) + { + slice_index--; + } } - } - - return(slice_index); + return (slice_index); } - - - - #if 0 // Get rates using time slice and singles bin indices. int @@ -190,118 +175,100 @@ get_singles_rate(int singles_bin_index, int time_slice) const { } #endif - // Set a singles by bin index and time slice. -void -SinglesRatesForTimeSlices:: -set_singles(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 ) { - _singles[time_slice][singles_bin_index] = new_rate; - } -} - +void +SinglesRatesForTimeSlices::set_singles(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) + { + _singles[time_slice][singles_bin_index] = new_rate; + } +} -int -SinglesRatesForTimeSlices:: -rebin(std::vector& new_end_times) { +int +SinglesRatesForTimeSlices::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()); double start_time = get_slice_start_time(0); - // Loop over new time slices. - 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) { - 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(singles_bin, start_time, end_time)); - } - + 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) + { + 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(singles_bin, start_time, end_time)); + } + } + + // Next new time slice starts at the end of this slice. + 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 +std::vector SinglesRatesForTimeSlices::get_times() const { return _times; } - - - int -SinglesRatesForTimeSlices:: -get_num_time_slices() const { - return(_num_time_slices); +SinglesRatesForTimeSlices::get_num_time_slices() const +{ + return (_num_time_slices); } - - double -SinglesRatesForTimeSlices:: -get_singles_time_interval() const { - return(_singles_time_interval); +SinglesRatesForTimeSlices::get_singles_time_interval() const +{ + return (_singles_time_interval); } - - - - float -SinglesRatesForTimeSlices:: -get_singles(const int singles_bin_index, - const double start_time, const double end_time) const { +SinglesRatesForTimeSlices::get_singles(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; // Start and end times for starting and ending slices. @@ -312,48 +279,46 @@ get_singles(const int singles_bin_index, slice_start_time = get_slice_start_time(start_slice); slice_end_time = _times[start_slice]; - if (start_time>end_time) - error(boost::format("get_singles() called with start_time %1% larger than end time %2%") - % start_time % end_time); + if (start_time > end_time) + error(boost::format("get_singles() called with start_time %1% larger than end time %2%") % start_time % end_time); if (start_time < get_slice_start_time(start_slice) - 1e-2 /* allow for some rounding */) error(boost::format("get_singles() called with start time %1% which is smaller than the start time in the data (%2%)") % start_time % slice_start_time); if (end_time > _times[end_slice] + 1e-2 /* allow for some rounding */) - error(boost::format("get_singles() called with end time %1% which is larger than the end time in the data (%2%)") - % end_time % slice_end_time); + error(boost::format("get_singles() called with end time %1% which is larger than the end time in the data (%2%)") % end_time + % slice_end_time); double old_duration = slice_end_time - slice_start_time; double included_duration = slice_end_time - start_time; double fraction = included_duration / old_duration; - + // Set the total singles so far to be the fraction of the bin. total_singles = fraction * _singles[start_slice][singles_bin_index]; - if ( start_slice < end_slice ) { - - // Calculate the fraction of the end_slice to include. - slice_start_time = get_slice_start_time(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 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_singles += _singles[slice][singles_bin_index]; - } - } + if (start_slice < end_slice) + { - return( static_cast(total_singles) ); - -} + // Calculate the fraction of the end_slice to include. + slice_start_time = get_slice_start_time(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 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_singles += _singles[slice][singles_bin_index]; + } + } + return (static_cast(total_singles)); +} /* * @@ -361,76 +326,74 @@ get_singles(const int singles_bin_index, * */ +void +SinglesRatesForTimeSlices::set_time_interval() +{ - - - -void -SinglesRatesForTimeSlices:: -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; - total += diff; - - if ( min_diff == 0 || diff < min_diff ) { - min_diff = diff; + 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) + { + min_diff = diff; + } + + if (diff > max_diff) + { + max_diff = 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 ) { - // Slice durations are not consistent enough to be considered the same. - _singles_time_interval = 0; - } - -} + 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 -SinglesRatesForTimeSlices:: -get_slice_start_time(int slice_index) const { +double +SinglesRatesForTimeSlices::get_slice_start_time(int slice_index) const +{ - if ( slice_index >= _num_time_slices ) { - slice_index = _num_time_slices - 1; - } - - if ( slice_index == 0 ) { - return(_times[0] - _singles_time_interval); - } else { - return(_times[slice_index - 1]); - } + if (slice_index >= _num_time_slices) + { + slice_index = _num_time_slices - 1; + } + + if (slice_index == 0) + { + return (_times[0] - _singles_time_interval); + } + else + { + return (_times[slice_index - 1]); + } } TimeFrameDefinitions -SinglesRatesForTimeSlices:: -get_time_frame_definitions() const +SinglesRatesForTimeSlices::get_time_frame_definitions() const { - std::vector > start_ends(get_num_time_slices()); - for (int i=0; i> start_ends(get_num_time_slices()); + for (int i = 0; i < get_num_time_slices(); ++i) { - start_ends[i].first=get_slice_start_time(i); - start_ends[i].second=_times[i]; + start_ends[i].first = get_slice_start_time(i); + start_ends[i].second = _times[i]; } return TimeFrameDefinitions(start_ends); } END_NAMESPACE_STIR - - - diff --git a/src/data_buildblock/SinglesRatesFromECAT7.cxx b/src/data_buildblock/SinglesRatesFromECAT7.cxx index 937f5f7c6..4be26d110 100644 --- a/src/data_buildblock/SinglesRatesFromECAT7.cxx +++ b/src/data_buildblock/SinglesRatesFromECAT7.cxx @@ -22,7 +22,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 @@ -36,20 +36,16 @@ START_NAMESPACE_STIR START_NAMESPACE_ECAT START_NAMESPACE_ECAT7 -const char * const -SinglesRatesFromECAT7::registered_name = "Singles From ECAT7"; +const char* const SinglesRatesFromECAT7::registered_name = "Singles From ECAT7"; -SinglesRatesFromECAT7:: -SinglesRatesFromECAT7() +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 @@ -60,112 +56,88 @@ 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) { - error("Error opening '%s' as ECAT7\n", ECAT7_filename.c_str()); - } - - 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()); - } - - scanner_sptr.reset(find_scanner_from_ECAT_system_type(mptr->mhptr->system_type)); + 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 + || mptr->mhptr->file_type == Float3dSinogram)) + { + error("SinglesRatesFromECAT7: filename %s should be an ECAT7 emission file\n", ECAT7_filename.c_str()); + } - if (scanner_sptr->get_type() != Scanner::E966) { - warning("check SinglesRatesFromECAT7 for non-966\n"); - } + 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 ) { - // Create the main array of data. - this->_singles = Array<2,float>(IndexRange2D(1, main_header->num_frames, - 0, total_singles_units - 1)); - } + 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)); + } - MatrixData* matrix; - 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.; - - 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) { - this->_singles[mat_frame][singles_bin] = *(singles_ptr + singles_bin); + 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.; + + 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) + { + 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 +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 ae55399c7..2bbd48b2d --- a/src/data_buildblock/SinglesRatesFromGEHDF5.cxx +++ b/src/data_buildblock/SinglesRatesFromGEHDF5.cxx @@ -30,106 +30,93 @@ #include #include - - START_NAMESPACE_STIR -namespace GE { -namespace RDF_HDF5 { +namespace GE +{ +namespace RDF_HDF5 +{ -const char * const -SinglesRatesFromGEHDF5::registered_name = "SinglesRatesFromGEHDF5"; +const char* const SinglesRatesFromGEHDF5::registered_name = "SinglesRatesFromGEHDF5"; // Constructor -SinglesRatesFromGEHDF5:: -SinglesRatesFromGEHDF5() +SinglesRatesFromGEHDF5::SinglesRatesFromGEHDF5() {} - void -SinglesRatesFromGEHDF5:: -read_from_file(const std::string& rdf_filename) +SinglesRatesFromGEHDF5::read_from_file(const std::string& rdf_filename) { - unsigned int slice = 0; + unsigned int slice = 0; - //PW Open the list mode file here. - m_input_sptr.reset(new GEHDF5Wrapper(rdf_filename)); + // PW Open the list mode file here. + m_input_sptr.reset(new GEHDF5Wrapper(rdf_filename)); + 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(); - 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(); + m_input_sptr->initialise_singles_data(); - m_input_sptr->initialise_singles_data(); + // Allocate the main array. + _num_time_slices = m_input_sptr->get_num_singles_samples(); + // GE uses unsigned int, while SinglesRateForTimeSlices uses int, so we need a copy + Array<2, unsigned int> GE_singles(IndexRange2D(0, _num_time_slices - 1, 0, total_singles_units - 1)); - // Allocate the main array. - _num_time_slices = m_input_sptr->get_num_singles_samples(); - // GE uses unsigned int, while SinglesRateForTimeSlices uses int, so we need a copy - Array<2, unsigned int> GE_singles(IndexRange2D(0, _num_time_slices - 1, 0, total_singles_units - 1)); - - while ( slice < _num_time_slices) + while (slice < _num_time_slices) { - m_input_sptr->read_singles(GE_singles[slice],slice+1); - ++slice; + m_input_sptr->read_singles(GE_singles[slice], slice + 1); + ++slice; } - // copy them across - _singles.grow(GE_singles.get_index_range()); - std::copy(GE_singles.begin_all(), GE_singles.end_all(), _singles.begin_all()); + // copy them across + _singles.grow(GE_singles.get_index_range()); + std::copy(GE_singles.begin_all(), GE_singles.end_all(), _singles.begin_all()); - //PW Modify this bit of code too. - if (slice != _num_time_slices) + // PW Modify this bit of code too. + if (slice != _num_time_slices) { - error("\nSinglesRatesFromGEHDF5: Couldn't read all records in the file. Read %d of %d. Exiting\n", - slice, _num_time_slices); - //TODO resize singles to return array with new sizes + error("\nSinglesRatesFromGEHDF5: Couldn't read all records in the file. Read %d of %d. Exiting\n", slice, _num_time_slices); + // TODO resize singles to return array with new sizes } - _times = std::vector(_num_time_slices); - if (_num_time_slices>1) // this is currently the same as checking if the input file is a listmode file + _times = std::vector(_num_time_slices); + if (_num_time_slices > 1) // this is currently the same as checking if the input file is a listmode file { // GE RDF9 listmode stores singles every second _singles_time_interval = 1.0; - for(unsigned int slice = 0;slice < _num_time_slices;++slice) - _times[slice] = slice+_singles_time_interval; // note that this has to store the "end-time" of the slice + for (unsigned int slice = 0; slice < _num_time_slices; ++slice) + _times[slice] = slice + _singles_time_interval; // note that this has to store the "end-time" of the slice - assert(_times.size()!=0); + assert(_times.size() != 0); } - else // Then it must be a sinogram, and therefore only has 1 time and 1 interval. + 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_end_time(1); - _singles_time_interval = tf.get_duration(1); + TimeFrameDefinitions tf = m_input_sptr->get_exam_info_sptr()->get_time_frame_definitions(); + _times[0] = tf.get_end_time(1); + _singles_time_interval = tf.get_duration(1); } } - -void -SinglesRatesFromGEHDF5:: -initialise_keymap() +void +SinglesRatesFromGEHDF5::initialise_keymap() { parser.add_start_key("SinglesRatesFromGEHDF5"); parser.add_key("filename", &_rdf_filename); parser.add_stop_key("End SinglesRatesFromGEHDF5"); } -bool -SinglesRatesFromGEHDF5:: -post_processing() +bool +SinglesRatesFromGEHDF5::post_processing() { read_from_file(_rdf_filename); return false; } - -void +void SinglesRatesFromGEHDF5::set_defaults() { _rdf_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 c8f4d19c6..96d8caa31 100644 --- a/src/data_buildblock/SinglesRatesFromSglFile.cxx +++ b/src/data_buildblock/SinglesRatesFromSglFile.cxx @@ -24,8 +24,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 @@ -34,35 +34,27 @@ using std::ofstream; using std::streampos; using std::ios; - - START_NAMESPACE_STIR START_NAMESPACE_ECAT START_NAMESPACE_ECAT7 -const unsigned -SinglesRatesFromSglFile::SIZE_OF_SINGLES_RECORD = 4*128; +const unsigned SinglesRatesFromSglFile::SIZE_OF_SINGLES_RECORD = 4 * 128; -const char * const -SinglesRatesFromSglFile::registered_name = "Singles From Sgl File"; +const char* const SinglesRatesFromSglFile::registered_name = "Singles From Sgl File"; -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; @@ -70,18 +62,12 @@ convert_int_to_4_bytes(unsigned long int val, unsigned char *buffer) { buffer[3] = (val & 0x000000ff); } - - - - // Constructor -SinglesRatesFromSglFile:: -SinglesRatesFromSglFile() +SinglesRatesFromSglFile::SinglesRatesFromSglFile() {} 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; @@ -93,219 +79,208 @@ read_singles_from_sgl_file(const std::string& sgl_filename) #else std::ifstream singles_file(sgl_filename.c_str(), std::ios::binary); - if (!singles_file) { - error("\nSinglesRatesFromSglFile: Couldn't open \"%s\".\n", sgl_filename.c_str()); - } + if (!singles_file) + { + 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()); - } - + if (!singles_file) + { + 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()); - } - + + if (!singles_file) + { + 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)); + singles_file.read(buffer, sizeof(_singles_main_header)); if (!singles_file) - { - error("\nSinglesRatesFromSglFile: Couldn't read main_header from %s.",sgl_filename.c_str()); - } + { + 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"); + { + 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; - + while (singles_file && slice < _num_time_slices) { - unsigned char 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); - } - break; - } + // 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); + if (!singles_file) + { + + if (!singles_file.eof()) + { + warning("Error reading singles file record %d. Stopped reading from this point.", slice); + } - 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); + 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); + } } - } - - 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); - } - - - - // Copy the singles values to the main array. - - // Note. The singles values are arranged num_axial sets of num_transaxial - // values. - // - // For a singles values for a unit at axial_index, transaxial_index - // the values is found at single_str.sgl[] - // singles_str.sgl[ transaxial_index + (axial_index * num_transaxial) ] - // - // The singles values are stored in the _singles array in the same order. - // For other file formats the ordering of the units may be different. - for (int singles_bin = 0; singles_bin < total_singles_units; ++singles_bin) { - _singles[slice][singles_bin] = static_cast(singles_str.sgl[singles_bin]); + 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); + } + + // Copy the singles values to the main array. + + // Note. The singles values are arranged num_axial sets of num_transaxial + // values. + // + // For a singles values for a unit at axial_index, transaxial_index + // the values is found at single_str.sgl[] + // singles_str.sgl[ transaxial_index + (axial_index * num_transaxial) ] + // + // The singles values are stored in the _singles array in the same order. + // For other file formats the ordering of the units may be different. + 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); + + // 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; } - - - // singles in the sgl file given in msec.multiply with 0.001 to convert into sec. - _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) - { - 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 - } + { + 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 + } #endif // Return number of time slices read. - return slice; - + return slice; } - - - - // Write SinglesRatesFromSglFile to a singles file. -std::ostream& -SinglesRatesFromSglFile::write(std::ostream& output) { +std::ostream& +SinglesRatesFromSglFile::write(std::ostream& output) +{ #ifndef HAVE_LLN_MATRIX 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); - } - - + if (!output) + { + error("\nSinglesRatesFromSglFile: Failed to write to 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) { - - // 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); - - // 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) { - 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); - - if (!output) { - error("\nSinglesRatesFromSglFile: Failed to write to output."); - break; - } + for (int slice = 0; slice < _num_time_slices; ++slice) + { - } - + // Write data to buffer. + millisecs = static_cast(floor(_times[slice] * 1000.0)); -#endif + // Time and number of singles units + convert_int_to_4_bytes(millisecs, buffer); + convert_int_to_4_bytes(total_singles_units, buffer + 4); - return 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) + { + 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); + if (!output) + { + error("\nSinglesRatesFromSglFile: Failed to write to output."); + break; + } + } + +#endif + + return output; +} /* * @@ -313,41 +288,27 @@ SinglesRatesFromSglFile::write(std::ostream& output) { * */ - -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 +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 3524232ce..0e066da97 100644 --- a/src/data_buildblock/data_buildblock_registries.cxx +++ b/src/data_buildblock/data_buildblock_registries.cxx @@ -15,15 +15,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 @@ -39,4 +39,3 @@ static GE::RDF_HDF5::SinglesRatesFromGEHDF5::RegisterIt dummy300; #endif END_NAMESPACE_STIR - diff --git a/src/data_buildblock/randoms_from_singles.cxx b/src/data_buildblock/randoms_from_singles.cxx index 1f47d4480..d21100db4 100644 --- a/src/data_buildblock/randoms_from_singles.cxx +++ b/src/data_buildblock/randoms_from_singles.cxx @@ -29,8 +29,8 @@ START_NAMESPACE_STIR -void randoms_from_singles(ProjData& proj_data, const SinglesRates& singles, - float coincidence_time_window, float isotope_halflife) +void +randoms_from_singles(ProjData& proj_data, const SinglesRates& singles, float coincidence_time_window, float isotope_halflife) { const auto& scanner = *proj_data.get_proj_data_info_sptr()->get_scanner_ptr(); if (coincidence_time_window <= 0.F) @@ -44,14 +44,12 @@ void randoms_from_singles(ProjData& proj_data, const SinglesRates& singles, const TimeFrameDefinitions frame_defs = proj_data.get_exam_info_sptr()->get_time_frame_definitions(); // get total singles for this frame - Array<2,float> total_singles(IndexRange2D(num_rings, num_detectors_per_ring)); - for (int r=0; r total_singles(IndexRange2D(num_rings, num_detectors_per_ring)); + for (int r = 0; r < num_rings; ++r) + for (int c = 0; c < num_detectors_per_ring; ++c) { - const DetectionPosition<> pos(c,r,0); - total_singles[r][c]=singles.get_singles(pos, - frame_defs.get_start_time(1), - frame_defs.get_end_time(1)); + const DetectionPosition<> pos(c, r, 0); + total_singles[r][c] = singles.get_singles(pos, frame_defs.get_start_time(1), frame_defs.get_end_time(1)); } { @@ -78,19 +76,17 @@ void randoms_from_singles(ProjData& proj_data, const SinglesRates& singles, */ const double duration = frame_defs.get_duration(1); const double decay_corr_factor = decay_correction_factor(isotope_halflife, 0., duration); - const double double_decay_corr_factor = decay_correction_factor(0.5*isotope_halflife, 0., duration); + const double double_decay_corr_factor = decay_correction_factor(0.5 * isotope_halflife, 0., duration); const double corr_factor = square(decay_corr_factor) / double_decay_corr_factor / duration; info(boost::format("Isotope half-life: %1%\n" "RFS: decay correction factor: %2%,\n" "time frame duration: %3%.\n" "total correction factor from 2tau*(singles_totals)^2 to randoms_totals: %4%.\n") - % isotope_halflife % decay_corr_factor % duration % (1/corr_factor), + % isotope_halflife % decay_corr_factor % duration % (1 / corr_factor), 2); - multiply_crystal_factors(proj_data, total_singles, - static_cast(coincidence_time_window * corr_factor)); - + multiply_crystal_factors(proj_data, total_singles, static_cast(coincidence_time_window * corr_factor)); } } diff --git a/src/display/display_array.cxx b/src/display/display_array.cxx index 0c3c9a822..96e81f61b 100644 --- a/src/display/display_array.cxx +++ b/src/display/display_array.cxx @@ -8,15 +8,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. @@ -25,9 +25,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. @@ -38,17 +38,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 @@ -60,7 +60,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 @@ -75,39 +75,39 @@ #include #include #include "stir/warning.h" - -// 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; @@ -116,16 +116,16 @@ void display_bitmap(const Array<3,elemT>& plane_stack, Coordinate3D max_indices; if (!plane_stack.get_regular_range(min_indices, max_indices)) - { - warning("display_bitmap: can only display 'regular' arrays. Returning.\n"); - return; - } + { + warning("display_bitmap: can only display 'regular' arrays. Returning.\n"); + return; + } const int length_y = max_indices[2] - min_indices[2] + 1; 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; @@ -135,172 +135,165 @@ 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); + 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 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 - 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); - // output title, making some attempt to centre it - 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; - - for(i=0; i=0; i--) + int nr = plane_stack.get_min_index(); + int i; + while (nr <= plane_stack.get_max_index()) { - //delete[] (sc_image[i].image); now deleted by XDestroyImage - delete[] (sc_image[i].text); + 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); + // output title, making some attempt to centre it + 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; + + for (i = 0; i < num_in_window && nr <= plane_stack.get_max_index(); i++, nr++) + { + double thismaxi; + + if (maxi != 0.0) + { + if (scale_factors[nr] != 0) + thismaxi = maxi / scale_factors[nr]; + else + { + if (plane_stack[nr].find_max() == 0) + thismaxi = 0; + else + { + warning("display: Relative scale of image %d is zero", nr); + return; + } + } + } + else + thismaxi = (double)plane_stack[nr].find_max(); + + // TODO ANCI C++ 'new' throws exception when it cannot allocate + if ((sc_image[i].image = new image_t[image_sizeX * image_sizeY]) == 0) + { + warning("display: Error allocating space for image buffer. Exiting"); + return; + } + + Array2DtoSCImg(sc_image[i].image, plane_stack[nr], scale, thismaxi); + // KT 29/2/2000 + // work-around for the fact that the (old) display library + // does not use const char*. We copy the data into char *... + // There would be problems if sc_image[i].text is going + // to be modified. However, draw_sc_images does not do this, so let's + // live with it (otherwise it requires changing lots of declarations + // in screen.c, and possibly X !) + // TODO ? + sc_image[i].text = new char[strlen((text[nr] == 0) ? "" : text[nr])]; + strcpy(sc_image[i].text, (text[nr] == 0) ? "" : text[nr]); + } + + 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); + } + 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) +static void +Array2DtoSCImg(image_t image[], const Array<2, elemT>& plane, int scale, double maxi) { - image_t *pimage; - image_t *pix; - int y_count,x_count,i; + image_t* pimage; + image_t* pix; + 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) - { - const elemT current = plane[y_count][x_count]; - if (current<=0) - *pix = (SC_pixel_t)SC_C_BACKGROUND; - 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); - } - if (scale==1) return; + 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) + *pix = (SC_pixel_t)SC_C_BACKGROUND; + 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); + } + 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. -*/ - long tmp, init; - - tmp = (((long)*(pix+scale) - (int)*pix) * 0x100) / scale ; - for (i=1, init=*pix * 0x100L + 0x80; i 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; i < scale; i++) + *(pix + i) = (SC_pixel_t)((init + i * tmp) / 0x100); + } /* interpolate vertical lines */ pimage = image; - for (y_count=org_length_y-1; y_count>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 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++) + 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; - } + 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)) - { - warning("display_pgm: can only display 'regular' arrays. Returning.\n"); - return; - } + { + 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"); + + FILE* pgm = fopen(name, "wb"); if (pgm == NULL) + { + warning("Error opening file %s for output to PGM.", name); + return; + } + { - 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]); - if (scaled_max < scaled_plane_max) - scaled_max = scaled_plane_max; - } + 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; + } } - + 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 z = min_indices[1]; z <= max_indices[1]; z++) { - 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 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); + } } - // now draw white line below this image - 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); } @@ -449,16 +439,16 @@ 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; @@ -468,141 +458,133 @@ 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()); - ++text_iter; - ++vs_iter; - } + 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; - ++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) - { - full_data.fill(0); - for (int a = 0; a 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 < num_detectors_per_ring; ++a) + for (int rb = 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) + full_data[rb][a % num_detectors_per_ring][b % num_detectors_per_ring] = fan_data(ra, a, rb, b); + display(full_data, full_data.find_max(), title); + } } - /*********************************************** instantiations ***********************************************/ -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); +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 2d9fcc894..f8aeccec6 100644 --- a/src/display/gen.c +++ b/src/display/gen.c @@ -1,5 +1,5 @@ /* -*/ + */ /* Copyright (C) 2000 PARAPET partners Copyright (C) 2000- 2011, Hammersmith Imanet Ltd @@ -7,113 +7,124 @@ 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; - - 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) - return def; - if ((nnn>=minv) && (nnn<=maxv)) - return nnn; - puts("\nOut of bounds"); - } +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) + return def; /* nothing read, so return default */ + ret = sscanf(ptr, "%d", &nnn); + if (ret == 0 || ret == EOF) + return def; + 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); + 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); + { + sprintf(tmp, "\n%s: error reading for %lu bytes, %lu read\nreason", str, (unsigned long)size, (unsigned long)ret); + perror(tmp); + error(""); + } + 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); + 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); + { + 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); } -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 8dbb1ec42..20245681d 100644 --- a/src/display/gen.h +++ b/src/display/gen.h @@ -1,5 +1,5 @@ -/* -*/ +/* + */ /* Copyright (C) 2000 PARAPET partners Copyright (C) 2000- 2001, IRSL @@ -7,18 +7,18 @@ 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 @@ -26,8 +26,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 @@ -50,16 +50,17 @@ systems. /* Change November 1997: added next 3 lines */ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif #ifdef VAX -/* The VAX library does not have getch. An implemenation is provided in gen.c - getch reads a character from the keyboard without waiting for a - carriage return. You can use it for detecting arrowkeys - in combination with the KB_... macro's. -*/ -extern char getch(void); + /* The VAX library does not have getch. An implemenation is provided in gen.c + getch reads a character from the keyboard without waiting for a + carriage return. You can use it for detecting arrowkeys + in combination with the KB_... macro's. + */ + extern char getch(void); /* Macro's for using the arrowkeys. Use in the following way: char ch; ch = getch(); @@ -74,100 +75,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__ +# ifdef __GNUC__ /* TODO */ -#define getch() getchar() -#else -#include /* for getch */ -#define getch _getch -#endif +# 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 */ +# 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 +# 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 15d9a52b9..6ee86164c 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 @@ -8,120 +8,124 @@ */ /*! -\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; - - 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)) - return nnn; - puts("\nOut of bounds"); - } + 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) + return def; + 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) +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); + 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) +static void +deinit(void) { - if( ep) MLDeinitialize( ep); + if (ep) + MLDeinitialize(ep); } - -static void closelink( void) +static void +closelink(void) { - if( lp) MLClose( lp); + if (lp) + MLClose(lp); } - -void init_and_connectlink( char* linkname) +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); + 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 38c580973..509becc53 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 @@ -11,18 +11,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" @@ -31,8 +31,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; @@ -41,7 +41,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; @@ -52,249 +52,249 @@ 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]; +{ + 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 */ @@ -329,10 +332,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; @@ -345,293 +349,306 @@ 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) +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); + 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) + { + XEvent report; + char chr[2]; + XNextEvent(SCX_display, &report); + switch (report.type) + { + case ButtonPress: + if (report.xbutton.button == Button3) { - 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; - } + 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); + 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; } - 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); +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; - CurrentColormap = (CurrentColormap+1) % NUMBER_SCALES; - - SetColormap(SCX_display, SCX_window, SCX_visual_info, - all_color_scales[CurrentColormap].p, - all_color_scales[CurrentColormap].size); - break; - + XNextEvent(SCX_display, &report); + switch (report.type) + { + case KeyPress: + stop = 1; + 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; + } } - } - 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 ) + 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; - } + 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 ) - { - int i; - for (i=0; i< lengthX*lengthY; ++i) + if (SCX_get_class(SCX_visual_info) != PseudoColor || bytes_per_line != lengthX) { - 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); - 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. - */ - 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; - } - } - 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); + int 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); + 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. + */ + 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; + } + } + 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; } 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", @@ -639,68 +656,64 @@ 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 5f2bdae0b..a9c0ceba1 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 @@ -26,180 +26,175 @@ See STIR/LICENSE.txt for details */ - /* Change November 1997: added next 3 lines */ #ifdef __cplusplus -extern "C" { +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 -typedef SC_pixel_t image_t; -#else -typedef SC_pixel_t huge image_t; -#endif +# ifndef MSDOS16BIT + typedef SC_pixel_t image_t; +# else + typedef SC_pixel_t huge image_t; +# 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 Window SCX_window; -extern GC SCX_gc; + extern Display* SCX_display; + extern Window SCX_window; + extern GC SCX_gc; /* KT 28/11/2002 added for TrueColor support */ -extern XVisualInfo SCX_visual_info; -extern unsigned long SCX_color_translation[SC_C_FULL+1]; + extern XVisualInfo SCX_visual_info; + 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); + 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 - -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)) +# 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) -/* 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) -*/ +# 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) +# 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); - -typedef struct screen_image - { image_t *image; - int sx,sy; - char *text; - } screen_image_t; -/***************************************************************************** - 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); - + /* 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); + + typedef struct screen_image + { + image_t* image; + int sx, sy; + char* text; + } screen_image_t; + /***************************************************************************** + 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); /* 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 fc46abf90..e5e8879cd 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 @@ -26,107 +26,110 @@ #define SCreen_compiling #include "screen.h" - -void put_textstr (int x, int y, const char str[]) +void +put_textstr(int x, int y, const char str[]) { - int xx,yy; + 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 - { - /* 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); + { + /* 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); /* 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_x * nr_y > nr_sc) { - if (nr_y==1) nr_x=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++; - } + { + nr_y = nr_sc / nr_x; + if (nr_x * nr_y < nr_sc) + nr_y++; + } } else { - nr_sc = nr_x*nr_y; + 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 */ - - for(nr=0, i=0, y=start_y; i float_limits; @@ -46,28 +47,30 @@ void ROIValues::init() std_value = 0; } -void ROIValues::update() +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; - const float square_mean = square(mean_value); - - variance_value = (integral_of_square/roi_volume - square_mean); - if (fabs(variance_value) < 10E-5 * square_mean) + if (roi_volume == 0) + { + // ill_defined case... + mean_value = 0; variance_value = 0; - std_value = sqrt(variance_value); - } + std_value = 0; + } + else + { + mean_value = integral / roi_volume; + const float square_mean = square(mean_value); + + 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 { std::ostringstream s; s << " Volume of ROI = " << roi_volume << endl; @@ -106,8 +109,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, +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); - shared_ptr > - discretised_shape_ptr(image.get_empty_voxels_on_cartesian_grid()); - + const VoxelsOnCartesianGrid& image = dynamic_cast&>(density); + shared_ptr> discretised_shape_ptr(image.get_empty_voxels_on_cartesian_grid()); shape.construct_volume(*discretised_shape_ptr, num_samples); @@ -49,8 +45,8 @@ compute_ROI_values_per_plane(VectorWithOffset& values, void compute_ROI_values_per_plane(VectorWithOffset& values, - const DiscretisedDensity<3,float>& density, - const DiscretisedDensity<3,float>& discretised_shape) + const DiscretisedDensity<3, float>& density, + const DiscretisedDensity<3, float>& discretised_shape) { if (!density.has_same_characteristics(discretised_shape)) error("compute_ROI_values_per_plane: density and discretised_shape do not have the same characteristics."); @@ -65,8 +61,8 @@ compute_ROI_values_per_plane(VectorWithOffset& values, // initialise values correct size values = VectorWithOffset(min_z, max_z); - 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)[z].sum() * voxel_volume; (discretised_shape)[z] *= image[z]; @@ -77,43 +73,39 @@ compute_ROI_values_per_plane(VectorWithOffset& values, (discretised_shape)[z] *= image[z]; const float integral_square =(discretised_shape)[z].sum() * voxel_volume; #else - float ROI_min = std::numeric_limits::max(); - float ROI_max = std::numeric_limits::min(); - float integral = 0; - float integral_square = 0; - float volume = 0; - { - Array<2,float>::const_full_iterator - discr_shape_iter = (discretised_shape)[z].begin_all_const(); - const Array<2,float>::const_full_iterator - discr_shape_end = (discretised_shape)[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); - } - integral *= voxel_volume; - integral_square *= voxel_volume; - volume *= voxel_volume; - } + float ROI_min = std::numeric_limits::max(); + float ROI_max = std::numeric_limits::min(); + float integral = 0; + float integral_square = 0; + float volume = 0; + { + Array<2, float>::const_full_iterator discr_shape_iter = (discretised_shape)[z].begin_all_const(); + const Array<2, float>::const_full_iterator discr_shape_end = (discretised_shape)[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 @@ -121,156 +113,140 @@ 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); } ROIValues -compute_total_ROI_values(const DiscretisedDensity<3,float>& image, - const DiscretisedDensity<3,float>& discretised_shape) +compute_total_ROI_values(const DiscretisedDensity<3, float>& image, const DiscretisedDensity<3, float>& discretised_shape) { if (!image.has_same_characteristics(discretised_shape)) error("compute_total_ROI_values: image and discretised_shape do not have the same characteristics."); VectorWithOffset values; compute_ROI_values_per_plane(values, image, discretised_shape); - 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) +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 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++) - { - const float volume = discretised_shape.sum() * voxel_volume; - discretised_shape[z] *= image[z]; - const float ROI_min = discretised_shape.find_min(); - const float ROI_max = discretised_shape.find_max(); - 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); - } + 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(); + const float ROI_max = discretised_shape.find_max(); + 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); + } } - 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; + return val1.get_mean() / val2.get_mean() - 1; } - float compute_uniformity(ROIValues& val) { - return val.get_stddev()/val.get_mean(); + 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) { - 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]); - } + 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 60d842499..9239a3a11 100644 --- a/src/experimental/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.cxx +++ b/src/experimental/IO/ECAT7DynamicDiscretisedDensityOutputFileFormat.cxx @@ -29,21 +29,18 @@ 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"); @@ -51,9 +48,8 @@ initialise_keymap() base_type::initialise_keymap(); } -void -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -set_defaults() +void +ECAT7DynamicDiscretisedDensityOutputFileFormat::set_defaults() { this->default_scanner_name = "ECAT 962"; base_type::set_defaults(); @@ -64,69 +60,62 @@ 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) + if (find_ECAT_system_type(*scanner_ptr) == 0) { warning("ECAT7DynamicDiscretisedDensityOutputFileFormat: default_scanner_name %s is not supported\n", - this->default_scanner_name.c_str()); + this->default_scanner_name.c_str()); return true; } return false; } -NumericType -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -set_type_of_numbers(const NumericType& new_type, const bool warn) +NumericType +ECAT7DynamicDiscretisedDensityOutputFileFormat::set_type_of_numbers(const NumericType& new_type, const bool warn) { - const NumericType supported_type_of_numbers = - NumericType("signed integer", 2); + 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"); - this->type_of_numbers = supported_type_of_numbers; - } + { + if (warn) + 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 this->type_of_numbers = new_type; return this->type_of_numbers; } -ByteOrder -ECAT7DynamicDiscretisedDensityOutputFileFormat:: -set_byte_order(const ByteOrder& new_byte_order, const bool warn) +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; - } + { + if (warn) + warning("ECAT7DynamicDiscretisedDensityOutputFileFormat: byte_order is currently fixed to big-endian\n"); + this->file_byte_order = ByteOrder::big_endian; + } 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 45fbbe382..ef1313aad 100644 --- a/src/experimental/IO/OutputFileFormat_default.cxx +++ b/src/experimental/IO/OutputFileFormat_default.cxx @@ -12,11 +12,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 af72ec815..d2b32fdee 100644 --- a/src/experimental/IO/local_InputFileFormatRegistry.cxx +++ b/src/experimental/IO/local_InputFileFormatRegistry.cxx @@ -20,5 +20,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 45fbbe382..ef1313aad 100644 --- a/src/experimental/IO/local_OutputFileFormat_default.cxx +++ b/src/experimental/IO/local_OutputFileFormat_default.cxx @@ -12,11 +12,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 c9b00dcfd..e143f0975 100644 --- a/src/experimental/buildblock/AbsTimeIntervalFromDynamicData.cxx +++ b/src/experimental/buildblock/AbsTimeIntervalFromDynamicData.cxx @@ -27,38 +27,33 @@ START_NAMESPACE_STIR -const char * const -AbsTimeIntervalFromDynamicData::registered_name = "from Dynamic Data"; +const char* const AbsTimeIntervalFromDynamicData::registered_name = "from Dynamic Data"; -AbsTimeIntervalFromDynamicData:: -AbsTimeIntervalFromDynamicData() +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() +Succeeded +AbsTimeIntervalFromDynamicData::set_times() { - if (this->_start_time_frame_num==0) + 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) + if (this->_end_time_frame_num == 0) { warning("AbsTimeIntervalFromDynamicData: need to set end_time_frame_num"); return Succeeded::no; @@ -67,56 +62,48 @@ set_times() 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(); + 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)); - + 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(); + 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->_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->_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); + 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"); @@ -126,8 +113,7 @@ initialise_keymap() } bool -AbsTimeIntervalFromDynamicData:: -post_processing() +AbsTimeIntervalFromDynamicData::post_processing() { if (set_times() == Succeeded::no) { diff --git a/src/experimental/buildblock/AbsTimeIntervalFromECAT7ACF.cxx b/src/experimental/buildblock/AbsTimeIntervalFromECAT7ACF.cxx index 01dc99720..37088d677 100644 --- a/src/experimental/buildblock/AbsTimeIntervalFromECAT7ACF.cxx +++ b/src/experimental/buildblock/AbsTimeIntervalFromECAT7ACF.cxx @@ -23,70 +23,59 @@ START_NAMESPACE_STIR -const char * const -AbsTimeIntervalFromECAT7ACF::registered_name = "from ECAT7 ACF"; +const char* const AbsTimeIntervalFromECAT7ACF::registered_name = "from ECAT7 ACF"; -AbsTimeIntervalFromECAT7ACF:: -AbsTimeIntervalFromECAT7ACF() +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) + if (_transmission_duration <= 0) { - warning("AbsTimeIntervalFromECAT7ACF: duration should be > 0 but is %g%.", - _transmission_duration); + 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) + 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"); @@ -95,8 +84,7 @@ initialise_keymap() } bool -AbsTimeIntervalFromECAT7ACF:: -post_processing() +AbsTimeIntervalFromECAT7ACF::post_processing() { if (set_times() == Succeeded::no) { diff --git a/src/experimental/buildblock/AbsTimeIntervalWithParsing.cxx b/src/experimental/buildblock/AbsTimeIntervalWithParsing.cxx index 6e47f084c..0f17f2e52 100644 --- a/src/experimental/buildblock/AbsTimeIntervalWithParsing.cxx +++ b/src/experimental/buildblock/AbsTimeIntervalWithParsing.cxx @@ -21,30 +21,25 @@ 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; +static const double time_not_yet_determined = -4321; -AbsTimeIntervalWithParsing:: -AbsTimeIntervalWithParsing() +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"); @@ -53,19 +48,16 @@ initialise_keymap() } bool -AbsTimeIntervalWithParsing:: -post_processing() +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()); + 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()); + warning("AbsTimeInterval: duration (%g) should be > 0", this->get_duration_in_secs()); return true; } diff --git a/src/experimental/buildblock/DAVArrayFilter3D.cxx b/src/experimental/buildblock/DAVArrayFilter3D.cxx index a8f91c283..84cf06648 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 @@ -19,7 +19,7 @@ #include "stir_experimental/DAVArrayFilter3D.h" #include "stir/Coordinate3D.h" #include "stir/Array.h" -// remove +// remove #include #include #include @@ -33,131 +33,120 @@ using std::endl; using std::sort; using std::min_element; - START_NAMESPACE_STIR - template 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 +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]; - // 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]]; - // 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 + + 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 (int i = 4;i<=8; i++) - averaged_arrays3D[i] = 0; + // 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]; + // 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]]; + // 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; + } } - - } - - 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 +DAVArrayFilter3D::is_trivial() const { - if (mask_radius_x!=1 &&mask_radius_y !=1 &&mask_radius_z!=1) + 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 53c2452ba..7eb803ad3 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 @@ -30,11 +30,10 @@ using std::fstream; using std::cerr; using std::endl; - 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(); @@ -42,42 +41,39 @@ DAVImageFilter3D:: DAVImageFilter3D(const CartesianCoordinate3D& mas } 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) - // return Succeeded::no; - dav_filter = - DAVArrayFilter3D(Coordinate3D - (mask_radius_z, mask_radius_y, mask_radius_x)); + // if (consistency_check(density) == Succeeded::no) + // return Succeeded::no; + 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); + // 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 +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); - + // assert(consistency_check(in_density) == Succeeded::yes); + // cerr << mask_radius_x << " " << mask_radius_y << endl; + dav_filter(out_density, in_density); } template @@ -90,7 +86,7 @@ DAVImageFilter3D::set_defaults() } template -void +void DAVImageFilter3D::initialise_keymap() { parser.add_start_key("DAV Filter Parameters"); @@ -100,16 +96,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 @@ -121,6 +114,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 7b5c6eb0e..b73e9bc72 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 @@ -44,855 +44,892 @@ 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); - 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_3D_array.grow(IndexRange3D(0,0,0,0,0,0)); - } - else if (sq_kapas!=1.F) - { - - while(true) + if (size_for_kapa0_over_kapa1.get_length() == 0) { - 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 < 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); - - - // rescale to DC=1 - filter_coefficients_padded /= filter_coefficients_padded.sum(); - - 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); - 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; + size_for_kapa0_over_kapa1.grow(0, length_of_size_array - 1); + size_for_kapa0_over_kapa1.fill(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; + const int kapa0_over_kapa1_interval + = min(static_cast(floor(kapa0_over_kapa1 / kapa0_over_kapa1_interval_size)), length_of_size_array - 1); - } - } - 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; + float sq_kapas = kapa0_over_kapa1; + /******************************************************************************************/ - } - } - 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*64))); - break; - case 128: - 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; - - 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<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 + 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 + // ( 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<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; + + 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); + 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; + } + } + 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"); + } + + // 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 * 64))); + break; + case 128: + 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; + + 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<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()); + + 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 < 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 + else // sq_kappas == 1 { new_filter_coefficients_3D_array = filter_coefficients; } - - -#endif - - - // 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; - - +#endif + + // 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; } void -construct_scaled_filter_coefficients_2D(Array<2,float> &new_filter_coefficients_2D_array, - VectorWithOffset kernel_1d, - const float kapa0_over_kapa1) - +construct_scaled_filter_coefficients_2D(Array<2, float>& new_filter_coefficients_2D_array, + VectorWithOffset kernel_1d, + const float kapa0_over_kapa1) + { - - 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) + if (kapa0_over_kapa1 != 0) { - 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 < 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; - - } - } - 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; + // kapa0_over_kapa1 - 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; + // 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())); - divide_complex_arrays(fft_filter_num_1D_array,fft_filter_1D_array); + 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]; + } + + /*************************************************************************************/ + + 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; + } - - 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)); - +#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()); - - 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 -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; @@ -900,1508 +937,1623 @@ 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) +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 + 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; - + return Succeeded::yes; } - template -void -ModifiedInverseAveragingImageFilterAll::precalculate_filter_coefficients (VectorWithOffset < VectorWithOffset < VectorWithOffset > > > >& all_filter_coefficients, - DiscretisedDensity<3,elemT>* in_density) const +void +ModifiedInverseAveragingImageFilterAll::precalculate_filter_coefficients( + VectorWithOffset>>>>& + all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const { - - 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()); - + 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); + + 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) - { - 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") - { - 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); + 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") + { + 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); + } } - - } - - 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); - 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; - + 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; + 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, false); //true); - + + 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]; - } - + { + 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(); + } + } + + 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]; - } - - - + { + 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 +void +ModifiedInverseAveragingImageFilterAll::precalculate_filter_coefficients_2D( + VectorWithOffset>>>>& + all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const { - - VectorWithOffset < shared_ptr > > filter_lookup; + + 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) - { - 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") - { - 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); + 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") + { + 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); + } } - - } - - 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); - 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; - + 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; + 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, 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 - { + 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]; + } - all_filter_coefficients[k][j][i] = - new ArrayFilter2DUsingConvolution(); - - } - - } + info(boost::format("min and max in image - kappa1 %1%, %2%") % kappa1_ptr_bck->find_min() % kappa1_ptr_bck->find_max()); - - //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") + { + +# 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]; + } + } + else + { + + all_filter_coefficients[k][j][i] = new ArrayFilter2DUsingConvolution(); + } + } + + // 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]; - } - - - + { + 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 +void +ModifiedInverseAveragingImageFilterAll::precalculate_filter_coefficients_separable( + VectorWithOffset>>>>& + all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const { - - VectorWithOffset < shared_ptr > > filter_lookup; + + 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) - { - 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") { - 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); + 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") + { + 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); + } } - - } - - 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); - 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; - + 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; + 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, 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; - 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 - { + 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); - 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[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()); - - 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") + { +# 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 + { + + all_filter_coefficients[k][j][i] + = new ModifiedInverseAverigingArrayFilter<3, float>(); // 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]; - } - - - + { + 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 +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; + // 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); - } - } - else + const VoxelsOnCartesianGrid& in_density_cast_0 = dynamic_cast&>(in_density); - precalculate_filter_coefficients_separable(all_filter_coefficients_separable,initial_image); - + // 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 - // { - // } - } 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); - } - - } - - 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]; - } - - - } - - } - } - - -#endif + 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); + } + } + + 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; + 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 +ModifiedInverseAveragingImageFilterAll::virtual_apply(DiscretisedDensity<3, elemT>& density) const { - DiscretisedDensity<3,elemT>* tmp_density = - density.clone(); + DiscretisedDensity<3, elemT>* tmp_density = density.clone(); virtual_apply(density, *tmp_density); delete tmp_density; } - template void 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); @@ -2410,36 +2562,30 @@ 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 @@ -2448,14 +2594,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 420acd136..bfb536f3d 100644 --- a/src/experimental/buildblock/ModifiedInverseAverigingArrayFilter.cxx +++ b/src/experimental/buildblock/ModifiedInverseAverigingArrayFilter.cxx @@ -21,290 +21,264 @@ using std::iostream; using std::cerr; using std::endl; - - START_NAMESPACE_STIR - - -void -FFT_routines::find_fft_filter(Array<1,float>& filter_coefficients) +void +FFT_routines::find_fft_filter(Array<1, float>& filter_coefficients) { - four1(filter_coefficients,filter_coefficients.get_length()/2,1); + four1(filter_coefficients, filter_coefficients.get_length() / 2, 1); } - + void -FFT_routines::find_fft_unity(Array<1,float>& unity) +FFT_routines::find_fft_unity(Array<1, float>& unity) { - four1(filter_coefficients,filter_coefficients.get_length()/2,1); + 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) +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 + + // 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); - size_for_kapa0_over_kapa1.fill(64); - } - - - 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 (size_for_kapa0_over_kapa1.get_length() == 0) { - 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; - - 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) - { - 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; - case 1024: - fft_filter_1D_array_ptr = &fft_filter_1D_array_1024; - break; - case 2048: - fft_filter_1D_array_ptr = &fft_filter_1D_array_2048; - break; - case 4096: - fft_filter_1D_array_ptr = &fft_filter_1D_array_4096; - break; - case 8192: - 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; - } - 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> 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)); - - //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); - - - - // make it consistent with mathemematica -- the output of the - fft_filter_num_1D_array /= sqrt(static_cast(size/2)); - + size_for_kapa0_over_kapa1.grow(0, length_of_size_array - 1); + size_for_kapa0_over_kapa1.fill(64); + } - // 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 new_filter_coefficients; + /******************************************************************************************/ - - - break; // out of while(true) - } - //} - } // this bracket is for the while loop + if (sq_kapas > 10000) + { + new_filter_coefficients.grow(0, 0); } - else //sq_kappas == 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]; + 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) + { + 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; + case 1024: + fft_filter_1D_array_ptr = &fft_filter_1D_array_1024; + break; + case 2048: + fft_filter_1D_array_ptr = &fft_filter_1D_array_2048; + break; + case 4096: + fft_filter_1D_array_ptr = &fft_filter_1D_array_4096; + break; + case 8192: + 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; + } + 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> 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)); + + // 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); + + // 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 < 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++) + + 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); + all_1d_array_filters[i - 1] = new ArrayFilter1DUsingConvolution(new_filter_coefficients); } - - } - -#endif - +} +#endif // SM new 17/09/2001 #if 0 @@ -327,7 +301,7 @@ ModifiedInverseAverigingArrayFilter(const VectorWithOffset& filter_coeffi *coeff_output<< endl; //cerr < size_for_kapa0_over_kapa1; @@ -520,9 +494,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] << " "; @@ -570,38 +543,13 @@ ModifiedInverseAverigingArrayFilter(const VectorWithOffset& filter_coeffi } - #endif - template ModifiedInverseAverigingArrayFilter<3, float>; END_NAMESPACE_STIR - - - - - - - - - - - - - - - - - - - - - - - -//old +// old #if 0 @@ -689,7 +637,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 5cb212a2e..1e48f707f 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 @@ -57,216 +57,201 @@ 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); - size_for_kapa0_over_kapa1.fill(64); - } - - - float sq_kapas = 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)); - } - 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) { - 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_x = size; - 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) - { - 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; - default: - 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_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)); - } - /* - 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] << " "; */ - - - 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; + 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_x = size; + 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) + { + 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; + default: + 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_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)); + } + /* + 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] << " "; */ + + 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; + + /* 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,939 +262,1029 @@ 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); + // 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] << " "; - - }*/ - - - - // 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] << " "; + 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] << " "; + }*/ +} 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) +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 + 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) - { - 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") { - do_attenuation = true; - all_attenuation_segments[segment_num] = - new SegmentByView(attenuation_proj_data_ptr->get_segment_by_view(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") + { + 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); + } } - 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); - } - - } - - 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); - 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; - + 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; + 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, false); //true); - + + 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]; - } - + { + 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]; - } - - - + { + 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 +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; + // 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 + // { + // } } - 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>; - - } - } - } - - } - - - 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]; - - } - } + 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>; + } + } + } + } + + 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]; + } + } + } + + 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 +ModifiedInverseAverigingImageFilter::virtual_apply(DiscretisedDensity<3, elemT>& density) const { - DiscretisedDensity<3,elemT>* tmp_density = - density.clone(); + DiscretisedDensity<3, elemT>* tmp_density = density.clone(); virtual_apply(density, *tmp_density); delete tmp_density; } - template void 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); @@ -1223,32 +1298,24 @@ 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 +1323,6 @@ ModifiedInverseAverigingImageFilter::registered_name = template ModifiedInverseAverigingImageFilter; - - END_NAMESPACE_STIR - /************************************************************************************************/ - - - - - diff --git a/src/experimental/buildblock/NonseparableSpatiallyVaryingFilters.cxx b/src/experimental/buildblock/NonseparableSpatiallyVaryingFilters.cxx index e166beb80..d359d8d37 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,540 @@ 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); -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); - +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())); + filter_coefficients = kernel_2d; + // 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); -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) - -{ -#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())); - filter_coefficients = kernel_2d; - - // 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_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]; - } - - } + float sq_kapas = kapa0_over_kapa1; + /******************************************************************************************/ - 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 ++; - } + 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)); - /* 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 + // 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 +584,571 @@ 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) +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 + 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 - sensitivity_image = NULL; - - if (precomputed_coefficients_filename !="1") - precomputed_coefficients_image = - DiscretisedDensity<3,float>::read_from_file(precomputed_coefficients_filename); + + if (initial_image_filename != "1") + initial_image = DiscretisedDensity<3, float>::read_from_file(initial_image_filename); else - precomputed_coefficients_image =NULL; - - if (normalised_bck_filename !="1") - normalised_bck_image = - DiscretisedDensity<3,float>::read_from_file(normalised_bck_filename); + initial_image = NULL; + + if (sensitivity_image_filename != "1") + sensitivity_image = DiscretisedDensity<3, float>::read_from_file(sensitivity_image_filename); else - normalised_bck_image =NULL; - - - - return Succeeded::yes; - -} + 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 (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 -NonseparableSpatiallyVaryingFilters::precalculate_filter_coefficients_2D (VectorWithOffset < VectorWithOffset < VectorWithOffset > > > >& all_filter_coefficients, - DiscretisedDensity<3,elemT>* in_density) const +void +NonseparableSpatiallyVaryingFilters::precalculate_filter_coefficients_2D( + VectorWithOffset>>>>& + all_filter_coefficients, + DiscretisedDensity<3, elemT>* in_density) const { - - VectorWithOffset < shared_ptr > > filter_lookup; + + 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) - { - 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") { - 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); + 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") + { + 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); + } } - - } - - 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); - 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; - + 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; + 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, false); //true); - + + 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]; - } - + { + 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; - 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]; - } - - - -} + 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]; + } +} // 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) + + 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") { - 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(); - - } - - - } - } - else - precalculate_filter_coefficients_2D(all_filter_coefficients_nonseparable_2D,initial_image); - - + 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*>(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 - {} - - 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() +void +NonseparableSpatiallyVaryingFilters::virtual_apply(DiscretisedDensity<3, elemT>& density) const { - const unsigned int size_x = filter_coefficients_for_parsing[1].get_length(); - const unsigned int size_y = filter_coefficients_for_parsing.get_length(); + 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]); - } -return false; +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"); } - - -const char * const -NonseparableSpatiallyVaryingFilters::registered_name = -"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; +} + +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 352dc8073..c3f47f55e 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 @@ -46,136 +46,134 @@ 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())); - - 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); - - while(true) + if (kapa0_over_kapa1 != 0) { - 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]; - - } + // 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); + + 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++) { @@ -190,227 +188,274 @@ 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; + } + } + } + } #if 0 for (int k = 0;k<= 20;k++) @@ -420,48 +465,40 @@ 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(); - -} + // rescale to DC=1 + 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; @@ -469,601 +506,605 @@ 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) +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 + 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) - { - 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") - { - 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); + 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") + { + 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); + } } - - } - - 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); - 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; - + 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; + 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, false); //true); - + + 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]; - } - + { + 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]; - } - - - + { + 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) + // 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); - } + 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); + } } - 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) + 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< 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); + + 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) + 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(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 + 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 - } - +# 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 +NonseparableSpatiallyVaryingFilters3D::virtual_apply(DiscretisedDensity<3, elemT>& density) const { - DiscretisedDensity<3,elemT>* tmp_density = - density.clone(); + 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"); - } - + 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() +void +NonseparableSpatiallyVaryingFilters3D::initialise_keymap() { - 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(); + 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 59e65190b..39c2f36bd 100644 --- a/src/experimental/buildblock/Quaternion.cxx +++ b/src/experimental/buildblock/Quaternion.cxx @@ -16,23 +16,18 @@ See STIR/LICENSE.txt for details */ - #include "stir_experimental/Quaternion.h" - START_NAMESPACE_STIR template Quaternion::Quaternion() - : base_type() + : 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; @@ -42,7 +37,7 @@ Quaternion::Quaternion(const coordT& c1, template Quaternion::Quaternion(const base_type& c) - : base_type(c) + : base_type(c) {} #if 0 @@ -75,7 +70,6 @@ Quaternion:: component_4() const } #endif - template class Quaternion; END_NAMESPACE_STIR diff --git a/src/experimental/buildblock/SeparableLowPassArrayFilter.cxx b/src/experimental/buildblock/SeparableLowPassArrayFilter.cxx index ea608d78f..76b6aed37 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 @@ -17,57 +16,48 @@ using std::endl; See STIR/LICENSE.txt for details */ - START_NAMESPACE_STIR template -SeparableLowPassArrayFilter:: -SeparableLowPassArrayFilter() +SeparableLowPassArrayFilter::SeparableLowPassArrayFilter() { - for (int i=1;i<=num_dimensions;i++) - { - all_1d_array_filters[i-1] = - new ArrayFilter1DUsingConvolution(); - } + 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); - } - all_1d_array_filters[0] = - new ArrayFilter1DUsingConvolution(); - - } - + // 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(); + } } -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 b6fb4923b..bc47248ca 100644 --- a/src/experimental/buildblock/SeparableLowPassImageFilter.cxx +++ b/src/experimental/buildblock/SeparableLowPassImageFilter.cxx @@ -10,134 +10,107 @@ START_NAMESPACE_STIR template -SeparableLowPassImageFilter:: -SeparableLowPassImageFilter() -:filter_coefficients(VectorWithOffset(-1,1)) +SeparableLowPassImageFilter::SeparableLowPassImageFilter() + : filter_coefficients(VectorWithOffset(-1, 1)) { - set_defaults(); + 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) +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]); - }*/ + /* VectorWithOffset filter_coeff(filter_coefficients.size()); + + 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 +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); + // 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() +SeparableLowPassImageFilter::set_defaults() { - //for ( int i = 0;i<=filter_coefficients.get_length();i++) - filter_coefficients.fill(0); - z_trivial =1; - - + // 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 811283239..eafeebd36 100644 --- a/src/experimental/buildblock/fwd_and_bck_manipulation_for_SAF.cxx +++ b/src/experimental/buildblock/fwd_and_bck_manipulation_for_SAF.cxx @@ -7,141 +7,138 @@ #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) +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);*/ - + /* 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 z = min_z; z <= max_z; ++z) { - 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 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); - 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; + 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); + + 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 z = min_z; z <= max_z; ++z) { - for (int x = min_x; x<= max_x; ++x) - { - if (image[z][y][x] == 0) - continue; - 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) + for (int y = min_y; y <= max_y; ++y) { - 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 x = min_x; x <= max_x; ++x) + { + if (image[z][y][x] == 0) + continue; + 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(); + } + } } - } } - } - } 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 diff --git a/src/experimental/buildblock/local_buildblock_registries.cxx b/src/experimental/buildblock/local_buildblock_registries.cxx index bd02a654b..97d64d714 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 771f52a1b..45d331fe3 100644 --- a/src/experimental/buildblock/local_helping_functions.cxx +++ b/src/experimental/buildblock/local_helping_functions.cxx @@ -5,7 +5,6 @@ See STIR/LICENSE.txt for details */ - #include "stir_experimental/local_helping_functions.h" #include "stir/IndexRange2D.h" #include "stir/info.h" @@ -20,155 +19,146 @@ using std::fstream; using std::cerr; using std::endl; - - 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) +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()); + 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) +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()); + 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) +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); - + // 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; - - array_nom[i] = out1; - array_nom[j] = out2; - i=i+2; - j=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; + + array_nom[i] = out1; + array_nom[j] = out2; + i = i + 2; + j = j + 2; + } } - - -void create_kernel_3d ( Array<3,float>& kernel_3d, const VectorWithOffset < float>& kernel_1d) +void +create_kernel_3d(Array<3, float>& kernel_3d, const VectorWithOffset& kernel_1d) { - if (kernel_3d.get_min_index() ==kernel_3d.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 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]; - } - } - - + 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 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]; + } + } } -void create_kernel_2d ( Array<2, float> & kernel_2d, const VectorWithOffset < float>& kernel_1d) +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++) + 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]; + 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(); @@ -177,192 +167,183 @@ 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 k = start_z; k <= end_z; k++) { - 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 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]; - - } - - out_array[1] = tmp_out_array[1]; - + 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]; + 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()) - { - *iter_1d++ = *iter_3d++; // real part - *iter_1d++ = 0; // imaginary part - } + 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 + } #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()) - { - *iter_3d++ = *iter_1d++; // real part - iter_1d++; // skip imaginary part - } + 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 + } #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) +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()); + + 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++) + // 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++) { - out_array[r] = tmp_out_array[k]; - r +=2; + 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++) + 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)]; + 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) +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]; - } - - - - + 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 e7b2d15c0..e2dec691a 100644 --- a/src/experimental/buildblock/multiply_plane_scale_factorsImageProcessor.cxx +++ b/src/experimental/buildblock/multiply_plane_scale_factorsImageProcessor.cxx @@ -27,113 +27,91 @@ 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())) - { - 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()); - return Succeeded::no; - } + 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()); + return Succeeded::no; + } else - return Succeeded::yes; + return Succeeded::yes; } - template void -multiply_plane_scale_factorsImageProcessor:: -virtual_apply(DiscretisedDensity<3,elemT>& density) const +multiply_plane_scale_factorsImageProcessor::virtual_apply(DiscretisedDensity<3, elemT>& density) const -{ - if (density.get_length()!=static_cast(plane_scale_factors.size())) +{ + 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())] - ); + 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 b658a5b3e..7f5f32bdd 100644 --- a/src/experimental/iterative/OSSPS/line_search.cxx +++ b/src/experimental/iterative/OSSPS/line_search.cxx @@ -14,7 +14,7 @@ \brief disabled implementation of doing a simple line search (from the stir::OSSPSReconstruction class) \author Kris Thielemans - + */ #include "stir/warning.h" @@ -23,25 +23,25 @@ #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) + while (p_iter != p_end) { - accumulate_loglikelihood(*p_iter, *e_iter, /* rim_truncation_sino*/0, accum); - ++p_iter; ++e_iter; + 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) @@ -52,156 +52,146 @@ 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); - - shared_ptr symmetries_sptr = - 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()); - - //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(); + PoissonLogLikelihoodWithLinearModelForMeanAndProjData& objective_function + = static_cast&>(*this->objective_function_sptr); + + shared_ptr symmetries_sptr + = 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()); + + // 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(); // ++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(); + 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_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) + 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; - } - } + 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; } @@ -210,9 +200,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 1cfcdd702..c8afc8851 100644 --- a/src/experimental/listmode/CListModeDataLMF.cxx +++ b/src/experimental/listmode/CListModeDataLMF.cxx @@ -7,7 +7,7 @@ \author Monica Vieira Martins \author Christian Morel \author Kris Thielemans - + */ /* Crystal Clear Collaboration @@ -17,7 +17,6 @@ SPDX-License-Identifier: Apache-2.0 */ - #include "stir_experimental/listmode/CListModeDataLMF.h" #include "stir_experimental/listmode/CListRecordLMF.h" #include "stir/Succeeded.h" @@ -31,68 +30,63 @@ using std::streampos; START_NAMESPACE_STIR -CListModeDataLMF:: -CListModeDataLMF(const string& listmode_filename) - : listmode_filename(listmode_filename) +CListModeDataLMF::CListModeDataLMF(const string& listmode_filename) + : listmode_filename(listmode_filename) { - //opening and reading file.cch, filling in structure LMF_cch + // 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() +CListModeDataLMF::~CListModeDataLMF() { - if(pfCCS) { - fclose(pfCCS); - } + 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); @@ -109,13 +103,12 @@ 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; @@ -124,19 +117,17 @@ 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 7463a4134..5b438f6f1 100644 --- a/src/experimental/listmode/LmToProjDataWithMC.cxx +++ b/src/experimental/listmode/LmToProjDataWithMC.cxx @@ -23,73 +23,68 @@ START_NAMESPACE_STIR -void +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 +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() { return LmToProjData::post_processing(); } -Succeeded LmToProjDataWithMC::set_up() +Succeeded +LmToProjDataWithMC::set_up() { if (is_null_ptr(ro3d_ptr)) - { - error("Invalid Rigid Object 3D Motion object"); - } + { + error("Invalid Rigid Object 3D Motion object"); + } if (reference_position_is_average_position_in_frame) { if (!is_null_ptr(_reference_abs_time_sptr)) - { - error("time interval for reference position is set, but you asked for average over each frame"); - } + { + error("time interval for reference position is set, but you asked for average over each frame"); + } } else { // set transformation_to_reference_position if (is_null_ptr(_reference_abs_time_sptr)) - { - error("time interval for reference position is not set"); - } + { + error("time interval for reference position is not set"); + } { - 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(); } } @@ -107,78 +102,69 @@ Succeeded LmToProjDataWithMC::set_up() } 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) +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)); - + 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 +void LmToProjDataWithMC::get_bin_from_event(Bin& bin, const CListEvent& event) const { - const ProjDataInfoCylindricalNoArcCorr& proj_data_info = - static_cast(*template_proj_data_info_ptr); + const ProjDataInfoCylindricalNoArcCorr& proj_data_info + = 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); + 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); - } + { + // 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); - } + { + 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 54b08d5ab..951d66926 100644 --- a/src/experimental/listmode_utilities/change_lm_time_tags.cxx +++ b/src/experimental/listmode_utilities/change_lm_time_tags.cxx @@ -5,28 +5,28 @@ 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 #include "stir/warning.h" #include "stir/error.h" -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(); @@ -42,38 +42,30 @@ 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) { - std::cerr << "Usage: " << argv[0] - << " \\\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" - "Example arguments:\n" - "\t fixed_H666_lm1 H666_lm1 30000 2\n"; - exit(EXIT_FAILURE); - } + + if (argc != 4 && argc != 5) + { + std::cerr << "Usage: " << argv[0] + << " \\\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" + "Example arguments:\n" + "\t fixed_H666_lm1 H666_lm1 30000 2\n"; + exit(EXIT_FAILURE); + } 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(); @@ -81,56 +73,45 @@ 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(); + 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 (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; - } - } - // 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); + { + 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 - } - return EXIT_SUCCESS; } - - - diff --git a/src/experimental/listmode_utilities/get_singles_info.cxx b/src/experimental/listmode_utilities/get_singles_info.cxx index 0de39b0dc..1b82fdf98 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" #include "stir/error.h" @@ -29,14 +28,11 @@ using std::string; USING_NAMESPACE_STIR - - - -int -main (int argc, char* argv[]) +int +main(int argc, char* argv[]) { - if (argc!=5) + if (argc != 5) { cerr << "Usage: " << argv[0] << " output_filename sgl_filename fdef_filename frame_num\n"; exit(EXIT_FAILURE); @@ -47,45 +43,43 @@ main (int argc, char* argv[]) 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); - if (frame_num < 1 || frame_num > frame_defs.get_num_frames()) { - error("Incorrect frame number\n"); - } + if (frame_num < 1 || frame_num > frame_defs.get_num_frames()) + { + error("Incorrect frame number\n"); + } // open output file std::ofstream output(output_filename.c_str()); - if (!output.good()) { - error("Error opening output file\n"); - } + if (!output.good()) + { + error("Error opening output file\n"); + } // 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 14f0eebc9..883055b17 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 @@ -25,11 +25,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 @@ -37,31 +37,29 @@ 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[]) +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); + + if (argc != 1 && argc != 2) + { + cerr << "Usage: " << argv[0] << " [par_file]\n"; + exit(EXIT_FAILURE); + } + 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 7a638727d..867c2ffba 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" @@ -29,80 +29,78 @@ #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 +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 +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 (par_filename != 0) { - if (parse(par_filename)==false) - exit(EXIT_FAILURE); + if (parse(par_filename) == false) + exit(EXIT_FAILURE); } else ask_parameters(); - } bool -MatchTrackerAndScanner:: -post_processing() +MatchTrackerAndScanner::post_processing() { - if (scan_start_time_secs_since_1970_UTC==-1) + 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)."); + "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 + else { - if (scan_start_time_secs_since_1970_UTC<1000) - { - warning("scan_start_time_secs_since_1970_UTC too small"); - return true; - } + 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) + if (frame_definition_filename.size() == 0) { warning("Have to specify 'time frame_definition_filename'"); return true; @@ -111,60 +109,51 @@ post_processing() frame_defs = TimeFrameDefinitions(frame_definition_filename); if (is_null_ptr(_ro3d_sptr)) - { - warning("Invalid Rigid Object 3D Motion object"); - return true; - } - - - 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) - { - warning("this->relative_threshold has to be between 0 and 1"); - return true; - } - return false; + { + warning("Invalid Rigid Object 3D Motion object"); + return true; + } + 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) + { + 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() +MatchTrackerAndScanner::run() { - std::vector > polaris_points; - std::vector > positions_in_scanner; + 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; { - 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 @@ -186,115 +175,94 @@ run() 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()); - - 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); + 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); + 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; + 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; } } // 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) + 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) + + 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 a17076d9f..c5eba8223 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" @@ -38,18 +38,15 @@ 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 +static Succeeded parse_line(const std::string& deformation_field_from_NCAT_file, - std::istream& ncat_file, - CartesianCoordinate3D& current_voxel, - CartesianCoordinate3D& current_displacement) + std::istream& ncat_file, + CartesianCoordinate3D& current_voxel, + CartesianCoordinate3D& current_displacement) { std::string line; std::getline(ncat_file, line); @@ -58,26 +55,28 @@ parse_line(const std::string& deformation_field_from_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"); + 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()) + 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); + 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; @@ -85,51 +84,56 @@ parse_line(const std::string& deformation_field_from_NCAT_file, #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()) + 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); + 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); + 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) + 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()); + 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; + 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) @@ -153,55 +157,46 @@ set_deformation_field_from_NCAT_file(DeformationFieldOnCartesianGrid<3,float>& d 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; - } + 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; + 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, +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_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)); + 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()); + 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); @@ -211,8 +206,7 @@ set_deformation_field_from_file(DeformationFieldOnCartesianGrid<3,float>& deform origin = image_sptr->get_origin(); grid_spacing = voxels_ptr->get_grid_spacing(); - image_sptr = - read_from_file >(deformation_field_from_file_y); + 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()); @@ -220,8 +214,7 @@ set_deformation_field_from_file(DeformationFieldOnCartesianGrid<3,float>& deform } deformation_field[2] = *image_sptr; - image_sptr = - read_from_file >(deformation_field_from_file_x); + 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()); @@ -232,54 +225,49 @@ set_deformation_field_from_file(DeformationFieldOnCartesianGrid<3,float>& deform return Succeeded::yes; } -static -Succeeded -set_deformation_field_from_file(DeformationFieldOnCartesianGrid<3,float>& deformation_field, +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); + // Read the multicomponent image + unique_ptr>> uptr + = read_from_file>>(deformation_field_multicomponent_filename); - const VoxelsOnCartesianGrid > &voxel_coords(*uptr); + 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()); + 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]; + // 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(); + grid_spacing = voxel_coords.get_grid_spacing(); + origin = voxel_coords.get_origin(); return Succeeded::yes; } template void -NonRigidObjectTransformationUsingBSplines:: -set_defaults() +NonRigidObjectTransformationUsingBSplines::set_defaults() { - this->deformation_field_sptr.reset(new DeformationFieldOnCartesianGrid); + 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); @@ -299,80 +287,77 @@ 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_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) + { + if (this->_deformation_field_from_file_z.size() == 0) { - warning("NonRigidObjectTransformationUsingBSplines:\n" - "you need to set either deformation_field, " - "deformation_field_from_NCAT_file or deformation multicomponent filename"); - return true; + 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_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_x, + this->_deformation_field_from_file_y, this->_deformation_field_from_file_z) - == Succeeded::no) - return true; - } - - } + == 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; - } + { + 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 @@ -380,99 +365,95 @@ 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) +NonRigidObjectTransformationUsingBSplines::NonRigidObjectTransformationUsingBSplines( + const std::string& filename_x, const std::string& filename_y, const std::string& filename_z, const int bspline_order) { - this->set_defaults(); + 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) +NonRigidObjectTransformationUsingBSplines::NonRigidObjectTransformationUsingBSplines( + const std::string& filename, const int bspline_order) { - this->set_defaults(); + 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->_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(); + 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) + 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; + 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)); + 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 4453c06ea..f7e3ea02f 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" @@ -36,93 +35,81 @@ #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); @@ -130,18 +117,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]); @@ -164,181 +151,157 @@ 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; } - + { + warning("You need to specify an input file"); + return true; + } + this->_gated_proj_data_sptr = GatedProjData::read_from_file(this->_input_filename); - // image stuff + // 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; } + { + 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; + } if (this->_additive_projection_data_filename != "0") - { - this->_gated_additive_proj_data_sptr = - GatedProjData::read_from_file(this->_additive_projection_data_filename); - }; + { + 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 + else { // make a single frame starting from 0 to 1. - std::vector > frame_times(1, std::pair(0,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 +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) - ); + 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->already_set_up = false; 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->already_set_up = this->already_set_up && (this->max_timing_pos_num_to_process == 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->already_set_up = this->already_set_up && (this->zero_seg0_end_planes == 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->already_set_up = false; 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->already_set_up = false; + this->already_set_up = false; this->projector_pair_ptr = arg; - } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_frame_num(const int arg) +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_frame_num(const int arg) { this->already_set_up = this->already_set_up && (this->frame_num == arg); this->frame_num = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_frame_definitions(const TimeFrameDefinitions& arg) +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_frame_definitions( + const TimeFrameDefinitions& arg) { this->already_set_up = this->already_set_up && (this->frame_defs == arg); this->frame_defs = arg; @@ -347,40 +310,36 @@ set_frame_definitions(const TimeFrameDefinitions& arg) /*************************************************************** set_up() ***************************************************************/ -template -Succeeded -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_up_before_sensitivity(shared_ptr const& target_sptr) +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()); + 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 == -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); + 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); - + 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; } + { + 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 { @@ -388,88 +347,61 @@ 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; + 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) + 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) - ); + 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)); + 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); + 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); - } + { + 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_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); + 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 @@ -484,12 +416,11 @@ 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 @@ -504,20 +435,18 @@ 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); + iter->compute_sub_gradient_without_penalty_plus_sensitivity(gradient, current_estimate, subset_num); } ++iter; if (iter == end_iter) @@ -528,51 +457,39 @@ compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, while (iter != end_iter) { - iter->compute_sub_gradient_without_penalty_plus_sensitivity(*gradient_this_function_sptr, - current_estimate, - subset_num); + 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(); + 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->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 333afbab2..de9a5f43c 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 @@ -21,29 +21,27 @@ #include using std::ifstream; - -START_NAMESPACE_STIR +START_NAMESPACE_STIR 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()) ; - } - - const unsigned int MAX_STRING_LENGTH=512; + { + error("Polaris_MT_File: error opening file %s - Does it Exist?", mt_filename.c_str()); + } + + const unsigned int MAX_STRING_LENGTH = 512; char DataStr[MAX_STRING_LENGTH]; /* Read opening line */ - if ( !mt_stream.getline( DataStr, MAX_STRING_LENGTH) ) + if (!mt_stream.getline(DataStr, MAX_STRING_LENGTH)) { - error("Polaris_MT_File: error reading Line 1 of file %s", - mt_filename.c_str()); + 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) + if (strncmp(DataStr, "Collection Data", 14) == 0) { // Output of NDI Toolviewer // format of first line @@ -53,200 +51,196 @@ Polaris_MT_File::Polaris_MT_File(const std::string& mt_filename) else { // it's of the following format - //23/5/2003 18:18:32 - 11 1 966_IRSL_II + // 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) +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; + 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)) + 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); - } + 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); - } + { + 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) +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; + 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); - + mt_stream.getline(DataStr, MAX_STRING_LENGTH); - Record record; - while (!mt_stream.eof() && - 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); - } + 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); + } else - { - warning("\nPolaris_MT_File: skipping (as I cannot decode) the following line:\n" - "'%s'\n", - DataStr); - } + { + 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() +Polaris_MT_File::get_start_time_in_secs_since_1970() { - return start_time_in_secs_since_1970; + return start_time_in_secs_since_1970; } -Polaris_MT_File::Record +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/RigidObject3DMotion.cxx b/src/experimental/motion/RigidObject3DMotion.cxx index 6e2f6325d..738b2f84d 100644 --- a/src/experimental/motion/RigidObject3DMotion.cxx +++ b/src/experimental/motion/RigidObject3DMotion.cxx @@ -24,17 +24,15 @@ START_NAMESPACE_STIR - - -void +void RigidObject3DMotion::set_defaults() -{ - //time_offset=time_not_yet_determined; +{ + // time_offset=time_not_yet_determined; } -void +void RigidObject3DMotion::initialise_keymap() -{ +{ #if 0 parser.add_key("reference_quaternion", &reference_quaternion); parser.add_key("reference_translation", &reference_translation); @@ -42,8 +40,7 @@ RigidObject3DMotion::initialise_keymap() } bool -RigidObject3DMotion:: -post_processing() +RigidObject3DMotion::post_processing() { if (!is_synchronised()) @@ -86,40 +83,30 @@ 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 +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())); + 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 +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()); + 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 +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()); + 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 +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()); + return compose(this->get_motion_in_tracker_coords_rel_time(time), this->get_transformation_from_scanner_coords()); } #if 0 @@ -142,7 +129,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 cff4d3840..3388e1187 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" @@ -34,33 +34,36 @@ #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 template -static inline -void +static inline void push_back(VectorWithOffset& v, const T& elem) { - if (v.capacity()==v.size()) - v.reserve(v.capacity()*2); + if (v.capacity() == v.size()) + v.reserve(v.capacity() * 2); - v.resize(v.size()+1); - v[v.size()-1] = elem; + 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. @@ -80,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 \c RigidObject3DTransformation uses (0,z,y,x) + while \c 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 \c RigidObject3DTransformation: \code Quaternion(q0,qZ,qY,qX) = Quaternion(q0,qz,qx,qy) @@ -93,8 +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. @@ -107,422 +109,384 @@ 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(); - } -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 +double +RigidObject3DMotionFromPolaris::rel_time_to_polaris_time(const double time) const { - return time*time_drift + time_offset; + return time * time_drift + time_offset; } -double -RigidObject3DMotionFromPolaris:: -polaris_time_to_rel_time(const double time) const +double +RigidObject3DMotionFromPolaris::polaris_time_to_rel_time(const double time) const { - return (time - time_offset)/time_drift; + 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) - { - result.push_back(this->polaris_time_to_rel_time(iter->sample_time)); - ++iter; - } + 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()) - { - /* Accept motions recorded during time interval */ - if ((iter->sample_time >= start_time ) && ( iter->sample_time<= end_time)) + Polaris_MT_File::const_iterator iter = mt_file_ptr->begin(); + + while (iter != mt_file_ptr->end()) { - 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; - /* Maintain running total quaternions and translations */ - total_t += trans; - total_q += quater; - samples += 1; + /* 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(); + // 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; + /* Maintain running total quaternions and translations */ + total_t += trans; + total_q += quater; + samples += 1; + } + ++iter; } - ++iter; - } /* Average quat and translation */ - - if (samples==0) + + 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); + "\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) + + 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 +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)); + 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 +RigidObject3DTransformation +RigidObject3DMotionFromPolaris::get_motion_in_tracker_coords_rel_time(const double time) const { - const double polaris_time = - rel_time_to_polaris_time(time); + 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() && - iterator_for_record_just_after_this_time->sample_time < polaris_time) + 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()) - { - error("RigidObject3DMotionFromPolaris: motion asked for time %g which is " - "beyond the range of data (time in Polaris units: %g)\n", - time, polaris_time); - // statement to avoid compiler warning - return RigidObject3DTransformation(); - } + { + error("RigidObject3DMotionFromPolaris: motion asked for time %g which is " + "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); - } - + { + 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 ) - { - // check if tags match from current position - 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; - - unsigned long int num_matched_tags = 1; - start_MT_time_of_matching_sequence = (double)iterator_for_random_num->sample_time; - - mt_match_times.resize(0); - lm_match_times.resize(0); - push_back(mt_match_times, (double)start_MT_time_of_matching_sequence); - 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) + for (long int mt_offset = 0; mt_offset + num_lm_tags <= num_mt_tags; ++mt_offset) { - // 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"; - 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'; - } - } // end of fit - - 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; - } - } - return; + // check if tags match from current position + 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; + + unsigned long int num_matched_tags = 1; + start_MT_time_of_matching_sequence = (double)iterator_for_random_num->sample_time; + + mt_match_times.resize(0); + lm_match_times.resize(0); + push_back(mt_match_times, (double)start_MT_time_of_matching_sequence); + 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) + { + // 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"; + 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'; + } + } // end of fit + + 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; + } + } + 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)) + 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; + 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 << "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 << "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 +Succeeded RigidObject3DMotionFromPolaris::synchronise() { if (this->list_mode_filename.size() == 0) @@ -531,298 +495,272 @@ RigidObject3DMotionFromPolaris::synchronise() 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)); + 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()); } - { // 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 (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()); - } - } - + // 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) + 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); + "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)) + 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 ; + 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; + 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; - } + { + 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); + 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); + "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) + 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) + 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); + "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; + 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) +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; - - + + 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); + + 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 + unsigned long CurrentTime = 0; + if (listmode_data.get_next_record(record) == Succeeded::no) + { + break; // get out of while loop + } + 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; + } + } + more_events -= 1; } - 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 ; - } - } - 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 +bool +RigidObject3DMotionFromPolaris::is_synchronised() const { - return time_offset!=time_not_yet_determined; -} + return time_offset != time_not_yet_determined; +} -void +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 +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() +bool +RigidObject3DMotionFromPolaris::post_processing() { if (set_mt_file(mt_filename) == Succeeded::no) { @@ -830,8 +768,8 @@ bool RigidObject3DMotionFromPolaris::post_processing() 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()) @@ -855,102 +793,97 @@ bool RigidObject3DMotionFromPolaris::post_processing() move_from_scanner_coords = RigidObject3DTransformation(quat, trans); #else - { - std::string conventions; - std::string transformation_as_string; - 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; - } - 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) { - std::ostringstream s; - - 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; - } - } + std::string conventions; + std::string transformation_as_string; + 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; + } + 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) + { + std::ostringstream s; + + 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); - } + cerr << "'Move_from_scanner' quaternion " << move_from_scanner_coords.get_quaternion() << endl; + cerr << "'Move_from_Scanner' translation " << move_from_scanner_coords.get_translation() << endl; + this->set_transformation_from_scanner_coords(move_from_scanner_coords); + } - if (norm(this->move_from_scanner_coords.get_translation() - invalid_translation)<1) + 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?"); + 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) + if (max_time_drift_deviation < 0 || max_time_drift_deviation > .9) { - warning("Polaris: Invalid max_time_drift_deviation %g", max_time_drift_deviation); + 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) + if (max_time_offset_deviation < 0 || max_time_offset_deviation > 100000) { - warning("Polaris: Invalid max_time_offset_deviation %g", max_time_offset_deviation); + 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 2f68b492f..35c8f6b6a 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 @@ -28,7 +28,7 @@ #include #include #ifndef NEW_ROT -#include "stir/ProjDataInfoCylindricalNoArcCorr.h" +# include "stir/ProjDataInfoCylindricalNoArcCorr.h" #endif using std::cerr; @@ -36,55 +36,58 @@ 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,54 +96,53 @@ RigidObject3DTransformation::registered_name = "rigid"; The rest of the code is written independent of the convention used. */ #if 1 -static inline -Quaternion +static inline Quaternion point2quat(const CartesianCoordinate3D& p) -{ return Quaternion(0,p.z(),p.y(),p.x());} +{ + return Quaternion(0, p.z(), p.y(), p.x()); +} -static inline -CartesianCoordinate3D +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]); +{ + 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 +static inline Quaternion point2quat(const CartesianCoordinate3D& p) -{ return Quaternion(0,p.x(),p.y(),p.z());} -static inline -CartesianCoordinate3D +{ + 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]); +{ + 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 RigidObject3DTransformation::inverse() const { #ifdef FIRSTROT @@ -148,40 +150,40 @@ RigidObject3DTransformation::inverse() const 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 +CartesianCoordinate3D RigidObject3DTransformation::get_translation() const { return translation; @@ -200,94 +202,89 @@ 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 -#else // for rotational matrix +# 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 // 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,32 +293,28 @@ 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"); @@ -329,13 +322,12 @@ RigidObject3DTransformation::get_relative_transformation(RigidObject3DTransforma // 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,53 +438,37 @@ 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) +operator<<(std::ostream& out, const RigidObject3DTransformation& rigid_object_transformation) { - out << '{' - << rigid_object_transformation.get_quaternion() - << ',' - << rigid_object_transformation.get_translation() - << "}"; + 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); + in.setstate(std::ios::failbit); return in; } Quaternion q; @@ -500,7 +476,7 @@ operator>>(std::istream& in, in >> std::ws >> c; if (!in || c != ',') { - in.setstate( std::ios::failbit); + in.setstate(std::ios::failbit); return in; } CartesianCoordinate3D t; @@ -508,165 +484,139 @@ operator>>(std::istream& in, in >> std::ws >> c; if (!in || c != '}') { - in.setstate( std::ios::failbit); + in.setstate(std::ios::failbit); return in; } - rigid_object_transformation = RigidObject3DTransformation(q,t); + rigid_object_transformation = RigidObject3DTransformation(q, t); return in; } - /****************** find_closest_transformation **************/ 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; - } - - 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); - } + ++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; +} + +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) + 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); + 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) + max_eigenvector, + horn_matrix, + start, + /* tolerance*/ .0005, + /*max_num_iterations*/ 10000UL) == Succeeded::no) { warning("find_closest_transformation failed because power method did not converge"); @@ -676,56 +626,41 @@ find_closest_transformation(RigidObject3DTransformation& result, 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 f4a8494a0..5d30daf3b 100644 --- a/src/experimental/motion/TimeFrameMotion.cxx +++ b/src/experimental/motion/TimeFrameMotion.cxx @@ -18,28 +18,27 @@ START_NAMESPACE_STIR -void +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 +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); } /* @@ -50,7 +49,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(); @@ -58,35 +57,34 @@ TimeFrameMotion(const char * const par_filename) } */ bool -TimeFrameMotion:: -post_processing() +TimeFrameMotion::post_processing() { - if (_scan_start_time_secs_since_1970_UTC==-1) + 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)."); + "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 + else { - if (_scan_start_time_secs_since_1970_UTC<1000) - { - warning("scan_start_time_secs_since_1970_UTC too small"); - return true; - } + 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) + if (_frame_definition_filename.size() == 0) { warning("Have to specify 'time frame_definition_filename'\n"); return true; @@ -95,17 +93,15 @@ post_processing() _frame_defs = TimeFrameDefinitions(_frame_definition_filename); if (is_null_ptr(_ro3d_sptr)) - { - warning("Invalid Rigid Object 3D Motion object\n"); - return true; - } + { + 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())) + 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()); + warning("Frame number should be between 1 and %d\n", _frame_defs.get_num_frames()); return true; } @@ -115,63 +111,51 @@ post_processing() 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); + { + 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) +void +TimeFrameMotion::move_to_reference(const bool value) { - _do_move_to_reference=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) +TimeFrameMotion::set_frame_num_to_process(const int value) { - _frame_num_to_process=value; - if (_frame_num_to_process==-1) + _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 2ac573955..bbb79597d 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 */ @@ -24,62 +24,56 @@ #include "stir/error.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) + 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; - } - } + { + 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 @@ -94,8 +88,7 @@ post_processing() } template -Transform3DObjectImageProcessor:: -Transform3DObjectImageProcessor(const shared_ptr > transf) +Transform3DObjectImageProcessor::Transform3DObjectImageProcessor(const shared_ptr> transf) { set_defaults(); this->transformation_sptr = transf; @@ -103,27 +96,21 @@ Transform3DObjectImageProcessor(const shared_ptr > template Succeeded -Transform3DObjectImageProcessor:: -virtual_set_up(const DiscretisedDensity<3,elemT>& density) +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); - } + 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); - } + { + 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()); } @@ -132,184 +119,159 @@ virtual_set_up(const DiscretisedDensity<3,elemT>& density) this->_transformed_coords.recycle(); this->_transformed_coords_and_jacobian.recycle(); } - return Succeeded::yes; + 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); + { + 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]); - } - } + 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]); - } - } + { + 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); + 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 ); + 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 cb7565824..c4edc8acc 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 fdf1a4861..e2cb9d096 100644 --- a/src/experimental/motion/transform_3d_object.cxx +++ b/src/experimental/motion/transform_3d_object.cxx @@ -30,101 +30,87 @@ #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) +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 + 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) +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 + 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>> +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); + 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); - 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; - } + 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); + 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; + } 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>> +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); + 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); - 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); - } + 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); + 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); + } return transformed_centre_coords; } @@ -132,47 +118,41 @@ find_grid_coords_of_transformed_centres_and_jacobian(const DiscretisedDensity<3, // transform ProjData Succeeded 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) { 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()); + 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) + 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) + 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(); @@ -180,21 +160,15 @@ 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); +# 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(); @@ -202,75 +176,56 @@ transform_3d_object(ProjData& out_proj_data, 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 - - } + 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) - { + 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; + 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); + + 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(); @@ -278,40 +233,34 @@ transform_3d_object(ProjData& out_proj_data, 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 - ); + 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 (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::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 2fc107d16..ee9c13a3b 100644 --- a/src/experimental/motion_test/test_BSpline_transformations.cxx +++ b/src/experimental/motion_test/test_BSpline_transformations.cxx @@ -33,7 +33,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 @@ -49,13 +49,11 @@ 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; @@ -63,111 +61,115 @@ 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) +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; + if (_to_transform.empty()) + everything_ok = false; + if (_disp_4D.empty()) + everything_ok = false; + _bspline_order = 1; } void -TestBSplineTransformation:: -run_transformation() +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 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; + // 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)); + 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()); + // 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 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); + 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"); + // 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."); + // 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. + // 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() +TestBSplineTransformation::run_tests() { - try { - cerr << "Tests for TransformationTests\n"; - this->run_transformation(); + try + { + cerr << "Tests for TransformationTests\n"; + this->run_transformation(); } - catch(...) { - 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 != 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; + 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 9525ee379..117be6188 100644 --- a/src/experimental/motion_utilities/add_planes_to_image.cxx +++ b/src/experimental/motion_utilities/add_planes_to_image.cxx @@ -15,38 +15,35 @@ 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; - return EXIT_FAILURE; - } + 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); - - 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); + 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); + + 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); 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 718e1f3c4..1d7e9a56e 100644 --- a/src/experimental/motion_utilities/find_motion_corrected_norm_factors.cxx +++ b/src/experimental/motion_utilities/find_motion_corrected_norm_factors.cxx @@ -35,22 +35,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 @@ -63,39 +63,35 @@ 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/. @@ -155,15 +151,13 @@ END:= 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(); @@ -177,27 +171,25 @@ 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 +void FindMCNormFactors::set_defaults() { max_segment_num_to_process = -1; @@ -205,25 +197,25 @@ FindMCNormFactors::set_defaults() _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 +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); @@ -233,84 +225,66 @@ 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 (par_filename != 0) { if (parse(par_filename) == false) - error("Please correct parameter file"); + error("Please correct parameter file"); } else ask_parameters(); - } bool -FindMCNormFactors:: -post_processing() +FindMCNormFactors::post_processing() { - - if (output_filename_prefix.size()==0) + 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) + 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); + 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(); + 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); + 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_cyl_uncompressed_ptr = - dynamic_cast - (proj_data_info_uncompressed_ptr.get()); - + 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()); if (!do_pre_normalisation && is_null_ptr(normalisation_ptr)) { - //normalisation_ptr = new TrivialBinNormalisation; + // 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) + if (!do_pre_normalisation && normalisation_ptr->set_up(proj_data_info_uncompressed_ptr) != Succeeded::yes) { warning("set-up of normalisation failed\n"); return true; @@ -320,34 +294,33 @@ post_processing() do_time_frame = true; - if (do_time_frame && frame_definition_filename.size()==0) + 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)); + 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())) + 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()); + 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 (is_null_ptr(ro3d_ptr)) + { + warning("Invalid Rigid Object 3D Motion object\n"); + return true; + } #if 0 if (!ro3d_ptr->is_synchronised()) @@ -363,18 +336,15 @@ post_processing() 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(); - } + { + 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 +void FindMCNormFactors::process_data() { #ifdef NEW_ROT @@ -386,288 +356,246 @@ 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); + 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) + 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; + 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); + 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); #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 +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) + 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++) - { + + for (int seg = start_segment_index; seg <= end_segment_index; seg++) { + { #ifdef USE_SegmentByView - proj_data.set_segment(*segments[seg]); + proj_data.set_segment(*segments[seg]); #else - write_data(*output, (*segments[seg])); + write_data(*output, (*segments[seg])); #endif - //delete segments[seg]; - segments[seg].reset(); // deallocate for shared_ptr + // delete segments[seg]; + segments[seg].reset(); // deallocate for shared_ptr + } } - - } } - - -static -shared_ptr +static shared_ptr construct_proj_data(shared_ptr& output, - const string& output_filename, + const string& output_filename, const shared_ptr& proj_data_info_ptr) { vector segment_sequence_in_stream(proj_data_info_ptr->get_num_segments()); - { - auto 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(); + { + auto 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[]) +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); + + if (argc != 1 && argc != 2) + { + cerr << "Usage: " << argv[0] << " [par_file]\n"; + exit(EXIT_FAILURE); + } + 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 95b02f4e2..185afcf2b 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. @@ -39,9 +39,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 @@ -49,17 +49,16 @@ START_NAMESPACE_STIR END := \endverbatim -*/ +*/ 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(); @@ -67,42 +66,37 @@ 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 +void MyApp::set_defaults() -{ -} - +{} -void +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 (par_filename != 0) { - if (parse(par_filename)==false) - exit(EXIT_FAILURE); + 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; @@ -116,69 +110,65 @@ post_processing() return false; } - -Succeeded -MyApp:: -process_data() +Succeeded +MyApp::process_data() { - BasicCoordinate<3,float> in_coord; - while(true) + 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; + << 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[]) +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]=='-') + 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; - } + 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); - } + { + warning("Wrong option\n"); + exit(EXIT_FAILURE); + } } - 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"; - exit(EXIT_FAILURE); - } - MyApp application(argc==2 ? argv[1] : 0); - Succeeded success = - application.process_data(); + 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"; + exit(EXIT_FAILURE); + } + 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 0cbd1a76e..31ac85ef2 100644 --- a/src/experimental/motion_utilities/list_polaris_info.cxx +++ b/src/experimental/motion_utilities/list_polaris_info.cxx @@ -21,59 +21,62 @@ USING_NAMESPACE_STIR -static void print_usage_and_exit(const char * const prog_name) +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"; + 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[]) +int +main(int argc, char* argv[]) { - const char * const prog_name = argv[0]; + const char* const prog_name = argv[0]; unsigned int mask_for_tags = 0xfffffff; - while (argc>2 && argv[1][0] == '-') + while (argc > 2 && argv[1][0] == '-') { - if (strcmp(argv[1], "--mask-for-tags")==0) - { - mask_for_tags = atoi(argv[2]); - argc-=2; argv+=2; - } + 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); - } + { + print_usage_and_exit(prog_name); + } } - - if (argc!=2) { - print_usage_and_exit(prog_name); - } - const char * const polaris_filename = argv[1]; + if (argc != 2) + { + print_usage_and_exit(prog_name); + } + 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) + 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; + << "\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 f806df621..0b5a60bc9 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,22 @@ \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) { - cerr << "Usage: " << argv[0] << " \\\n" - << "\t[par_file]\n"; - exit(EXIT_FAILURE); - } - stir::MatchTrackerAndScanner application(argc==2 ? argv[1] : 0); + if (argc != 1 && argc != 2) + { + cerr << "Usage: " << argv[0] << " \\\n" + << "\t[par_file]\n"; + exit(EXIT_FAILURE); + } + 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 2d15cc82a..1355c435a 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. @@ -41,9 +41,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 @@ -62,20 +62,18 @@ START_NAMESPACE_STIR END := \endverbatim -*/ +*/ 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(); @@ -84,165 +82,145 @@ 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 +void MoveImage::set_defaults() { base_type::set_defaults(); - output_file_format_sptr = - OutputFileFormat >::default_sptr(); + output_file_format_sptr = OutputFileFormat>::default_sptr(); } -void +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 (par_filename != 0) { - if (parse(par_filename)==false) - exit(EXIT_FAILURE); + 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) + 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); + in_density_sptr = read_from_file>(input_filename); return false; } - -Succeeded -MoveImage:: -process_data() +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 max_frame_num = - 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) + shared_ptr> 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 max_frame_num + = 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); + 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()); - + 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[]) +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]=='-') + 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; - } + 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); - } + { + warning("Wrong option\n"); + exit(EXIT_FAILURE); + } } - 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"; - exit(EXIT_FAILURE); - } - MoveImage application(argc==2 ? argv[1] : 0); + 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"; + exit(EXIT_FAILURE); + } + 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 5c36c1f85..89bde20f0 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. @@ -39,9 +39,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 @@ -58,19 +58,18 @@ START_NAMESPACE_STIR END := \endverbatim -*/ +*/ 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(); @@ -85,180 +84,161 @@ 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 +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 +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 (par_filename != 0) { - if (parse(par_filename)==false) - exit(EXIT_FAILURE); + 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) + 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) + 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(); + 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(); + 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 (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 max_frame_num = - 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 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(); + + 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); { - 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)); + 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'; + 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; + 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[]) +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]=='-') + 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; - } + 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); - } + { + warning("Wrong option\n"); + exit(EXIT_FAILURE); + } } - 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"; - exit(EXIT_FAILURE); - } - MoveProjData application(argc==2 ? argv[1] : 0); + 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"; + exit(EXIT_FAILURE); + } + 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 84b6c0d51..69a04e93a 100644 --- a/src/experimental/motion_utilities/non_rigid_transform.cxx +++ b/src/experimental/motion_utilities/non_rigid_transform.cxx @@ -16,10 +16,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:= @@ -43,86 +44,95 @@ #include "stir_experimental/motion/NonRigidObjectTransformationUsingBSplines.h" #include "stir_experimental/motion/Transform3DObjectImageProcessor.h" -int main(int argc, char *argv[]) +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; + 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]; + 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(); + 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 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; - } -} + } + 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 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/experimental/motion_utilities/remove_corrupted_sinograms.cxx b/src/experimental/motion_utilities/remove_corrupted_sinograms.cxx index 38a2b4965..2a36677de 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,229 +51,197 @@ 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++) + 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 ++; + 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; + 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_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++; + { + 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; + 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; + 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++; + { + 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; - } + 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) + 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; + 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; + ++axial_pos_to_remove_min; } - - } int 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; - return EXIT_FAILURE; - } + + 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; + 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)); + 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) + 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 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); + 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; @@ -285,30 +252,23 @@ main(int argc, char* argv[]) 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; - - - + 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 07c65fad3..fb60f647d 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. @@ -45,44 +45,44 @@ 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 { 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 +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 +void ReportMovement::initialise_keymap() { parser.add_start_key("ReportMovement Parameters"); @@ -95,23 +95,20 @@ 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 (par_filename != 0) { - if (parse(par_filename)==false) - exit(EXIT_FAILURE); + 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; @@ -119,10 +116,8 @@ post_processing() return false; } - -Succeeded -ReportMovement:: -process_data() +Succeeded +ReportMovement::process_data() { std::string filename_all = this->output_filename_prefix + "_all.log"; @@ -132,13 +127,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 max_frame_num = - this->get_frame_num_to_process()==-1 - ? this->get_time_frame_defs().get_num_frames() - : 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(); double MSE_within_frame_all_frames = 0; double MSE_from_ref_all_frames = 0; @@ -146,136 +137,117 @@ 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); + 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; + // cerr << "\nDoing frame " << current_frame_num + // << ": from " << start_time << " to " << end_time << endl; - //set_frame_num_to_process(current_frame_num); + // 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)); + 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 + 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'; + << 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'; - + 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[]) +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]=='-') + 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; - } + 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); - } + { + warning("Wrong option\n"); + exit(EXIT_FAILURE); + } } - 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"; - exit(EXIT_FAILURE); - } - ReportMovement application(argc==2 ? argv[1] : 0); + 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"; + exit(EXIT_FAILURE); + } + 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 f741da38c..744a348e2 100644 --- a/src/experimental/motion_utilities/rigid_object_transform_image.cxx +++ b/src/experimental/motion_utilities/rigid_object_transform_image.cxx @@ -5,7 +5,8 @@ Internal GE use only. */ -namespace stir { // for doxygen +namespace stir +{ // for doxygen /*! \file \ingroup motion_utilities @@ -15,9 +16,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 +50,6 @@ using std::endl; START_NAMESPACE_STIR - #if 0 class TF @@ -81,89 +81,87 @@ class TF END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) +int +main(int argc, char** argv) { - const char * const program_name = argv[0]; + 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] == '-') { - do_origin_shift = false; - argc-=1; argv+=1; + 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) + { + do_origin_shift = false; + 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"; + << 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()); + 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)); + 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; } @@ -176,28 +174,25 @@ int main(int argc, char **argv) { 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 + 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 + 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"); @@ -207,8 +202,7 @@ int main(int argc, char **argv) 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 03b1f2ec1..0fddc3d0a 100644 --- a/src/experimental/motion_utilities/rigid_object_transform_projdata.cxx +++ b/src/experimental/motion_utilities/rigid_object_transform_projdata.cxx @@ -2,7 +2,8 @@ Copyright (C) 2003 - 2012-01-06, Hammersmith Imanet Ltd See STIR/LICENSE.txt for details */ -namespace stir { // for doxygen +namespace stir +{ // for doxygen /*! \file \ingroup motion_utilities @@ -13,8 +14,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 +23,7 @@ namespace stir { // for doxygen \author Kris Thielemans */ -} // END_NAMESPACE_STIR +} // namespace stir #include "stir/ProjDataInterfile.h" #include "stir/Succeeded.h" @@ -36,99 +37,94 @@ namespace stir { // for doxygen USING_NAMESPACE_STIR - -int main(int argc, char **argv) +int +main(int argc, char** argv) { - const char * const program_name = argv[0]; + 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] == '-') { - do_origin_shift = false; - argc-=1; argv+=1; + if (strcmp(argv[0], "--no_origin_shift") == 0) + { + do_origin_shift = false; + 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"; + << 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; + 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) + 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]); + 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(); + 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(); + 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); - ProjDataInterfile out_projdata(in_projdata_sptr->get_exam_info_sptr(), proj_data_info_ptr, output_filename, std::ios::out); + 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)); + 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 d9f793885..bad234cd6 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,65 @@ USING_NAMESPACE_STIR -static void print_usage_and_exit(const char * const prog_name) +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"; + 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[]) +int +main(int argc, char* argv[]) { - const char * const prog_name = argv[0]; + 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] == '-') + 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; - } + 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); - } + { + print_usage_and_exit(prog_name); + } } - - if (argc!=3) { - print_usage_and_exit(prog_name); - } - const char * const polaris_filename = argv[1]; - const char * const list_mode_filename = argv[2]; + if (argc != 3) + { + print_usage_and_exit(prog_name); + } + 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 3f0f4bb06..0c41b8ad9 100644 --- a/src/experimental/recon_buildblock/BinNormalisationFromML2D.cxx +++ b/src/experimental/recon_buildblock/BinNormalisationFromML2D.cxx @@ -16,7 +16,6 @@ \author Kris Thielemans */ - #include "stir_experimental/recon_buildblock/BinNormalisationFromML2D.h" #include "stir/RelatedViewgrams.h" #include "stir/ViewSegmentNumbers.h" @@ -31,24 +30,21 @@ START_NAMESPACE_STIR -const char * const -BinNormalisationFromML2D::registered_name = "From ML2D"; - +const char* const BinNormalisationFromML2D::registered_name = "From ML2D"; -void +void BinNormalisationFromML2D::set_defaults() { - normalisation_filename_prefix=""; + 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); @@ -60,37 +56,29 @@ initialise_keymap() parser.add_stop_key("End Bin Normalisation From ML2D"); } -bool -BinNormalisationFromML2D:: -post_processing() +bool +BinNormalisationFromML2D::post_processing() { return false; } -BinNormalisationFromML2D:: -BinNormalisationFromML2D() +BinNormalisationFromML2D::BinNormalisationFromML2D() { set_defaults(); } -Succeeded -BinNormalisationFromML2D:: -set_up(const shared_ptr& proj_data_info_ptr) +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(); + 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; @@ -101,98 +89,92 @@ set_up(const shared_ptr& proj_data_info_ptr) // 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; - } - - delete[] normalisation_filename; - } - // geo norm + { + 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 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 + { + { + 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; - } - } + { + { + 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); + 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); } } - - 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()); - } - - -END_NAMESPACE_STIR +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 3ad7da1c1..4f03071b5 100644 --- a/src/experimental/recon_buildblock/BinNormalisationSinogramRescaling.cxx +++ b/src/experimental/recon_buildblock/BinNormalisationSinogramRescaling.cxx @@ -13,7 +13,6 @@ See STIR/LICENSE.txt for details */ - #include "stir_experimental/recon_buildblock/BinNormalisationSinogramRescaling.h" #include "stir/shared_ptr.h" #include "stir/RelatedViewgrams.h" @@ -30,31 +29,27 @@ using std::ifstream; START_NAMESPACE_STIR +const char* const BinNormalisationSinogramRescaling::registered_name = "Sinogram Rescaling"; -const char * const -BinNormalisationSinogramRescaling::registered_name = "Sinogram Rescaling"; - -void +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() +bool +BinNormalisationSinogramRescaling::post_processing() { - if (sinogram_rescaling_factors_filename.size()==0) - { + if (sinogram_rescaling_factors_filename.size() == 0) + { warning("You have to specify sinogram rescaling filename\n"); return true; } @@ -62,116 +57,101 @@ post_processing() return false; } - -BinNormalisationSinogramRescaling:: -BinNormalisationSinogramRescaling() +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) +BinNormalisationSinogramRescaling::set_up(const shared_ptr& proj_data_info_sptr_v) { - proj_data_info_sptr = 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()); + 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; + 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) + 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); + 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(); - } + 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()); + 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 +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); - } + { + 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 3ee718243..192a29db2 100644 --- a/src/experimental/recon_buildblock/BinNormalisationUsingProfile.cxx +++ b/src/experimental/recon_buildblock/BinNormalisationUsingProfile.cxx @@ -13,7 +13,6 @@ See STIR/LICENSE.txt for details */ - #include "stir_experimental/recon_buildblock/BinNormalisationUsingProfile.h" #include "stir/RelatedViewgrams.h" #include "stir/stream.h" @@ -22,25 +21,24 @@ 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); @@ -50,7 +48,7 @@ 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) { @@ -60,48 +58,38 @@ post_processing() return false; } - -BinNormalisationUsingProfile:: -BinNormalisationUsingProfile() +BinNormalisationUsingProfile::BinNormalisationUsingProfile() { set_defaults(); } -BinNormalisationUsingProfile:: -BinNormalisationUsingProfile(const string& filename) - : profile_filename(filename) +BinNormalisationUsingProfile::BinNormalisationUsingProfile(const string& filename) + : profile_filename(filename) { - if (post_processing()==true) + if (post_processing() == true) error("Exiting\n"); } -void -BinNormalisationUsingProfile:: -apply(RelatedViewgrams& viewgrams,const double start_time, const double end_time) const +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) + 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; - } + 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(); @@ -117,24 +105,17 @@ 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) + 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]; - } + 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 6ba7c9609..945ee5807 100644 --- a/src/experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.cxx +++ b/src/experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.cxx @@ -2,17 +2,17 @@ // /* Copyright (C) 2000 PARAPET partners - Copyright (C) 2000- 2007, Hammersmith Imanet Ltd - This file is part of STIR. - + Copyright (C) 2000- 2007, Hammersmith Imanet Ltd + This file is part of STIR. + SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license - + 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 @@ -32,16 +32,16 @@ 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 +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(); @@ -50,186 +50,162 @@ 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; - - 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"); - - } - - 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; - } + "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"); + } + + 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; + } } -/*! 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) +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) + 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 " "z-direction of the origin (which is %g) should be a multiple of the plane " "separation (%g)\n", - image_info_ptr->get_origin().z(), cartesian_grid_info_ptr->get_grid_spacing()[1]); + 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"); + "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()); + 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) + 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 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); + 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(); + 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"); - } + { + 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 +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)); + 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 53cf7d9c2..425c9483a 100644 --- a/src/experimental/recon_buildblock/ParametricQuadraticPrior.cxx +++ b/src/experimental/recon_buildblock/ParametricQuadraticPrior.cxx @@ -11,8 +11,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 @@ -27,12 +27,12 @@ START_NAMESPACE_STIR template -void +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); @@ -40,35 +40,36 @@ ParametricQuadraticPrior::initialise_keymap() } template -bool +bool ParametricQuadraticPrior::post_processing() { - if (base_type::post_processing()==true) + 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) + 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?? + 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); @@ -76,7 +77,8 @@ ParametricQuadraticPrior::set_up (shared_ptr -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); @@ -88,102 +90,103 @@ 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); + // 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) + 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); + 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) + 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]; + ++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); + // This works only for ParametricVoxelsOnCartesianGrid and maybe for other ecat7 format files. + write_to_file(filename, prior_gradient); delete[] filename; } } @@ -208,52 +211,49 @@ 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) + 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); + 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) + 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; + 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); + 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 46c8208b3..c38f6c616 100644 --- a/src/experimental/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData.cxx +++ b/src/experimental/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData.cxx @@ -30,137 +30,135 @@ #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; } - + { + 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 + // 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; } + { + warning("zoom should be positive"); + 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 (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; + } + + 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 @@ -174,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), @@ -190,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 @@ -387,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 30706492b..0c27c11dd 100644 --- a/src/experimental/recon_buildblock/PostsmoothingForwardProjectorByBin.cxx +++ b/src/experimental/recon_buildblock/PostsmoothingForwardProjectorByBin.cxx @@ -24,14 +24,10 @@ 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); @@ -39,12 +35,11 @@ set_defaults() 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"); @@ -56,169 +51,153 @@ initialise_keymap() } bool -PostsmoothingForwardProjectorByBin:: -post_processing() +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; - 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++]); - } - } - 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++]); - } - } + { + 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; + 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++]); + } + } + 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++]); + } + } return false; } -PostsmoothingForwardProjectorByBin:: - PostsmoothingForwardProjectorByBin() +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) +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); - } - + 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) +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); - } + // 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 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 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) - { - 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]; - } - } - } + 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]; + } + } + } } - - END_NAMESPACE_STIR diff --git a/src/experimental/recon_buildblock/ProjMatrixByBinSinglePhoton.cxx b/src/experimental/recon_buildblock/ProjMatrixByBinSinglePhoton.cxx index 97320eb16..fb8ea2023 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" @@ -28,18 +26,14 @@ START_NAMESPACE_STIR +const char* const ProjMatrixByBinSinglePhoton::registered_name = "Single Photon"; -const char * const -ProjMatrixByBinSinglePhoton::registered_name = - "Single Photon"; - -ProjMatrixByBinSinglePhoton:: -ProjMatrixByBinSinglePhoton() +ProjMatrixByBinSinglePhoton::ProjMatrixByBinSinglePhoton() { set_defaults(); } -void +void ProjMatrixByBinSinglePhoton::initialise_keymap() { ProjMatrixByBin::initialise_keymap(); @@ -47,74 +41,60 @@ ProjMatrixByBinSinglePhoton::initialise_keymap() parser.add_stop_key("End Single Photon Matrix Parameters"); } - void ProjMatrixByBinSinglePhoton::set_defaults() { ProjMatrixByBin::set_defaults(); } - void -ProjMatrixByBinSinglePhoton:: -set_up( - const shared_ptr& proj_data_info_ptr_v, - const shared_ptr >& density_info_ptr - ) +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) + 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(); + 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)); + 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 d87cbf878..d46189e07 100644 --- a/src/experimental/recon_buildblock/ProjMatrixByBinUsingSolidAngle.cxx +++ b/src/experimental/recon_buildblock/ProjMatrixByBinUsingSolidAngle.cxx @@ -16,8 +16,6 @@ */ - - #include "stir_experimental/recon_buildblock/ProjMatrixByBinUsingSolidAngle.h" #include "stir/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.h" #include "stir/VoxelsOnCartesianGrid.h" @@ -29,18 +27,14 @@ START_NAMESPACE_STIR +const char* const ProjMatrixByBinUsingSolidAngle::registered_name = "Solid Angle"; -const char * const -ProjMatrixByBinUsingSolidAngle::registered_name = - "Solid Angle"; - -ProjMatrixByBinUsingSolidAngle:: -ProjMatrixByBinUsingSolidAngle() +ProjMatrixByBinUsingSolidAngle::ProjMatrixByBinUsingSolidAngle() { set_defaults(); } -void +void ProjMatrixByBinUsingSolidAngle::initialise_keymap() { ProjMatrixByBin::initialise_keymap(); @@ -48,111 +42,90 @@ ProjMatrixByBinUsingSolidAngle::initialise_keymap() parser.add_stop_key("End Solid Angle Matrix Parameters"); } - void ProjMatrixByBinUsingSolidAngle::set_defaults() { ProjMatrixByBin::set_defaults(); } - void -ProjMatrixByBinUsingSolidAngle:: -set_up( - const shared_ptr& proj_data_info_ptr_v, - const shared_ptr >& density_info_ptr - ) +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()); + 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) +inline int +sign(const float x) { - return x>0 ? 1 : -1; + 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) +inline T +cube(const T x) { - return x*x*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) +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)); + 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) + @@ -160,208 +133,180 @@ 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) +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); + 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) +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); + 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) +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); + 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) +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); + 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 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 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 + 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; + 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 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); + 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; - } + 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)); - } + s_voxel_onpreviousRow += tphi; + + } while (square(X) + square(Y) < square(fovrad)); + } #if 0 // now add on other LORs @@ -382,10 +327,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 79d3885f7..baece04ab 100644 --- a/src/experimental/recon_buildblock/ProjMatrixByBinWithPositronRange.cxx +++ b/src/experimental/recon_buildblock/ProjMatrixByBinWithPositronRange.cxx @@ -16,8 +16,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,20 @@ START_NAMESPACE_STIR +const char* const ProjMatrixByBinWithPositronRange::registered_name = "With Positron Range"; -const char * const -ProjMatrixByBinWithPositronRange::registered_name = - "With Positron Range"; - -ProjMatrixByBinWithPositronRange:: -ProjMatrixByBinWithPositronRange() +ProjMatrixByBinWithPositronRange::ProjMatrixByBinWithPositronRange() { set_defaults(); } -void +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,17 +51,16 @@ ProjMatrixByBinWithPositronRange::initialise_keymap() parser.add_stop_key("End With Positron Range Matrix Parameters"); } - void 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 @@ -76,33 +68,33 @@ 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); + 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) - { + 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) - { + 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; } @@ -110,52 +102,34 @@ ProjMatrixByBinWithPositronRange::post_processing() } void -ProjMatrixByBinWithPositronRange:: -set_up( - const shared_ptr& proj_data_info_ptr_v, - const shared_ptr >& density_info_ptr - ) +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()); + 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 @@ -170,14 +144,10 @@ 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) + 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 3bf3201b1..a01303d27 100644 --- a/src/experimental/recon_buildblock/ProjMatrixByDensel.cxx +++ b/src/experimental/recon_buildblock/ProjMatrixByDensel.cxx @@ -4,11 +4,11 @@ \file \ingroup recon_buildblock - - \brief implementation of the stir::ProjMatrixByDensel class - + + \brief implementation of the stir::ProjMatrixByDensel class + \author Kris Thielemans - + */ /* Copyright (C) 2000- 2004, Hammersmith Imanet Ltd @@ -16,60 +16,48 @@ See STIR/LICENSE.txt for details */ - #include "stir_experimental/recon_buildblock/ProjMatrixByDensel.h" #include "stir/recon_buildblock/ProjMatrixElemsForOneDensel.h" #include "stir/Succeeded.h" - START_NAMESPACE_STIR ProjMatrixByDensel::ProjMatrixByDensel() -{ - cache_disabled=false; +{ + cache_disabled = false; } - -Succeeded -ProjMatrixByDensel:: -get_cached_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probabilities) const - - - -{ - if ( cache_disabled ) + +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 @@ -120,8 +108,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 9a0a88f87..650d4197c 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" @@ -25,42 +24,35 @@ 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); @@ -70,237 +62,229 @@ 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) - { + { - 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 - // 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_min_ax_pos = min_ax_pos; - int previous_inc_min_ax_pos = -1; + 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 + // 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_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) - { - 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) + for (int view = proj_data_info_ptr->get_min_view_num(); view <= proj_data_info_ptr->get_max_view_num(); ++view) { - if (tang_posget_min_tangential_pos_num()) - { - tang_pos_inc = 1; - 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) - { - // 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 - // << '(' << 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); - probs.push_back(ProjMatrixElemsForOneDensel::value_type(bin)); - } - } - } - else // the Pbv was zero - { - if (tang_pos_inc==-1) - { - tang_pos_inc=1; - } - else + 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_pos < min_ax_pos) + { + ax_pos_inc = 1; + ax_pos = min_ax_pos; + continue; + } + // else + + bool found_nonzero_tangential = false; + int start_tang_pos = previous_min_tang_pos + previous_inc_min_tang_pos; + + // check if the increment wasn't too large (or not negative enough): + // do this by looping until the current bin gives 0 +#if 1 + // std::cerr << "Start at tang_pos " << start_tang_pos + // << " (" << seg << ',' << view << ',' << ax_pos << ')'<< std::endl; + Bin bin(seg, view, ax_pos, 0); + int tang_pos_inc = -1; + 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(); + continue; + } + // else + + bin.tangential_pos_num() = tang_pos; + 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 + // << '(' << 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); + probs.push_back(ProjMatrixElemsForOneDensel::value_type(bin)); + } + } + } + else // the Pbv was zero + { + 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) - { - // the first tang_pos where the result is zero again. So, all the next ones will be 0 as well. - break; - } + { + 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) + { + previous_min_ax_pos = ax_pos; + found_nonzero_axial = true; + } + } + } + else // all bins for this ax_pos were zero + { + if (ax_pos_inc == -1) + { + ax_pos_inc = 1; + } + 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 + // ax_pos loop to miss to non-zero bins. See above + } + } } - } - } // end loop over tang_pos - 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) - { - previous_min_ax_pos = ax_pos; - found_nonzero_axial = true; - } - } - } - else // all bins for this ax_pos were zero - { - if (ax_pos_inc==-1) - { - ax_pos_inc = 1; - } - 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 - // ax_pos loop to miss to non-zero bins. See above - } - } - - } - + #else - 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(); - break; - } - 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 - break; - } - } - 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 - // << " (" << 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 - // << '(' << seg << ',' << view << ',' << ax_pos << ')'<< std::endl; - //XXXprevious_min_tang_pos = tang_pos; + 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(); + break; + } + 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 + break; + } + } + 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 + // << " (" << 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 + // << '(' << seg << ',' << view << ',' << ax_pos << ')'<< std::endl; + // XXXprevious_min_tang_pos = tang_pos; + } + found_nonzero_tangential = true; + bin.set_bin_value(LOI); + probs.push_back(ProjMatrixElemsForOneDensel::value_type(bin)); + } + 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; + } + } // end loop over tang_pos + 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 + // 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 + // loop here to the left of the start_tang_pos; + } + } + else + { + // if (found_nonzero_tangential) + // std::cerr << "first ax_pos at " << ax_pos + // << '(' << seg << ',' << view << ')' << std::endl; + found_nonzero_axial = found_nonzero_tangential; + } } - found_nonzero_tangential = true; - bin.set_bin_value(LOI); - probs.push_back(ProjMatrixElemsForOneDensel::value_type(bin)); - } - 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; - } - } // end loop over tang_pos - 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 - // 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 - // loop here to the left of the start_tang_pos; - } - } - 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 - // this would only be true if only voxels in a restricted cylindrical FOV would be used. - // assert(found_nonzero_axial); + // next assert only possible when every voxel is detected at least once in every seg,view + // this would only be true if only voxels in a restricted cylindrical FOV would be used. + // assert(found_nonzero_axial); + } } - } - #if 0 @@ -392,4 +376,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 03511c909..97f8d4dd6 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,94 @@ using std::min; START_NAMESPACE_STIR +const char* const ProjMatrixByDenselUsingRayTracing::registered_name = "Ray Tracing"; -const char * const -ProjMatrixByDenselUsingRayTracing::registered_name = - "Ray Tracing"; - -ProjMatrixByDenselUsingRayTracing:: -ProjMatrixByDenselUsingRayTracing() +ProjMatrixByDenselUsingRayTracing::ProjMatrixByDenselUsingRayTracing() { set_defaults(); } -void +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; + // 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) - // return true; - if (num_tangential_LORs<1) - { - warning("ProjMatrixByDenselUsingRayTracing: num_tangential_LORs should be at least 1, but is %d\n", - num_tangential_LORs); - return true; - } + // 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); + return true; + } return false; } const DataSymmetriesForDensels* -ProjMatrixByDenselUsingRayTracing:: get_symmetries_ptr() const +ProjMatrixByDenselUsingRayTracing::get_symmetries_ptr() const { - return symmetries_ptr.get(); + 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(); + 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; + { + 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; }; #if 0 @@ -153,87 +135,111 @@ 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 +250,13 @@ 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); @@ -266,91 +270,72 @@ file. A bit of a mistery that. */ if (!use_actual_detector_boundaries) - { - phi = proj_data_info_ptr->get_phi(bin); - //s_in_mm = proj_data_info_ptr->get_s(bin); - } + { + phi = proj_data_info_ptr->get_phi(bin); + // 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); - // 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); - } + { + // can be static_cast later on + const ProjDataInfoCylindricalNoArcCorr& proj_data_info_noarccor + = 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); + } // 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); - } + { + 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; - 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) { - 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) - { - // 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 + // 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; + 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) + { + 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) + { + // 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 #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 f7edd0818..3872beacf 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 1e294a851..a4943cbf6 100644 --- a/src/experimental/recon_test/fwdtestDensel.cxx +++ b/src/experimental/recon_test/fwdtestDensel.cxx @@ -11,7 +11,7 @@ This program allows forward projection of a few segments/views - only, or of the full data set. + only, or of the full data set. Usage: \verbatim @@ -20,7 +20,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- 2003, IRSL @@ -43,362 +43,297 @@ #include "stir/error.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(); - } - 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 = 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()); 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); + 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()); - } + { + 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: + switch (ask_num("Start image is cuboid (1) or cylinder (2) or on file (3)", 1, 3, 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_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; + 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()); + // display(*image_sptr, image_sptr->find_max()); } - 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 { - cerr << "Saving start image to 'test_image'" << endl; - write_basic_interfile("test_image", *image_sptr); - } - - -// 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, +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 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 z = min_z; z <= max_z; ++z) { - for (int x = min_x; x<= max_x; ++x) - { - if (image[z][y][x] == 0) - continue; - 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) + // std::cerr << "z "<< z<< std::endl; + for (int y = min_y; y <= max_y; ++y) { - 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 x = min_x; x <= max_x; ++x) + { + if (image[z][y][x] == 0) + continue; + 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 (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"); - delete all_segments[segment_num]; - } + { + if (!(proj_data.set_segment(*all_segments[segment_num]) == Succeeded::yes)) + error("Error set_segment\n"); + delete all_segments[segment_num]; + } } - - -void fill_cuboid(VoxelsOnCartesianGrid& image) +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 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) +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.); - + 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++) + 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); + 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); } - - for (int z=image.get_min_z(); z<=image.get_max_z(); z++) + + 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; + 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 9cede71e4..e40566f56 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 @@ -36,11 +36,10 @@ using std::cerr; START_NAMESPACE_STIR template -bool -coordinates_less(const BasicCoordinate<3,T>& el1, const BasicCoordinate<3,T>& el2) +bool +coordinates_less(const BasicCoordinate<3, T>& el1, const BasicCoordinate<3, T>& el2) { - return el1[1]& el1, const BasicCoordinate<3,T>& el 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); + 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)); @@ -102,538 +98,453 @@ 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 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 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 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 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 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_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 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) +ProjMatrixByBinUsingInterpolationTests::run_tests_for_1_projdata(const shared_ptr& proj_data_info_sptr) { - CartesianCoordinate3D origin (0,0,0); - const float zoom=1.F; + 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) + 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())); + 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() -{ +{ cerr << "Tests for ProjMatrixByBinUsingInterpolation\n"; 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=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=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(); + 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) +int +main(int argc, char** argv) { - ProjMatrixByBinUsingInterpolationTests tests(argc==2? argv[1] : 0); + 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 eb0c0504b..79d1386f5 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,346 @@ 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) +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 i) { - std::swap(data[j],data[i]); - std::swap(data[j+1],data[i+1]); - } - m=n >> 1; - while (m >= 2 && j > m) { - j -= m; - m >>= 1; + 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]); + } + m = n >> 1; + while (m >= 2 && j > m) + { + j -= m; + m >>= 1; + } + j += m; } - j += m; - } - 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 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 < mmax; m += 2) + { + for (i = m; i <= n; i += istep) + { + j = i + mmax; + tempr = wr * data[j] - wi * data[j + 1]; + tempi = wr * data[j + 1] + wi * data[j]; + data[j] = data[i] - tempr; + data[j + 1] = data[i + 1] - tempi; + data[i] += tempr; + data[i + 1] += tempi; + } + wr = (wtemp = wr) * wpr - wi * wpi + wr; + wi = wi * wpr + wtemp * wpi + wi; + } + mmax = istep; } - mmax=istep; - } } - -inline float rand1() +inline float +rand1() { - return 2*(rand()-RAND_MAX/2.F)/RAND_MAX; + return 2 * (rand() - RAND_MAX / 2.F) / RAND_MAX; } END_NAMESPACE_STIR using namespace stir; -int main() +int +main() { cout << "Sign: "; int sign; cin >> 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; + 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; - } + { + 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 9fab56972..536aa6c5a 100644 --- a/src/experimental/test/test_LmToProjdataWithMC.cxx +++ b/src/experimental/test/test_LmToProjdataWithMC.cxx @@ -21,71 +21,64 @@ using std::cerr; using std::endl; - START_NAMESPACE_STIR -class LmToProjDataWithMCTests: public RunTests +class LmToProjDataWithMCTests : public RunTests { -public: +public: void run_tests(); }; - - - void LmToProjDataWithMCTests::run_tests() { - const char * const par_filename = "test.par"; + 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 b7efaf4fb..8ff4addea 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" @@ -18,190 +18,189 @@ using std::cerr; using std::endl; - START_NAMESPACE_STIR /*! \ingroup test \brief Test class for Quaternion */ -class QuaternionTests: public RunTests +class QuaternionTests : public RunTests { -public: +public: void run_tests(); }; - void 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(); diff --git a/src/experimental/test/test_RigidObject3DTransformation.cxx b/src/experimental/test/test_RigidObject3DTransformation.cxx index e51d2b1dc..8d1a1d3eb 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,37 @@ #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 +class RigidObject3DTransformationTests : public RunTests { -public: +public: void run_tests(); + private: void test_transform_bin(); void test_transform_bin_with_inverse(const ProjDataInfo& proj_data_info, const bool is_uncompressed); @@ -89,51 +92,47 @@ RigidObject3DTransformationTests::run_tests() 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 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 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"); + } + // 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"); + } } - // 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"); - - } - } } #if 0 @@ -180,58 +179,50 @@ 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(); + timer.start(); #endif - const CartesianCoordinate3D transformed_point_3 = - 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); + const CartesianCoordinate3D transformed_point_3 + = 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); #ifdef DO_TIMINGS - compose_timer.stop(); + 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 = - 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); + 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); #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()); + 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 @@ -358,159 +345,130 @@ static Coordinate4D 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 +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])))); + 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) +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 << "\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 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 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(); - const CartesianCoordinate3D voxel_size = - dynamic_cast const&>(*density_sptr).get_grid_spacing(); + 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(); // 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,100 +480,82 @@ 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 CartesianCoordinate3D image_centre = - CartesianCoordinate3D((density_sptr->get_min_index()+density_sptr->get_max_index())/2.F,0,0) - * 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; 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) + 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; - } + { + 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); - } + 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); + 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(deviationfind_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_orgfind_max()); + if (!check(deviation < allowed_deviation, "deviation determined via backprojection")) { - std::cerr << "\t\tdeviation of pixel with LOR after transformations (in mm): " << max_deviation_transformed << '\n'; + 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"; @@ -623,59 +563,53 @@ test_find_closest_transformation() 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")) + 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'; + 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 8e9b557b9..f877e30e4 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,80 @@ using std::endl; #include "stir/geometry/line_distances.h" int -main(int argc,char *argv[]) +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"; - 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 = - 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); - - 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; + USING_NAMESPACE_STIR + + 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 + = 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); + + 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; #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,45 +121,46 @@ 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; - const DetectionPositionPair<> det_pos_pair_0(DetectionPosition<>(det1_0, ring1_0), DetectionPosition<>(det2_0, ring2_0)); - proj_data_cyl_no_arc_ptr->get_bin_for_det_pos_pair(bin_check_0, det_pos_pair_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; - const DetectionPositionPair<> det_pos_pair_90(DetectionPosition<>(det1_90, ring1_90), DetectionPosition<>(det2_90, ring2_90)); - proj_data_cyl_no_arc_ptr->get_bin_for_det_pos_pair(bin_check_90, det_pos_pair_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; + const DetectionPositionPair<> det_pos_pair_0(DetectionPosition<>(det1_0, ring1_0), DetectionPosition<>(det2_0, ring2_0)); + proj_data_cyl_no_arc_ptr->get_bin_for_det_pos_pair(bin_check_0, det_pos_pair_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; + const DetectionPositionPair<> det_pos_pair_90(DetectionPosition<>(det1_90, ring1_90), + DetectionPosition<>(det2_90, ring2_90)); + proj_data_cyl_no_arc_ptr->get_bin_for_det_pos_pair(bin_check_90, det_pos_pair_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); - - 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, - 0); // set timing_pos_num=0 as test-code is pre-TOF + 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, + 0); // set timing_pos_num=0 as test-code is pre-TOF #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/Bland_Altman_plot.cxx b/src/experimental/utilities/Bland_Altman_plot.cxx index b311b8a7b..0183f1ae3 100644 --- a/src/experimental/utilities/Bland_Altman_plot.cxx +++ b/src/experimental/utilities/Bland_Altman_plot.cxx @@ -8,23 +8,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. */ @@ -40,131 +40,127 @@ #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) +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 "; + 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) + ofstream output_stream(name.c_str(), ios::out); // output file // + if (!output_stream) { - std::cerr << "Cannot open " << name << endl ; + 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; + 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) + 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()) + 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); + 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()); + 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"; } { @@ -107,20 +102,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 \"" - <= 3 && argv[1][0] == '-') { if (strcmp(argv[1], "--2d") == 0) - { - is_3d_scan = false; - --argc; ++argv; - } + { + is_3d_scan = false; + --argc; + ++argv; + } else if (strcmp(argv[1], "--3d") == 0) - { - is_3d_scan = true; - --argc; ++argv; - } + { + is_3d_scan = true; + --argc; + ++argv; + } else - print_usage_and_exit(program_name); + print_usage_and_exit(program_name); } - if(argc!=4) + 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) { - 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); + 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); + } - 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 + 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)) + char buffer[512]; + int success = EXIT_SUCCESS; + while (!feof(sgl_fptr)) { - size_t num_read = - fread(buffer, 1, 512, 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; - } + { + 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 1f2837da8..f37d2fa7d 100644 --- a/src/experimental/utilities/add_side_shields.cxx +++ b/src/experimental/utilities/add_side_shields.cxx @@ -27,117 +27,87 @@ #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) { - cerr << "Usage: " << argv[0] << " output_filename input_filename\n"; - exit(EXIT_FAILURE); - } + 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; - - 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 = - // 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 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 = + // make_coord(old_index_to_new, -new_max_xy, -new_max_xy); + // 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); 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); @@ -153,15 +123,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 3d1aa77e3..48d1c263c 100644 --- a/src/experimental/utilities/add_time_frame_info.cxx +++ b/src/experimental/utilities/add_time_frame_info.cxx @@ -34,31 +34,31 @@ using std::ifstream; using std::istream; using std::setw; -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 719cd13e2..fa4ed5139 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 @@ -33,24 +33,24 @@ using std::vector; USING_NAMESPACE_STIR - -int main(int argc, char **argv) +int +main(int argc, char** argv) { - if(argc!=4) { - cerr<<"Usage: " << argv[0] << " \n"; - exit(EXIT_FAILURE); - } - + 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]; + + // read image - shared_ptr > density_ptr - (read_from_file >(input_filename)); + shared_ptr> density_ptr(read_from_file>(input_filename)); // read factors vector rescale_factors; @@ -58,27 +58,22 @@ int main(int argc, char **argv) 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); - } + { + 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 13c2e3254..461151296 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" #include "stir/warning.h" @@ -24,26 +23,23 @@ 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 8a8ed9b0f..b4b22302d 100644 --- a/src/experimental/utilities/compute_gradient.cxx +++ b/src/experimental/utilities/compute_gradient.cxx @@ -10,10 +10,10 @@ */ /*! - \file + \file \ingroup utilities - - \brief + + \brief \author Kris Thielemans @@ -78,49 +78,44 @@ 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 8083fd27b..1bd0cd7e5 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). @@ -30,52 +30,49 @@ using std::ofstream; USING_NAMESPACE_STIR -int main(int argc, char **argv) +int +main(int argc, char** argv) { - if(argc!=3) { - cerr<<"Usage: " << argv[0] << " \n"; - exit(EXIT_FAILURE); - } - + 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) - { - rescale_factors[z] = (*density_ptr)[z].sum(); - } + 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) { - 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); - rescale_factors[z] = 10000.F; + 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); + rescale_factors[z] = 10000.F; + } + else + rescale_factors[z] = 1 / rescale_factors[z]; } - else - rescale_factors[z] = 1/rescale_factors[z]; - } // write to file { @@ -84,9 +81,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 e3ea791b8..f2110e66a 100644 --- a/src/experimental/utilities/create_normfactors.cxx +++ b/src/experimental/utilities/create_normfactors.cxx @@ -35,32 +35,31 @@ using std::string; USING_NAMESPACE_STIR -int main(int argc, char **argv) +int +main(int argc, char** argv) { - if (argc!=4) + 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"; + 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); @@ -68,78 +67,70 @@ int main(int argc, char **argv) ++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; + // 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); + 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; - } - } - } + { + 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; + } + } + } } return EXIT_SUCCESS; diff --git a/src/experimental/utilities/create_normfactors3D.cxx b/src/experimental/utilities/create_normfactors3D.cxx index 310e63262..2810eea31 100644 --- a/src/experimental/utilities/create_normfactors3D.cxx +++ b/src/experimental/utilities/create_normfactors3D.cxx @@ -37,81 +37,72 @@ using std::string; USING_NAMESPACE_STIR -int main(int argc, char **argv) +int +main(int argc, char** argv) { - if (argc!=4) + 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"; + 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 e317bb3c2..ada819fca 100644 --- a/src/experimental/utilities/fillwith1.cxx +++ b/src/experimental/utilities/fillwith1.cxx @@ -14,40 +14,31 @@ */ - #include "stir/ProjData.h" #include "stir/SegmentByView.h" #include "stir/Succeeded.h" #include "stir/error.h" -#include +#include +USING_NAMESPACE_STIR +int +main(int argc, char* argv[]) +{ -USING_NAMESPACE_STIR + 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); -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) + 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); + 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]); + 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 9d37ee3e5..85ddd7a67 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,13 +16,12 @@ See STIR/LICENSE.txt for details */ - #include "stir/ProjData.h" #include "stir/SegmentByView.h" #include "stir/Succeeded.h" #include "stir/error.h" -#include +#include #include using std::cerr; @@ -30,43 +30,38 @@ using std::fstream; using std::ifstream; using std::cout; - 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[]) +{ - 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()) + 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"); } - for (int segment_num=out_projdata_ptr->get_min_segment_num(); - segment_num<=out_projdata_ptr->get_max_segment_num(); + 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; - } + 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 98c6cf735..0058e2186 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" @@ -31,25 +30,23 @@ using std::cerr; using std::endl; using std::ofstream; - int -main( int argc, char* argv[]) +main(int argc, char* argv[]) { USING_NAMESPACE_STIR; - if ( argc !=4) + 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()) + 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; @@ -61,91 +58,76 @@ 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) + 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()); - } + 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 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; - } - - } - + 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) + if (!outfile) { warning("Error opening output file %d\n", scaling_factors_filename.c_str()); return EXIT_FAILURE; } outfile << scaling_factors; - if(!outfile) + 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 704abbaf7..83745f979 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 @@ -34,21 +34,19 @@ using std::max; using std::string; 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"; + 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()); + 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"); @@ -57,62 +55,61 @@ main(int argc, char *argv[]) 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) + 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 + 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); @@ -123,30 +120,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 68ecbbc95..78bf28297 100644 --- a/src/experimental/utilities/image_flip_x.cxx +++ b/src/experimental/utilities/image_flip_x.cxx @@ -24,69 +24,60 @@ #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) - { - case 'i': - input_filename = optarg; - break; - case 'o': - output_filename = 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:")) != -1) + switch (c) + { + case 'i': + input_filename = optarg; + break; + case 'o': + output_filename = 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) + if (output_filename == 0 || input_filename == 0) { - std::cerr << usage; - return EXIT_FAILURE; + 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 (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 (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; + + Succeeded success + = 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 bf2f98d39..2a89db7b5 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 @@ -38,172 +38,149 @@ using std::min; using std::max; 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) { - for (int other_det=0; other_det det_pos_pair(DetectionPosition<>(det, ring), DetectionPosition<>(other_det, other_ring)); - const Succeeded success = - proj_data_info.get_bin_for_det_pos_pair(bin, det_pos_pair); - if (success == Succeeded::yes) - list_of_bins_in_block.push_back(bin); - } + const int det = tang_crystal + tang_det_offset; + const int ring = ax_crystal + ax_det_offset; + { + for (int other_det = 0; other_det < num_detectors_per_ring; ++other_det) + for (int other_ring = max(0, ring + min_ring_diff); other_ring <= min(num_rings - 1, ring + max_ring_diff); + ++other_ring) + { + // first check for impossible coincidence (because it cannot be handled by get_bin_for_det_pos_pair) + if (det == other_det) + continue; + + const DetectionPositionPair<> det_pos_pair(DetectionPosition<>(det, ring), + DetectionPosition<>(other_det, other_ring)); + const Succeeded success = proj_data_info.get_bin_for_det_pos_pair(bin, det_pos_pair); + if (success == Succeeded::yes) + list_of_bins_in_block.push_back(bin); + } + } } - } } - -bool +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) +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" + << 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"; + << "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]); + 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()); + 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); + { + 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)); - + { + 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); - 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) + 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) { - 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; + 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() || - 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; + { + 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 < 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; #if 0 cerr << "s "<< segment_num << " v " << view_num @@ -212,26 +189,18 @@ int main(int argc, char **argv) << " lt " << last_tang_pos_num << 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); - } - out_projdata.set_viewgram(viewgram); - } + 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); + } + out_projdata.set_viewgram(viewgram); + } return EXIT_SUCCESS; } diff --git a/src/experimental/utilities/interpolate_projdata.cxx b/src/experimental/utilities/interpolate_projdata.cxx index e4b567e1f..a086b8550 100644 --- a/src/experimental/utilities/interpolate_projdata.cxx +++ b/src/experimental/utilities/interpolate_projdata.cxx @@ -2,8 +2,8 @@ // /* Copyright (C) 2005- 2012, Hammersmith Imanet Ltd - SPDX-License-Identifier: Apache-2.0 - + SPDX-License-Identifier: Apache-2.0 + See STIR/LICENSE.txt for details */ /*! @@ -13,21 +13,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" @@ -41,57 +41,57 @@ using namespace stir; using namespace stir::BSpline; -/***********************************************************/ +/***********************************************************/ + +int +main(int argc, const char* argv[]) +{ -int main(int argc, const char *argv[]) -{ - - if (argc< 4 || argc>9) + 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(); - + 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"); - if (interpolate_projdata(proj_data_out, *proj_data_in_sptr, these_types, remove_interleaving, use_view_offset) == - Succeeded::yes) + 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 3481bc392..c22adab38 100644 --- a/src/experimental/utilities/inverse_SSRB.cxx +++ b/src/experimental/utilities/inverse_SSRB.cxx @@ -2,8 +2,8 @@ // /* Copyright (C) 2005- 2007, Hammersmith Imanet Ltd - SPDX-License-Identifier: Apache-2.0 - + SPDX-License-Identifier: Apache-2.0 + See STIR/LICENSE.txt for details */ /*! @@ -13,16 +13,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" @@ -36,34 +36,33 @@ using std::cout; using std::cerr; 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 782ad7825..50b97ceb7 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 @@ -46,137 +45,121 @@ using std::iostream; using std::list; using std::find; - 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); + 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; - } - } + { + 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; + } + } 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 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); - } - + 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) - { - cerr << " USAGE: Inverse_proj_data: input projdata filename, output projdata (extension .s) " << endl; - return(EXIT_FAILURE); - } - else - { - proj_data_ptr = ProjData::read_from_file(argv[1]); - } - const ProjDataInfo * proj_data_info_ptr = - proj_data_ptr->get_proj_data_info_sptr(); + if (argc != 3) + { + cerr << " USAGE: Inverse_proj_data: input projdata filename, output projdata (extension .s) " << endl; + return (EXIT_FAILURE); + } + else + { + proj_data_ptr = ProjData::read_from_file(argv[1]); + } - 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 63e983cf9..e8b5850d5 100644 --- a/src/experimental/utilities/line_profiles_through_projdata.cxx +++ b/src/experimental/utilities/line_profiles_through_projdata.cxx @@ -20,7 +20,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 @@ -33,11 +33,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. */ @@ -46,8 +46,8 @@ #include "stir/ProjData.h" #include "stir/ProjDataInfo.h" #include "stir/Bin.h" -#include -#include +#include +#include #include using std::iostream; using std::ofstream; @@ -58,22 +58,22 @@ using std::endl; using std::cout; using std::setw; -int main(int argc, char *argv[]) -{ +int +main(int argc, char* argv[]) +{ USING_NAMESPACE_STIR - using namespace std; - if (argc!=9) + 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(); + << "\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]); @@ -84,13 +84,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= @@ -99,67 +99,66 @@ 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(); + 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(); + 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 d94e524b7..a1678c18b 100644 --- a/src/experimental/utilities/list_TAC_ROI_values.cxx +++ b/src/experimental/utilities/list_TAC_ROI_values.cxx @@ -17,7 +17,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 | @@ -51,8 +51,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" @@ -73,9 +73,8 @@ using std::cerr; using std::endl; using std::ofstream; - START_NAMESPACE_STIR -//TODO repetition of postfilter.cxx to be able to use its .par file +// TODO repetition of postfilter.cxx to be able to use its .par file class ROIValuesParameters : public KeyParser { public: @@ -83,16 +82,15 @@ class ROIValuesParameters : public KeyParser 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() @@ -101,10 +99,10 @@ ROIValuesParameters::ROIValuesParameters() initialise_keymap(); } -void ROIValuesParameters:: -increment_current_shape_num() +void +ROIValuesParameters::increment_current_shape_num() { - if (!is_null_ptr( current_shape_sptr)) + if (!is_null_ptr(current_shape_sptr)) { shape_ptrs.push_back(current_shape_sptr); shape_names.push_back(current_shape_name); @@ -113,9 +111,8 @@ increment_current_shape_num() } } -void -ROIValuesParameters:: -set_defaults() +void +ROIValuesParameters::set_defaults() { shape_ptrs.resize(0); shape_names.resize(0); @@ -123,46 +120,43 @@ set_defaults() 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)) + if (!is_null_ptr(current_shape_sptr)) { increment_current_shape_num(); } - if (num_samples.z()<=0) + 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) + 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) + if (num_samples.x() <= 0) { warning("number of samples to take in x-direction should be strictly positive\n"); return true; @@ -175,112 +169,103 @@ END_NAMESPACE_STIR USING_NAMESPACE_STIR int -main(int argc, char *argv[]) +main(int argc, char* argv[]) { - bool do_CV=false; - bool do_V=false; - const char * const progname = argv[0]; + bool do_CV = false; + bool do_V = false; + const char* const progname = argv[0]; - if (argc>1 && strcmp(argv[1],"--CV")==0) + if (argc > 1 && strcmp(argv[1], "--CV") == 0) { - do_CV=true; - --argc; ++argv; + do_CV = true; + --argc; + ++argv; } - if (argc>1 && strcmp(argv[1],"--V")==0) + if (argc > 1 && strcmp(argv[1], "--V") == 0) { - do_V=true; - --argc; ++argv; - if(strcmp(argv[1],"--CV")==0) - { - do_CV=true; - --argc;++argv; - } + 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"; + 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"; + 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." + << endl; + exit(EXIT_FAILURE); } - 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"; - 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 ; + { + warning("Cannot open output file.\n"); + return EXIT_FAILURE; + } + + 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); + 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(); diff --git a/src/experimental/utilities/make_cylinder.cxx b/src/experimental/utilities/make_cylinder.cxx index 5f58ef3bc..2378334aa 100644 --- a/src/experimental/utilities/make_cylinder.cxx +++ b/src/experimental/utilities/make_cylinder.cxx @@ -14,60 +14,52 @@ using std::cerr; using std::endl; - 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"; + 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 @@ -75,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 ea477f68b..3749620b8 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 */ @@ -20,63 +20,57 @@ using std::cerr; USING_NAMESPACE_STIR - -int main(int argc, char **argv) +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); - } - + 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]) + 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(); + 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 31b0d82a0..7e57a3fb1 100644 --- a/src/experimental/utilities/mode.cxx +++ b/src/experimental/utilities/mode.cxx @@ -16,114 +16,113 @@ #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& +ostream& operator<<(ostream& str, const vector& v) { - str << '{'; - for (int i=0; i0) - str << (unsigned int)v[v.size()-1]; - str << '}' << endl; - return str; + 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; - } + { + 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); - } + { + current_modes.push_back(current_elem); + } } - //cerr << "modes " < input_files(argc); - + --argc; + ++argv; + vector input_files(argc); // open input files - while (argc>0) - { - --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; + while (argc > 0) + { + --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,69 +130,67 @@ int main(int argc, char **argv) bool any_error = false; streamsize elem_count = 0; streamsize multiple_count = 0; - while(!all_done) + 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; - } - } + 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; - } + { + 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) - { - --argc; - istrstream s(*argv); - s >> (v[argc]); - argv++; - } + while (argc > 0) + { + --argc; + istrstream s(*argv); + s >> (v[argc]); + argv++; + } cerr << "elements " << v; const vector modes = compute_modes(v); @@ -201,6 +198,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 baed81561..c072221ec 100644 --- a/src/experimental/utilities/normalizedbckproj.cxx +++ b/src/experimental/utilities/normalizedbckproj.cxx @@ -6,24 +6,23 @@ \ingroup utilities \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 @@ -49,200 +47,164 @@ using std::find; using std::cerr; using std::endl; - - START_NAMESPACE_STIR void -do_segments(DiscretisedDensity<3,float>& image, +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) + 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()); - - + + 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; - } - /* - case 2: - { - cerr << endl; - cerr <<"Usage: " << argv[0] << "[proj_data_file] outputfile name\n"; - 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)); - fill = true; - break; - } - */ - default: + switch (argc) { - cerr <<"Usage: " << argv[0] << "proj_data_file outputfile_name\n"; - return (EXIT_FAILURE); + 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: + { + cerr << endl; + cerr <<"Usage: " << argv[0] << "[proj_data_file] outputfile name\n"; + 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)); + fill = true; + break; + } + */ + 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(); + VoxelsOnCartesianGrid* vox_image_ptr = new VoxelsOnCartesianGrid(*proj_data_info_ptr); - bool projector_type = - ask ( " Which projector do you want to use Ray Tracing (Y) or Solid Angle (N) ", true) ; + shared_ptr> image_sptr(vox_image_ptr); + string name; + if (projector_type) + name = "Ray Tracing"; + else + name = "Solid Angle"; - - const ProjDataInfo * proj_data_info_ptr = - proj_data_ptr->get_proj_data_info_sptr(); - - VoxelsOnCartesianGrid * vox_image_ptr = - new VoxelsOnCartesianGrid(*proj_data_info_ptr); - - 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); + + 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); - *image_sptr /= *denominator_ptr; - } + { + 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); + *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); - } + { + // 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 b1baee72e..6c9496ad2 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 */ @@ -53,236 +53,201 @@ using std::find; using std::cerr; using std::endl; - - 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); - 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 ; - 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++) +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++) { - 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); + 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; + 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); + + // 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); + } } void -do_segments(DiscretisedDensity<3,float>& image, +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) + 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(); - - + + 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[]) { - 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); - } + 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) + 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 = 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"; + 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++) + 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); + 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 0c5508a7f..5513b170d 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 @@ -29,7 +29,7 @@ #include "stir/recon_buildblock/TrivialBinNormalisation.h" #include -#include +#include #include #include @@ -42,9 +42,6 @@ using std::string; START_NAMESPACE_STIR - - - /*! \ingroup recon_buildblock \brief A preliminary class to prepare files for iterative reconstruction @@ -58,8 +55,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:= ... @@ -84,15 +81,14 @@ 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 { public: - - PrepareProjData(const char * const par_filename); + PrepareProjData(const char* const par_filename); void doit(); private: @@ -102,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; @@ -121,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(); @@ -131,19 +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(); @@ -162,12 +155,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); @@ -176,26 +168,24 @@ 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(); @@ -204,68 +194,60 @@ PrepareProjData(const char * const par_filename) warning("Invalid normalisation type\n"); exit(EXIT_FAILURE); } - can_make_trues = - prompts_projdata_filename.size()!=0 && - randoms_projdata_filename.size()!=0; + 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) + 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) + 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_prompts = prompts_denominator_projdata_filename.size() != 0; - if (do_prompts && randoms_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)); + "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()) + 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); @@ -277,70 +259,56 @@ 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(); + 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); + 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); + 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)); + 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)); - } + { + 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)); - } + { + prompts_denominator_projdata_ptr.reset( + new ProjDataInterfile(output_data_info_ptr, prompts_denominator_projdata_filename)); + } } - } - - void -PrepareProjData:: -doit() +PrepareProjData::doit() { - shared_ptr symmetries_ptr - (new TrivialDataSymmetriesForViewSegmentNumbers); + shared_ptr symmetries_ptr(new TrivialDataSymmetriesForViewSegmentNumbers); // take these out of the loop to avoid reallocation (but it's ugly) RelatedViewgrams normatten_viewgrams; @@ -351,153 +319,140 @@ 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); - - if (!symmetries_ptr->is_basic(view_seg_num)) - 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); - - { - 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); - - if (!is_null_ptr(normatten_projdata_ptr)) - normatten_projdata_ptr->set_related_viewgrams(normatten_viewgrams); - } - - // ** now compute scatter ** - /*RelatedViewgrams*/ scatter_viewgrams = normatten_viewgrams; - 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); - - 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); - } - - 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; - - { - // 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_viewgrams += randoms_viewgrams; - Shifted_Poisson_numerator_projdata_ptr->set_related_viewgrams(Shifted_Poisson_numerator_viewgrams); - } - { - // denominator of Shifted_Poisson is scatter+ 2*randoms*norm*atten - - randoms_viewgrams *= normatten_viewgrams; - /*RelatedViewgrams*/ Shifted_Poisson_denominator_viewgrams = scatter_viewgrams; - 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 - already_read_randoms = false; - } - - if (do_prompts) - { - if (!already_read_randoms) - { - randoms_viewgrams = - randoms_projdata_ptr->get_related_viewgrams(view_seg_num, symmetries_ptr); - } - + { + 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) { - // denominator of prompts is scatter+ randoms*norm*atten - - randoms_viewgrams *= normatten_viewgrams; - /*RelatedViewgrams*/ prompts_denominator_viewgrams = scatter_viewgrams; - prompts_denominator_viewgrams += randoms_viewgrams; - prompts_denominator_projdata_ptr->set_related_viewgrams(prompts_denominator_viewgrams); + const ViewSegmentNumbers view_seg_num(view_num, segment_num); + + if (!symmetries_ptr->is_basic(view_seg_num)) + 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); + + { + 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); + + if (!is_null_ptr(normatten_projdata_ptr)) + normatten_projdata_ptr->set_related_viewgrams(normatten_viewgrams); + } + + // ** now compute scatter ** + /*RelatedViewgrams*/ scatter_viewgrams = normatten_viewgrams; + 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); + + 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); + } + + 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; + + { + // 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_viewgrams += randoms_viewgrams; + Shifted_Poisson_numerator_projdata_ptr->set_related_viewgrams(Shifted_Poisson_numerator_viewgrams); + } + { + // denominator of Shifted_Poisson is scatter+ 2*randoms*norm*atten + + randoms_viewgrams *= normatten_viewgrams; + /*RelatedViewgrams*/ Shifted_Poisson_denominator_viewgrams = scatter_viewgrams; + 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 + already_read_randoms = false; + } + + 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 + + randoms_viewgrams *= normatten_viewgrams; + /*RelatedViewgrams*/ prompts_denominator_viewgrams = scatter_viewgrams; + prompts_denominator_viewgrams += randoms_viewgrams; + prompts_denominator_projdata_ptr->set_related_viewgrams(prompts_denominator_viewgrams); + } + } } - } - } - - } -} - - +} END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char *argv[]) +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) + + 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; + 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/remove_sinograms.cxx b/src/experimental/utilities/remove_sinograms.cxx index a83554742..22bd65168 100644 --- a/src/experimental/utilities/remove_sinograms.cxx +++ b/src/experimental/utilities/remove_sinograms.cxx @@ -30,88 +30,69 @@ using std::endl; USING_NAMESPACE_STIR - -int main(int argc, char **argv) +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"; + << 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]); - + + 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) + if (max_segment_num_to_process < 0) { - error("%s: there are not enough axial positions even in segment 0\n", - argv[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) - 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; - + 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; 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); + + 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); + 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; - - - + 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 64969e4ee..2b1784d73 100644 --- a/src/experimental/utilities/set_blocks_to_value.cxx +++ b/src/experimental/utilities/set_blocks_to_value.cxx @@ -37,160 +37,142 @@ using std::min; using std::max; 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) { - for (int other_det=0; other_det det_pos_pair(DetectionPosition<>(det, ring), DetectionPosition<>(other_det, other_ring)); - const Succeeded success = - proj_data_info.get_bin_for_det_pos_pair(bin, det_pos_pair); - if (success == Succeeded::yes) - list_of_bins_in_block.push_back(bin); - } + const int det = tang_crystal + tang_det_offset; + const int ring = ax_crystal + ax_det_offset; + { + for (int other_det = 0; other_det < num_detectors_per_ring; ++other_det) + for (int other_ring = max(0, ring + min_ring_diff); other_ring <= min(num_rings - 1, ring + max_ring_diff); + ++other_ring) + { + // first check for impossible coincidence (because it cannot be handled by get_bin_for_det_ps_pair) + if (det == other_det) + continue; + const DetectionPositionPair<> det_pos_pair(DetectionPosition<>(det, ring), + DetectionPosition<>(other_det, other_ring)); + const Succeeded success = proj_data_info.get_bin_for_det_pos_pair(bin, det_pos_pair); + if (success == Succeeded::yes) + list_of_bins_in_block.push_back(bin); + } + } } - } } -bool +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) +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" + << 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"; + << "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()); + 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); - - 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); + { + 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); 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)); - + { + 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); - 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) + 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) { - 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; - } - out_projdata.set_viewgram(viewgram); - } + 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()) + 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; + } + out_projdata.set_viewgram(viewgram); + } return EXIT_SUCCESS; } diff --git a/src/experimental/utilities/shift_projdata_along_axis.cxx b/src/experimental/utilities/shift_projdata_along_axis.cxx index cbb34b1f4..b48fb060f 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 @@ -31,45 +31,40 @@ using std::max; USING_NAMESPACE_STIR - -int main(int argc, char **argv) +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"; + << 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]); + 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); + 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); + 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]; + 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; + 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 d12c054b5..478308bd2 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" @@ -31,41 +30,41 @@ 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'; @@ -75,19 +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; @@ -96,16 +89,16 @@ 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; + + const int strtblk = matdir.strtblk; switch (mptr->mhptr->file_type) { #if 0 @@ -164,86 +157,78 @@ dump_subheader(MatrixFile * mptr, 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; + 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 Norm3d: { + fprintf(stderr, "Not implemented yet\n"); + break; } } - } +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"); + } + 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); + } -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"); - } - - - 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); + 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 -#include +#include using std::cerr; using std::endl; - - USING_NAMESPACE_STIR -int -main(int argc, char **argv) +int +main(int argc, char** argv) { - - - 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; - exit(EXIT_FAILURE); - } + 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; + 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(); + + 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; + { + 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; } diff --git a/src/experimental/utilities/zero_projdata_from_norm.cxx b/src/experimental/utilities/zero_projdata_from_norm.cxx index d759c2c53..3529174df 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 */ @@ -23,67 +23,54 @@ #include "stir/warning.h" #include -#include +#include using std::cerr; using std::endl; - - 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; - exit(EXIT_FAILURE); - } - + 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(); + 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; - } - } - - return success==Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; + { + 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; + } + } + + return success == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/include/stir/ArcCorrection.h b/src/include/stir/ArcCorrection.h index 912c98bc0..6c8943484 100644 --- a/src/include/stir/ArcCorrection.h +++ b/src/include/stir/ArcCorrection.h @@ -19,7 +19,6 @@ #ifndef __stir_ArcCorrection_H__ #define __stir_ArcCorrection_H__ - #include "stir/ProjDataInfo.h" #include "stir/Array.h" #include "stir/shared_ptr.h" @@ -29,17 +28,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'). @@ -47,7 +51,7 @@ 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 @@ -66,65 +70,58 @@ 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(). @@ -146,14 +143,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 8fa5d9723..837ae7be4 100644 --- a/src/include/stir/Array.h +++ b/src/include/stir/Array.h @@ -14,44 +14,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. @@ -68,18 +68,18 @@ 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 @@ -94,7 +94,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. */ //@{ @@ -103,19 +103,29 @@ 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 @@ -123,18 +133,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 ~Array() override; @@ -157,45 +167,43 @@ 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); //! Sets elements below value to the value (overrides VectorWithOffset::fill) - inline void apply_lower_threshold(const elemT &l); + inline void apply_lower_threshold(const elemT& l); //! Sets elements above value to the value (overrides VectorWithOffset::fill) - inline void apply_upper_threshold(const elemT &u); + inline void apply_upper_threshold(const elemT& u); //! 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. */ @@ -203,76 +211,59 @@ 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 (use 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 **************************************************/ -//! 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> + , + boost::operators, NumericVectorWithOffset>, + boost::operators>, + boost::operators, elemT> #endif { #ifdef SWIG @@ -280,12 +271,11 @@ class Array<1, elemT> : public NumericVectorWithOffset // typedef in a definition of a public typedef/member public: #else - private: -#endif - typedef NumericVectorWithOffset base_type; +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 //@{ @@ -306,21 +296,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 ~Array() override; @@ -344,118 +333,110 @@ 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 void grow(const int min_index, const int max_index) override; - + //! Array::resize initialises new elements to 0 inline virtual void resize(const IndexRange<1>& range); - + // Array::resize initialises new elements to 0 inline void resize(const int min_index, const int max_index) override; - + //! 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; - + 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 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 - //! 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; //@} }; - 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 70f369f87..98fce7eb1 100644 --- a/src/include/stir/Array.inl +++ b/src/include/stir/Array.inl @@ -11,9 +11,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 @@ -32,35 +32,31 @@ 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() + : base_type() {} template Array::Array(const IndexRange& range) -: base_type() + : base_type() { grow(range); } @@ -72,70 +68,69 @@ Array::Array(const self& t) #else Array::Array(const base_type& t) #endif -: base_type(t) +: base_type(t) {} template Array::~Array() {} - template -typename Array::full_iterator +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 +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)); + 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 +typename Array::const_full_iterator Array::end_all() const { return this->end_all_const(); } template -typename Array::full_iterator +typename Array::full_iterator Array::begin_all() { if (this->begin() == this->end()) - { - // empty array - return end_all(); - } + { + // empty array + return end_all(); + } else - return full_iterator(this->begin(), this->end(), - this->begin()->begin_all(), this->begin()->end_all()); + return full_iterator(this->begin(), this->end(), this->begin()->begin_all(), this->begin()->end_all()); } - + template -typename Array::const_full_iterator +typename Array::const_full_iterator Array::begin_all_const() const { if (this->begin() == this->end()) - { - // empty array - return end_all(); - } + { + // 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 const_full_iterator(this->begin(), this->end(), this->begin()->begin_all_const(), this->begin()->end_all_const()); } template -typename Array::const_full_iterator +typename Array::const_full_iterator Array::begin_all() const { return begin_all_const(); @@ -145,125 +140,120 @@ template IndexRange Array::get_index_range() const { - VectorWithOffset > - range(this->get_min_index(), this->get_max_index()); + 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 +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++) { - maxval = std::max(this->num[i].find_max(), maxval); + 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; } - return maxval; - } - else - { - //TODO we should return elemT::minimum or something - return 0; - } } template -elemT +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++) { - minval = std::min(this->num[i].find_min(), minval); + elemT minval = this->num[this->get_min_index()].find_min(); + for (int i = this->get_min_index() + 1; i <= this->get_max_index(); i++) + { + minval = std::min(this->num[i].find_min(), minval); + } + return minval; + } + else + { + // TODO we should return elemT::maximum or something + return 0; } - return minval; - } - 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 void -Array::apply_lower_threshold(const elemT &l) +Array::apply_lower_threshold(const elemT& l) { 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].apply_lower_threshold(l); this->check_state(); } template void -Array::apply_upper_threshold(const elemT &u) +Array::apply_upper_threshold(const elemT& u) { 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].apply_upper_threshold(u); this->check_state(); } @@ -275,83 +265,79 @@ 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) +Array& +Array::operator[](int i) { - return base_type::operator[](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) +Array::operator[](const BasicCoordinate& c) { - return (*this)[c[1]][cut_first_dimension(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) +Array& +Array::at(int i) { - return base_type::at(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) +Array::at(const BasicCoordinate& c) { - return (*this).at(c[1]).at(cut_first_dimension(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())) @@ -361,21 +347,18 @@ void Array:: 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; - } + } } 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(); @@ -385,16 +368,15 @@ void Array:: 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++); - } + } } 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); } @@ -405,75 +387,71 @@ 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++) - assign(this->num[i], 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) - assign(this->num[i], 0); - 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(); + { + 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) + assign(this->num[i], 0); + } + 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() -{ } + : base_type() +{} template Array<1, elemT>::Array(const IndexRange<1>& range) -: base_type() + : base_type() { grow(range); } template Array<1, elemT>::Array(const int min_index, const int max_index) -: base_type() + : 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 @@ -481,50 +459,49 @@ Array<1, elemT>::~Array() {} template -typename Array<1, elemT>::full_iterator +typename Array<1, elemT>::full_iterator Array<1, elemT>::begin_all() { return this->begin(); } - + template -typename Array<1, elemT>::const_full_iterator +typename Array<1, elemT>::const_full_iterator Array<1, elemT>::begin_all() const { return this->begin(); } template -typename Array<1, elemT>::full_iterator +typename Array<1, elemT>::full_iterator Array<1, elemT>::end_all() { return this->end(); } - template -typename Array<1, elemT>::const_full_iterator +typename Array<1, elemT>::const_full_iterator Array<1, elemT>::end_all() const { - return this->end(); + return this->end(); } template -typename Array<1, elemT>::const_full_iterator +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 +typename Array<1, elemT>::const_full_iterator Array<1, elemT>::end_all_const() const { - return this->end(); + return this->end(); } template -IndexRange<1> +IndexRange<1> Array<1, elemT>::get_index_range() const { return IndexRange<1>(this->get_min_index(), this->get_max_index()); @@ -532,74 +509,71 @@ Array<1, elemT>::get_index_range() const 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++) - { - if (this->num[i] > 0) - acc += this->num[i]; - } - return acc; + 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; }; - template elemT -Array<1, elemT>::find_max() const -{ +Array<1, elemT>::find_max() const +{ this->check_state(); if (this->size() > 0) - { - return *std::max_element(this->begin(), this->end()); - } - else - { - // TODO return elemT::minimum or so - return 0; - } + { + return *std::max_element(this->begin(), this->end()); + } + else + { + // TODO return elemT::minimum or so + 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) - { - return *std::min_element(this->begin(), this->end()); - } - else - { - // TODO return elemT::maximum or so - return 0; - } + { + return *std::min_element(this->begin(), this->end()); + } + else + { + // TODO return elemT::maximum or so + return 0; + } this->check_state(); -}; +}; template bool @@ -610,28 +584,26 @@ Array<1, elemT>::is_regular() const 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 -/* 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); @@ -640,33 +612,33 @@ 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); @@ -675,7 +647,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); @@ -684,7 +656,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); @@ -693,61 +665,69 @@ 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 +template +const elemT& +Array<1, elemT>::operator[](int i) const { - return base_type::operator[](i); + return base_type::operator[](i); }; -template -elemT& Array<1,elemT>:: operator[] (int i) +template +elemT& +Array<1, elemT>::operator[](int i) { - return base_type::operator[](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 +template +const elemT& +Array<1, elemT>::at(int i) const { - return base_type::at(i); + return base_type::at(i); }; -template -elemT& Array<1,elemT>:: at (int i) +template +elemT& +Array<1, elemT>::at(int i) { - return base_type::at(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]); -}; +}; END_NAMESPACE_STIR diff --git a/src/include/stir/ArrayFilter1DUsingConvolution.h b/src/include/stir/ArrayFilter1DUsingConvolution.h index f4be01e4a..32a4d7849 100644 --- a/src/include/stir/ArrayFilter1DUsingConvolution.h +++ b/src/include/stir/ArrayFilter1DUsingConvolution.h @@ -22,30 +22,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"). @@ -74,45 +74,34 @@ 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 override; - Succeeded - get_influencing_indices(IndexRange<1>& influencing_indices, - const IndexRange<1>& output_indices) const override; + Succeeded get_influencing_indices(IndexRange<1>& influencing_indices, const IndexRange<1>& output_indices) const override; - Succeeded - get_influenced_indices(IndexRange<1>& influenced_indices, - const IndexRange<1>& input_indices) const override; + Succeeded get_influenced_indices(IndexRange<1>& influenced_indices, const IndexRange<1>& input_indices) const override; 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 override; - + void do_it(Array<1, elemT>& out_array, const Array<1, elemT>& in_array) const override; }; - - END_NAMESPACE_STIR - -#endif //ArrayFilter1DUsingConvolution - - +#endif // ArrayFilter1DUsingConvolution diff --git a/src/include/stir/ArrayFilter1DUsingConvolutionSymmetricKernel.h b/src/include/stir/ArrayFilter1DUsingConvolutionSymmetricKernel.h index ed174f8cc..fd490c1f2 100644 --- a/src/include/stir/ArrayFilter1DUsingConvolutionSymmetricKernel.h +++ b/src/include/stir/ArrayFilter1DUsingConvolutionSymmetricKernel.h @@ -22,12 +22,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 @@ -35,46 +35,38 @@ 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 override; private: - VectorWithOffset< elemT> filter_coefficients; - void do_it(Array<1,elemT>& out_array, const Array<1,elemT>& in_array) const override; - + VectorWithOffset filter_coefficients; + void do_it(Array<1, elemT>& out_array, const Array<1, elemT>& in_array) const override; }; - - END_NAMESPACE_STIR - -#endif //ArrayFilter1DUsingConvolutionSymmetricKernel - - +#endif // ArrayFilter1DUsingConvolutionSymmetricKernel diff --git a/src/include/stir/ArrayFilter2DUsingConvolution.h b/src/include/stir/ArrayFilter2DUsingConvolution.h index fe10dce57..8be71245f 100644 --- a/src/include/stir/ArrayFilter2DUsingConvolution.h +++ b/src/include/stir/ArrayFilter2DUsingConvolution.h @@ -18,49 +18,37 @@ #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 override; - 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 override; - + Array<2, float> filter_coefficients; + void do_it(Array<2, elemT>& out_array, const Array<2, elemT>& in_array) const override; }; - - END_NAMESPACE_STIR - -#endif //ArrayFilter2DUsingConvolution - - +#endif // ArrayFilter2DUsingConvolution diff --git a/src/include/stir/ArrayFilter3DUsingConvolution.h b/src/include/stir/ArrayFilter3DUsingConvolution.h index 0d92c2f94..94c607bb0 100644 --- a/src/include/stir/ArrayFilter3DUsingConvolution.h +++ b/src/include/stir/ArrayFilter3DUsingConvolution.h @@ -18,50 +18,38 @@ #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 override; - 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 override; - 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 override; + 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 5dc6974e3..1289aa9ec 100644 --- a/src/include/stir/ArrayFilterUsingRealDFTWithPadding.h +++ b/src/include/stir/ArrayFilterUsingRealDFTWithPadding.h @@ -25,35 +25,34 @@ 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); //! Construct the filter given the complex kernel coefficients @@ -61,12 +60,12 @@ 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); //! 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. @@ -74,36 +73,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 override; 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) @@ -112,16 +108,13 @@ class ArrayFilterUsingRealDFTWithPadding : an array with the same dimensions as the 'real' kernel. */ void do_it(Array& out_array, const Array& in_array) const override; + 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 7701a424a..2d7b20f17 100644 --- a/src/include/stir/ArrayFunction.h +++ b/src/include/stir/ArrayFunction.h @@ -20,7 +20,7 @@
      • functions which work on all stir::Array objects, and which change every element of the - array: + array: 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. @@ -99,17 +103,13 @@ class ProjDataInMemory; 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 @@ -118,46 +118,41 @@ class ProjData : public ExamData #endif //! Destructor - ~ProjData() override {} + ~ProjData() override + {} //! 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 /*! \deprecated Use get_viewgram(const ViewgramIndices&) instead. */ - 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; + 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; //! Get viewgram - inline Viewgram - get_viewgram(const ViewgramIndices&) const; + inline Viewgram get_viewgram(const ViewgramIndices&) const; //! Set viewgram - virtual Succeeded - set_viewgram(const Viewgram&) = 0; + virtual Succeeded set_viewgram(const Viewgram&) = 0; //! Get sinogram /*! \deprecated Use get_sinogram(const SinogramIndices&) instead . */ - 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; + 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; //! Get sinogram - inline Sinogram - get_sinogram(const SinogramIndices&) const; + inline Sinogram get_sinogram(const SinogramIndices&) const; //! 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; + // virtual float get_bin_value(const Bin& this_bin) const = 0; //! construct projection data that stores a subset of the views - unique_ptr - get_subset(const std::vector& views) const; + unique_ptr get_subset(const std::vector& views) const; //! Get empty viewgram Viewgram get_empty_viewgram(const ViewgramIndices&) const; @@ -166,93 +161,82 @@ class ProjData : public ExamData /*! \deprecated Use get_viewgram(const ViewgramIndices&) instead. */ - 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; - + 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 SinogramIndices&) const; + Sinogram get_empty_sinogram(const SinogramIndices&) const; //! Get empty_sinogram /*! \deprecated Use get_sinogram(const SinogramIndices&) instead . */ - 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; + 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 by view - SegmentByView - get_empty_segment_by_view(const SegmentIndices&) const; + //! Get empty segment by view + SegmentByView get_empty_segment_by_view(const SegmentIndices&) const; //! Get empty segment by sino - SegmentBySinogram - get_empty_segment_by_sinogram(const SegmentIndices&) const; + SegmentBySinogram get_empty_segment_by_sinogram(const SegmentIndices&) const; //! Get empty segment view /*! \deprecated Use get_empty_segment_by_sinogram(const SegmentIndices&) instead . */ - SegmentByView - get_empty_segment_by_view(const int segment_num, - const bool make_num_tangential_poss_odd = false, - const int timing_pos = 0) const; + 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 sino /*! \deprecated Use get_empty_segment_by_sinogram(const SegmentIndices&) instead . */ - SegmentBySinogram - get_empty_segment_by_sinogram(const int segment_num, - const bool make_num_tangential_poss_odd = false, - const int timing_pos = 0) const; + 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 /*! \deprecated Use get_segment_by_sinogram(const SegmentIndices&) instead. */ - virtual SegmentBySinogram - get_segment_by_sinogram(const int segment_num, const int timing_pos = 0) const; + virtual SegmentBySinogram get_segment_by_sinogram(const int segment_num, const int timing_pos = 0) const; //! Get segment by sinogram - inline SegmentBySinogram - get_segment_by_sinogram(const SegmentIndices&) const; + inline SegmentBySinogram get_segment_by_sinogram(const SegmentIndices&) const; //! Get segment by view /*! \deprecated Use get_segment_by_view(const SegmentIndices&) instead. */ - virtual SegmentByView - get_segment_by_view(const int segment_num, const int timing_pos = 0) const; + virtual SegmentByView get_segment_by_view(const int segment_num, const int timing_pos = 0) const; //! Get segment by view - inline SegmentByView - get_segment_by_view(const SegmentIndices&) const; + inline SegmentByView get_segment_by_view(const SegmentIndices&) 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 // TODOTOF remove timing_pos arg - virtual RelatedViewgrams - get_related_viewgrams(const ViewgramIndices&, - const shared_ptr&, - const bool make_num_tangential_poss_odd = false, - const int timing_pos = 0) const; + virtual RelatedViewgrams get_related_viewgrams(const ViewgramIndices&, + 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 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 ViewgramIndices& viewgram_indices, - const shared_ptr& symmetries_ptr, - const bool make_num_tangential_poss_odd = false, - const int timing_pos = 0) const; - + RelatedViewgrams get_empty_related_viewgrams(const ViewgramIndices& viewgram_indices, + 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 */ @@ -271,51 +255,48 @@ 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 the TOF index running slowest (from - to +) and segment order given by standard_segment_sequence(). This order would be useful to fill data from a 4D array constructed as follows: \code - Array<4,float> array(IndexRange4D(p.get_num_tof_poss(), p.get_num_non_tof_sinograms(), p.get_num_views(), p.get_num_tangential_poss())); - \endcode + Array<4,float> array(IndexRange4D(p.get_num_tof_poss(), p.get_num_non_tof_sinograms(), p.get_num_views(), + p.get_num_tangential_poss())); \endcode \sa copy_to() (consistency between these 2 is guaranteed) \warning there is no range-check on \a array_iter */ - template < typename iterT> - iterT fill_from( iterT array_iter) + template + iterT fill_from(iterT array_iter) { - // A type check would be useful. - // BOOST_STATIC_ASSERT((boost::is_same::value_type, Type>::value)); + // A type check would be useful. + // BOOST_STATIC_ASSERT((boost::is_same::value_type, Type>::value)); - 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(); + 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 : standard_segment_sequence(*this->get_proj_data_info_sptr())) { auto segment = this->get_empty_segment_by_sinogram(s, false, k); // cannot use std::copy sadly as needs end-iterator for range - for (auto seg_iter = segment.begin_all(); - seg_iter != segment.end_all(); + for (auto 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 TOF index running slowest (from - to +) and @@ -324,20 +305,20 @@ class ProjData : public ExamData \sa fill_from() (consistency between these 2 is guaranteed) \warning there is no range-check on \a array_iter */ - template < typename iterT> + template iterT copy_to(iterT array_iter) const { - 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 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 : standard_segment_sequence(*this->get_proj_data_info_sptr())) { - const auto segment = this->get_segment_by_sinogram(s,k); + const auto segment = this->get_segment_by_sinogram(s, k); array_iter = std::copy(segment.begin_all_const(), segment.end_all_const(), array_iter); } } - return array_iter; + return array_iter; } //! Get number of segments @@ -391,16 +372,13 @@ class ProjData : public ExamData Succeeded write_to_file(const std::string& filename) const; //! \deprecated a*x+b*y (use 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); @@ -409,13 +387,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 71bc4156a..6c4fd83d4 100644 --- a/src/include/stir/ProjData.inl +++ b/src/include/stir/ProjData.inl @@ -36,13 +36,13 @@ ProjData::get_segment_by_view(const SegmentIndices& si) const return this->get_segment_by_view(si.segment_num(), si.timing_pos_num()); } -Viewgram +Viewgram ProjData::get_viewgram(const ViewgramIndices& vi) const { return this->get_viewgram(vi.view_num(), vi.segment_num(), false, vi.timing_pos_num()); } -Sinogram +Sinogram ProjData::get_sinogram(const SinogramIndices& vi) const { return this->get_sinogram(vi.axial_pos_num(), vi.segment_num(), false, vi.timing_pos_num()); @@ -54,64 +54,124 @@ 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_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_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_max_segment_num() const +{ + return proj_data_info_sptr->get_max_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_axial_pos_num(const int segment_num) const +{ + return proj_data_info_sptr->get_min_axial_pos_num(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_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_view_num() const -{ return proj_data_info_sptr->get_min_view_num(); } +int +ProjData::get_min_view_num() const +{ + return proj_data_info_sptr->get_min_view_num(); +} -int ProjData::get_max_view_num() const -{ return proj_data_info_sptr->get_max_view_num(); } +int +ProjData::get_max_view_num() const +{ + return proj_data_info_sptr->get_max_view_num(); +} + +int +ProjData::get_min_tangential_pos_num() const +{ + return proj_data_info_sptr->get_min_tangential_pos_num(); +} -int ProjData::get_min_tangential_pos_num() const -{ return proj_data_info_sptr->get_min_tangential_pos_num(); } +int +ProjData::get_max_tangential_pos_num() const +{ + return proj_data_info_sptr->get_max_tangential_pos_num(); +} -int ProjData::get_max_tangential_pos_num() const -{ return proj_data_info_sptr->get_max_tangential_pos_num(); } +int +ProjData::get_min_tof_pos_num() const +{ + return proj_data_info_sptr->get_min_tof_pos_num(); +} -int ProjData::get_min_tof_pos_num() const -{ return proj_data_info_sptr->get_min_tof_pos_num(); } +int +ProjData::get_max_tof_pos_num() const +{ + return proj_data_info_sptr->get_max_tof_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(); } +std::vector +ProjData::get_original_view_nums() const +{ + return proj_data_info_sptr->get_original_view_nums(); +} -std::vector ProjData::get_original_view_nums() const -{ return proj_data_info_sptr->get_original_view_nums(); } - END_NAMESPACE_STIR diff --git a/src/include/stir/ProjDataFromStream.h b/src/include/stir/ProjDataFromStream.h index a356460f6..5aea1f53c 100644 --- a/src/include/stir/ProjDataFromStream.h +++ b/src/include/stir/ProjDataFromStream.h @@ -29,7 +29,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" @@ -39,31 +39,31 @@ 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 make_num_tangential_poss_odd (used in various + \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 { public: - - enum StorageOrder { + enum StorageOrder + { Segment_AxialPos_View_TangPos, Timing_Segment_AxialPos_View_TangPos, Segment_View_AxialPos_TangPos, Timing_Segment_View_AxialPos_TangPos, - Unsupported }; + Unsupported + }; #if 0 static ProjDataFromStream* ask_parameters(const bool on_disk = true); #endif @@ -72,50 +72,50 @@ 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.f ); + 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.f); + 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 the timing bins sequence @@ -123,41 +123,40 @@ class ProjDataFromStream : public ProjData //! set the timing bins sequence void set_timing_poss_sequence_in_stream(const std::vector& seq); - //! 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 override; + //! 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 override; Succeeded set_viewgram(const Viewgram& v) override; - - //! 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 override; + + //! 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 override; Succeeded set_sinogram(const Sinogram& s) override; - + //! Get all sinograms for the given segment - SegmentBySinogram get_segment_by_sinogram(const int segment_num, - const int timing_num = 0) const override; + SegmentBySinogram get_segment_by_sinogram(const int segment_num, const int timing_num = 0) const override; //! Get all viewgrams for the given segment - SegmentByView get_segment_by_view(const int segment_num, - const int timing_pos = 0) const override; - - + SegmentByView get_segment_by_view(const int segment_num, const int timing_pos = 0) const override; + //! Set all sinograms for the given segment Succeeded set_segment(const SegmentBySinogram&) override; //! Set all viewgrams for the given segment Succeeded set_segment(const SegmentByView&) override; //! 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; @@ -167,27 +166,25 @@ class ProjDataFromStream : public ProjData std::streamoff get_offset(const Bin&) const; private: - void activate_TOF(); //! offset of the whole 3d sinogram in the stream - std::streamoff offset; + 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 + //! 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 + //! 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; @@ -196,7 +193,6 @@ class ProjDataFromStream : public ProjData #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 77a717ed5..a3f52f2fa 100644 --- a/src/include/stir/ProjDataFromStream.inl +++ b/src/include/stir/ProjDataFromStream.inl @@ -25,44 +25,53 @@ START_NAMESPACE_STIR - -//ProjDataFromStream::ProjDataFromStream() +// ProjDataFromStream::ProjDataFromStream() //{} -ProjDataFromStream::StorageOrder +ProjDataFromStream::StorageOrder ProjDataFromStream::get_storage_order() const -{ return storage_order; } +{ + return storage_order; +} -int +int ProjDataFromStream::find_segment_index_in_sequence(const int segment_num) const { - 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); // 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 +std::streamoff ProjDataFromStream::get_offset_in_stream() const -{ return offset; } +{ + return offset; +} -NumericType +NumericType ProjDataFromStream::get_data_type_in_stream() const -{ return on_disk_data_type; } +{ + return on_disk_data_type; +} -ByteOrder +ByteOrder ProjDataFromStream::get_byte_order_in_stream() const -{ return on_disk_byte_order; } +{ + return on_disk_byte_order; +} -std::vector +std::vector ProjDataFromStream::get_segment_sequence_in_stream() const -{ return segment_sequence; } +{ + return segment_sequence; +} std::vector ProjDataFromStream::get_timing_poss_sequence_in_stream() const -{ return timing_poss_sequence; } +{ + return timing_poss_sequence; +} #if 0 // this does not make a lot of sense. How to compare files etc. ? @@ -78,10 +87,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/ProjDataGEHDF5.h b/src/include/stir/ProjDataGEHDF5.h index d97a6ff96..b34639740 100644 --- a/src/include/stir/ProjDataGEHDF5.h +++ b/src/include/stir/ProjDataGEHDF5.h @@ -31,9 +31,10 @@ START_NAMESPACE_STIR -namespace GE { -namespace RDF_HDF5 { - +namespace GE +{ +namespace RDF_HDF5 +{ /*! \ingroup projdata @@ -44,47 +45,49 @@ namespace RDF_HDF5 { 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) override; - //! Set Sinogram - Succeeded set_sinogram(const Sinogram& s) override; - //! 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 override; - //! 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 override; - //! 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) override; + //! Set Sinogram + Succeeded set_sinogram(const Sinogram& s) override; + //! 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 override; + //! 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 override; + //! 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 0c32af3c3..9bfad53f7 100644 --- a/src/include/stir/ProjDataInMemory.h +++ b/src/include/stir/ProjDataInMemory.h @@ -37,54 +37,59 @@ class Succeeded; */ class ProjDataInMemory : public ProjData { -public: - +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); - Viewgram get_viewgram(const int view_num, const int segment_num, - const bool make_num_tangential_poss_odd=false + Viewgram get_viewgram(const int view_num, + const int segment_num, + const bool make_num_tangential_poss_odd = false #ifdef STIR_TOF - , const int timing_pos=0 + , + const int timing_pos = 0 #endif - ) const override; + ) const override; Succeeded set_viewgram(const Viewgram& v) override; - Sinogram get_sinogram(const int ax_pos_num, const int segment_num, - const bool make_num_tangential_poss_odd=false + Sinogram get_sinogram(const int ax_pos_num, + const int segment_num, + const bool make_num_tangential_poss_odd = false #ifdef STIR_TOF - , const int timing_pos=0 + , + const int timing_pos = 0 #endif - ) const override; + ) const override; Succeeded set_sinogram(const Sinogram& s) override; //! Get all sinograms for the given segment SegmentBySinogram get_segment_by_sinogram(const int segment_num #ifdef STIR_TOF - , const int timing_pos=0 + , + const int timing_pos = 0 #endif - ) const override; + ) const override; //! Get all viewgrams for the given segment SegmentByView get_segment_by_view(const int segment_num #ifdef STIR_TOF - , const int timing_pos=0 + , + const int timing_pos = 0 #endif - ) const override; + ) const override; //! Set all sinograms for the given segment Succeeded set_segment(const SegmentBySinogram&) override; @@ -104,105 +109,126 @@ class ProjDataInMemory : public ProjData //! destructor deallocates all memory the object owns ~ProjDataInMemory() override; - + //! 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 (use xapyb) - STIR_DEPRECATED void axpby(const float a, const ProjData& x, - const float b, const ProjData& y) override; + STIR_DEPRECATED void axpby(const float a, const ProjData& x, const float b, const ProjData& y) override; //! 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) - void xapyb(const ProjData& x, const float a, - const ProjData& y, const float b) override; + void xapyb(const ProjData& x, const float a, const ProjData& y, const float b) override; //! 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) - void xapyb(const ProjData& x, const ProjData& a, - const ProjData& y, const ProjData& b) override; + void xapyb(const ProjData& x, const ProjData& a, const ProjData& y, const ProjData& b) override; //! 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) void sapyb(const float a, const ProjData& y, const float b) override; //! 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) void sapyb(const ProjData& a, const ProjData& y, const ProjData& b) override; /** @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(); } + { + return buffer.begin(); + } //! start value for iterating through all elements in the (const) array, see iterator inline const_iterator begin() const - { return buffer.begin(); } + { + return buffer.begin(); + } //! end value for iterating through all elements in the array, see iterator inline iterator end() - { return buffer.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(); } + { + return buffer.end(); + } //! start value for iterating through all elements in the array, see iterator inline iterator begin_all() - { return buffer.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(); } + { + return buffer.begin_all(); + } //! end value for iterating through all elements in the array, see iterator inline iterator end_all() - { return buffer.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(); } + { + return buffer.end_all(); + } - //! \name access to the data via a pointer + //! \name access to the data via a pointer //@{ //! member function for access to the data via a float* inline float* get_data_ptr() - { return buffer.get_data_ptr(); } + { + return buffer.get_data_ptr(); + } //! member function for access to the data via a const float* - inline const float * get_const_data_ptr() const - { return buffer.get_const_data_ptr(); } + inline const float* get_const_data_ptr() const + { + return buffer.get_const_data_ptr(); + } //! signal end of access to float* inline void release_data_ptr() - { buffer.release_data_ptr(); } + { + buffer.release_data_ptr(); + } //! signal end of access to const float* inline void release_const_data_ptr() const - { buffer.release_const_data_ptr(); } + { + buffer.release_const_data_ptr(); + } //@} private: - Array<1,float> buffer; - + Array<1, float> buffer; + //! allocates buffer for storing the data. Has to be called by constructors void create_buffer(const bool initialise_with_0 = false); //! offset of the whole 3d sinogram in the stream - std::streamoff offset; + 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 + //! 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 + //! the order in which the timing bins occur in the stream std::vector timing_poss_sequence; //! Calculate the offset for a specific bin @@ -212,5 +238,4 @@ class ProjDataInMemory : public ProjData END_NAMESPACE_STIR - #endif diff --git a/src/include/stir/ProjDataInfo.h b/src/include/stir/ProjDataInfo.h index 74e4bfbf8..f6ef1a032 100644 --- a/src/include/stir/ProjDataInfo.h +++ b/src/include/stir/ProjDataInfo.h @@ -39,21 +39,28 @@ 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 @@ -65,35 +72,34 @@ class ProjDataInfo 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. - \warning N.E: TOF mash factor = 1, means possible many TOF bins + \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); + 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, - const int tof_mash_factor = 0); + */ + 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). @@ -102,41 +108,41 @@ class ProjDataInfo 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 = 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, - const int tof_mash_factor = 0); + 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); /************ constructors ***********/ // TODO should probably be protected //! Construct an empty object - ProjDataInfo(); - + 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 - */ + /*! 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); + 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); + 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' + //! Standard trick for a 'virtual copy-constructor' virtual ProjDataInfo* clone() const = 0; //! Like clone() but return a shared_ptr @@ -156,29 +162,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. */ @@ -186,7 +192,7 @@ 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); @@ -240,7 +246,7 @@ class ProjDataInfo /* 0 indicates non-TOF data, as well as the max number of TOF bins for the scanner (as all TOF bins will then be added). */ inline int get_tof_mash_factor() const; - //! Get the index of the first TOF position + //! 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; @@ -275,20 +281,20 @@ class ProjDataInfo //@{ //! 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) /*! @@ -302,13 +308,13 @@ 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. @@ -323,16 +329,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 @@ -340,8 +344,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 @@ -349,8 +353,8 @@ 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 @@ -361,9 +365,8 @@ class ProjDataInfo 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. @@ -376,16 +379,14 @@ class ProjDataInfo in the next release. \see get_LOR() */ - virtual - Bin - get_bin(const LOR&,const double delta_time = 0.0) 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; @@ -406,53 +407,60 @@ class ProjDataInfo //! Get empty viewgram /*! \deprecated */ - 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; - + 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 /*! \deprecated */ - 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; + 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 /*! \deprecated */ - 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; + 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 /*! \deprecated */ - 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; - + 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 /*! make_num_tangential_poss_odd has to be \c false */ - //TODOTOF + // TODOTOF RelatedViewgrams get_empty_related_viewgrams(const ViewgramIndices&, - const shared_ptr&, - const bool make_num_tangential_poss_odd = false, - const int timing_pos_num = 0) 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; }; + 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. + //! Vector which holds the lower and higher boundary for each TOF position, without the application of TOF mashing, in mm, for + //! faster access. #if 0 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. @@ -461,25 +469,35 @@ class ProjDataInfo //! Set horizontal bed position void set_bed_position_horizontal(const float bed_position_horizontal_arg) - { bed_position_horizontal = 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; } + 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; } + { + bed_position_vertical = bed_position_vertical_arg; + } //! Get vertical bed position - float get_bed_position_vertical() const { return bed_position_vertical; } - + float get_bed_position_vertical() const + { + return bed_position_vertical; + } + inline bool has_energy_information() const { - return scanner_ptr->has_energy_information(); + 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; @@ -503,11 +521,10 @@ class ProjDataInfo float tof_increament_in_mm; //! Number of tof bins (TOF mash factor applied) int num_tof_bins; - VectorWithOffset min_axial_pos_per_seg; + VectorWithOffset min_axial_pos_per_seg; VectorWithOffset max_axial_pos_per_seg; float bed_position_horizontal; float bed_position_vertical; - }; END_NAMESPACE_STIR @@ -515,4 +532,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 d714e1764..8677a7083 100644 --- a/src/include/stir/ProjDataInfo.inl +++ b/src/include/stir/ProjDataInfo.inl @@ -29,43 +29,50 @@ #include "stir/warning.h" START_NAMESPACE_STIR -shared_ptr -ProjDataInfo:: -create_shared_clone() const +shared_ptr +ProjDataInfo::create_shared_clone() const { shared_ptr sptr(this->clone()); return sptr; } shared_ptr -ProjDataInfo:: -create_non_tof_clone() const +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; + 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 +int ProjDataInfo::get_num_segments() const -{ return (max_axial_pos_per_seg.get_length());} - +{ + 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;} +{ + return max_axial_pos_per_seg[segment_num] - min_axial_pos_per_seg[segment_num] + 1; +} -int +int ProjDataInfo::get_num_views() const -{ return max_view_num - min_view_num + 1; } +{ + return max_view_num - min_view_num + 1; +} -int +int ProjDataInfo::get_num_tangential_poss() const -{ return max_tangential_pos_num - min_tangential_pos_num + 1; } +{ + return max_tangential_pos_num - min_tangential_pos_num + 1; +} int ProjDataInfo::get_num_tof_poss() const -{ return num_tof_bins; } +{ + return num_tof_bins; +} int ProjDataInfo::get_tof_bin(const double delta) const @@ -74,11 +81,10 @@ ProjDataInfo::get_tof_bin(const double delta) const 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; - } + { + 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; @@ -107,93 +113,105 @@ ProjDataInfo::get_unmashed_tof_bin(const double delta) const int ProjDataInfo::get_tof_mash_factor() const -{ return tof_mash_factor; } +{ + return tof_mash_factor; +} int ProjDataInfo::get_min_segment_num() const -{ return (max_axial_pos_per_seg.get_min_index()); } +{ + return (max_axial_pos_per_seg.get_min_index()); +} -int -ProjDataInfo::get_max_segment_num()const -{ return (max_axial_pos_per_seg.get_max_index()); } +int +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];} - +{ + return min_axial_pos_per_seg[segment_num]; +} int ProjDataInfo::get_max_axial_pos_num(const int segment_num) const -{ return max_axial_pos_per_seg[segment_num];} - +{ + return max_axial_pos_per_seg[segment_num]; +} -int +int ProjDataInfo::get_min_view_num() const - { return min_view_num; } - -int -ProjDataInfo::get_max_view_num() const -{ return max_view_num; } +{ + 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; + return min_tof_pos_num; } int ProjDataInfo::get_max_tof_pos_num() const { - return max_tof_pos_num; + return max_tof_pos_num; } 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 + // 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))); + return 1 / sqrt(1 + square(get_tantheta(bin))); } float ProjDataInfo::get_m(const Bin& bin) const { - return - get_t(bin)/get_costheta(bin); + return get_t(bin) / get_costheta(bin); } -const -Scanner* +const Scanner* ProjDataInfo::get_scanner_ptr() const -{ +{ return scanner_ptr.get(); } @@ -203,12 +221,11 @@ ProjDataInfo::get_scanner_sptr() const return scanner_ptr; } - int 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; @@ -217,13 +234,14 @@ ProjDataInfo::get_num_non_tof_sinograms() const int ProjDataInfo::get_num_sinograms() const { - return this->get_num_non_tof_sinograms()*this->get_num_tof_poss(); + 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()); } +{ + 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/ProjDataInfoBlocksOnCylindrical.h b/src/include/stir/ProjDataInfoBlocksOnCylindrical.h index 1183bbf40..8201468c6 100644 --- a/src/include/stir/ProjDataInfoBlocksOnCylindrical.h +++ b/src/include/stir/ProjDataInfoBlocksOnCylindrical.h @@ -5,7 +5,7 @@ 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, @@ -24,7 +24,6 @@ limitations under the License. #ifndef __stir_ProjDataInfoBlocksOnCylindrical_H__ #define __stir_ProjDataInfoBlocksOnCylindrical_H__ - #include "stir/ProjDataInfoGeneric.h" START_NAMESPACE_STIR diff --git a/src/include/stir/ProjDataInfoBlocksOnCylindricalNoArcCorr.h b/src/include/stir/ProjDataInfoBlocksOnCylindricalNoArcCorr.h index 2b74fb2a9..f3f953ee8 100644 --- a/src/include/stir/ProjDataInfoBlocksOnCylindricalNoArcCorr.h +++ b/src/include/stir/ProjDataInfoBlocksOnCylindricalNoArcCorr.h @@ -23,7 +23,6 @@ #ifndef __stir_ProjDataInfoBlocksOnCylindricalNoArcCorr_H__ #define __stir_ProjDataInfoBlocksOnCylindricalNoArcCorr_H__ - #include "stir/ProjDataInfoGenericNoArcCorr.h" #include "stir/ProjDataInfoBlocksOnCylindrical.h" #include "stir/GeometryBlocksOnCylindrical.h" @@ -50,7 +49,7 @@ 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. @@ -87,10 +86,11 @@ class ProjDataInfoBlocksOnCylindricalNoArcCorr : public ProjDataInfoGenericNoArc //! Constructor which gets geometry from the scanner ProjDataInfoBlocksOnCylindricalNoArcCorr(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 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* clone() const override; @@ -100,19 +100,20 @@ class ProjDataInfoBlocksOnCylindricalNoArcCorr : public ProjDataInfoGenericNoArc //! \name set of obsolete functions to go between bins<->LORs (will disappear!) //@{ - Succeeded find_scanner_coordinates_given_cartesian_coordinates(int& det1, int& det2, int& ring1, int& ring2, - const CartesianCoordinate3D& c1, - const CartesianCoordinate3D& c2) const; + Succeeded find_scanner_coordinates_given_cartesian_coordinates(int& det1, + int& det2, + int& ring1, + int& ring2, + const CartesianCoordinate3D& c1, + const CartesianCoordinate3D& c2) const; void find_bin_given_cartesian_coordinates_of_detection(Bin& bin, - const CartesianCoordinate3D& coord_1, - const CartesianCoordinate3D& coord_2) const; + const CartesianCoordinate3D& coord_1, + const CartesianCoordinate3D& coord_2) const; //@} private: - - bool blindly_equals(const root_type * const) const override; - + bool blindly_equals(const root_type* const) const override; }; END_NAMESPACE_STIR diff --git a/src/include/stir/ProjDataInfoBlocksOnCylindricalNoArcCorr.inl b/src/include/stir/ProjDataInfoBlocksOnCylindricalNoArcCorr.inl index c58678d47..a32491126 100644 --- a/src/include/stir/ProjDataInfoBlocksOnCylindricalNoArcCorr.inl +++ b/src/include/stir/ProjDataInfoBlocksOnCylindricalNoArcCorr.inl @@ -15,7 +15,7 @@ \ingroup projdata \brief Implementation of inline functions of class - stir::ProjDataInfoBlocksOnCylindricalNoArcCorr + stir::ProjDataInfoBlocksOnCylindricalNoArcCorr \author Kris Thielemans \author Parisa Khateri @@ -29,5 +29,4 @@ START_NAMESPACE_STIR - END_NAMESPACE_STIR diff --git a/src/include/stir/ProjDataInfoCylindrical.h b/src/include/stir/ProjDataInfoCylindrical.h index 4c3f9043c..d0b2a3432 100644 --- a/src/include/stir/ProjDataInfoCylindrical.h +++ b/src/include/stir/ProjDataInfoCylindrical.h @@ -25,7 +25,6 @@ #ifndef __stir_ProjDataInfoCylindrical_H__ #define __stir_ProjDataInfoCylindrical_H__ - #include "stir/ProjDataInfo.h" #include "stir/CartesianCoordinate3D.h" #include @@ -36,8 +35,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 @@ -46,7 +45,7 @@ class Succeeded; format. */ // TODOdoc more -class ProjDataInfoCylindrical: public ProjDataInfo +class ProjDataInfoCylindrical : public ProjDataInfo { private: typedef ProjDataInfo base_type; @@ -54,7 +53,7 @@ class ProjDataInfoCylindrical: public ProjDataInfo public: //! Type used by get_all_ring_pairs_for_segment_axial_pos_num() - typedef std::vector > RingNumPairs; + typedef std::vector> RingNumPairs; //! Constructors ProjDataInfoCylindrical(); @@ -62,34 +61,33 @@ 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 float get_tantheta(const Bin&) const override; - - inline float get_phi(const Bin&) const override; - + 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 float get_tantheta(const Bin&) const override; + + inline float get_phi(const Bin&) const override; + inline float get_t(const Bin&) const override; //! 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 override; - void - get_LOR(LORInAxialAndNoArcCorrSinogramCoordinates& lor, - const Bin& bin) const override; + void get_LOR(LORInAxialAndNoArcCorrSinogramCoordinates& lor, const Bin& bin) const override; #if 0 // KT disabled these as untested (and unused) @@ -116,8 +114,8 @@ class ProjDataInfoCylindrical: public ProjDataInfo void set_azimuthal_angle_offset(const float angle); //! Set the azimuthal sampling (in radians) 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 @@ -128,8 +126,7 @@ class ProjDataInfoCylindrical: public ProjDataInfo the first view returns the same \c get_phi. Depending on what you want, you might have to call \c set_azimuthal_angle_offset() as well. */ - void - set_num_views(const int new_num_views) override; + void set_num_views(const int new_num_views) override; void set_tof_mash_factor(const int new_num) override; @@ -141,23 +138,25 @@ class ProjDataInfoCylindrical: public ProjDataInfo inline float get_sampling_in_m(const Bin&) const override; //! 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. */ virtual inline float get_axial_sampling(int segment_num) const; //! Return if axial sampling makes sense /*! could be \c false for block/generic cases */ virtual inline bool axial_sampling_is_uniform() const - { return true; } - + { + return true; + } + //! 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 @@ -165,21 +164,21 @@ class ProjDataInfoCylindrical: public ProjDataInfo //! Set maximum ring difference void set_max_ring_difference(int max_ring_diff_v, int segment_num); - void set_num_axial_poss_per_segment(const VectorWithOffset& num_axial_poss_per_segment) override; + void set_num_axial_poss_per_segment(const VectorWithOffset& num_axial_poss_per_segment) override; void set_min_axial_pos_num(const int min_ax_pos_num, const int segment_num) override; void set_max_axial_pos_num(const int max_ax_pos_num, const int segment_num) override; void reduce_segment_range(const int min_segment_num, const int max_segment_num) override; //! 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; @@ -190,23 +189,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'. @@ -215,38 +213,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 /*! @@ -256,56 +247,51 @@ 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; std::string parameter_info() const override; 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: - bool blindly_equals(const root_type * const) const override = 0; + bool blindly_equals(const root_type* const) const override = 0; private: float azimuthal_angle_offset; 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!) */ @@ -319,7 +305,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; @@ -331,8 +317,7 @@ class ProjDataInfoCylindrical: public ProjDataInfo inline int get_num_axial_poss_per_ring_inc(const int segment_num) const; //! 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; @@ -340,10 +325,8 @@ class ProjDataInfoCylindrical: public ProjDataInfo //! initialise one element of the above table /*! Not thread-safe! Use initialise_ring_diff_arrays_if_not_done_yet() instead. */ 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 7b5c4922a..7fa36dcb7 100644 --- a/src/include/stir/ProjDataInfoCylindrical.inl +++ b/src/include/stir/ProjDataInfoCylindrical.inl @@ -35,23 +35,23 @@ 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) @@ -60,63 +60,56 @@ initialise_ring_diff_arrays_if_not_done_yet() const } } -//PW Added the view offset from the scanner, code may now support intrinsic tilt. +// PW Added the view offset from the scanner, code may now support intrinsic tilt. float -ProjDataInfoCylindrical::get_phi(const Bin& bin)const -{ return bin.view_num()*azimuthal_angle_sampling + azimuthal_angle_offset;} - +ProjDataInfoCylindrical::get_phi(const Bin& bin) const +{ + return bin.view_num() * azimuthal_angle_sampling + azimuthal_angle_offset; +} float 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); + 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) + 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 +float ProjDataInfoCylindrical::get_sampling_in_m(const Bin& bin) const { return get_axial_sampling(bin.segment_num()); } -float +float ProjDataInfoCylindrical::get_sampling_in_t(const Bin& bin) const { - return get_axial_sampling(bin.segment_num())*get_costheta(bin); + return get_axial_sampling(bin.segment_num()) * get_costheta(bin); } -int -ProjDataInfoCylindrical:: -get_num_axial_poss_per_ring_inc(const int segment_num) const +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; + return max_ring_diff[segment_num] != min_ring_diff[segment_num] ? 2 : 1; } - float ProjDataInfoCylindrical::get_azimuthal_angle_offset() const { @@ -125,43 +118,48 @@ ProjDataInfoCylindrical::get_azimuthal_angle_offset() const float ProjDataInfoCylindrical::get_azimuthal_angle_sampling() const -{return azimuthal_angle_sampling;} +{ + 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); + return ring_spacing / get_num_axial_poss_per_ring_inc(segment_num); } -float +float ProjDataInfoCylindrical::get_average_ring_difference(int segment_num) const { - // KT 05/07/2001 use float division here. + // 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 +int ProjDataInfoCylindrical::get_min_ring_difference(int segment_num) const -{ return min_ring_diff[segment_num]; } +{ + return min_ring_diff[segment_num]; +} -int +int ProjDataInfoCylindrical::get_max_ring_difference(int segment_num) const -{ return max_ring_diff[segment_num]; } +{ + 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) + 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"); - } + 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(); } @@ -169,8 +167,7 @@ ProjDataInfoCylindrical::get_ring_radius() const void 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()) + 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"); } @@ -181,7 +178,7 @@ ProjDataInfoCylindrical::set_ring_radii_for_all_views(const VectorWithOffset ProjDataInfoCylindrical::get_ring_radii_for_all_views() const { - if (this->ring_radius.get_min_index()==0 && this->ring_radius.get_max_index()==0) + 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]); @@ -192,9 +189,9 @@ ProjDataInfoCylindrical::get_ring_radii_for_all_views() const } float -ProjDataInfoCylindrical::get_ring_radius( const int view_num) const +ProjDataInfoCylindrical::get_ring_radius(const int view_num) const { - if (this->ring_radius.get_min_index()==0 && this->ring_radius.get_max_index()==0) + 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]; @@ -202,30 +199,29 @@ ProjDataInfoCylindrical::get_ring_radius( const int view_num) const float ProjDataInfoCylindrical::get_ring_spacing() const -{ return ring_spacing;} +{ + 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(); @@ -238,49 +234,37 @@ 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 +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()); + 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(); return *this->segment_axial_pos_to_ring_pair[segment_num][axial_pos_num]; } unsigned -ProjDataInfoCylindrical:: -get_num_ring_pairs_for_segment_axial_pos_num(const int segment_num, - const int axial_pos_num) const +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()); + 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 978beffa1..8a80f8e26 100644 --- a/src/include/stir/ProjDataInfoCylindricalArcCorr.h +++ b/src/include/stir/ProjDataInfoCylindricalArcCorr.h @@ -26,13 +26,12 @@ #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 @@ -50,15 +49,17 @@ 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, - const int tof_mash_factor = 0); + 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 override; - + bool operator==(const self_type&) const; inline float get_s(const Bin&) const override; @@ -67,19 +68,18 @@ class ProjDataInfoCylindricalArcCorr : public ProjDataInfoCylindrical //! Get tangential sampling inline float get_tangential_sampling() const; float get_sampling_in_s(const Bin&) const override - {return bin_size; } + { + return bin_size; + } - - Bin - get_bin(const LOR&, const double delta_time = 0.0) const override; + Bin get_bin(const LOR&, const double delta_time = 0.0) const override; std::string parameter_info() const override; + private: - float bin_size; - bool blindly_equals(const root_type * const) const override; - + bool blindly_equals(const root_type* const) const override; }; END_NAMESPACE_STIR diff --git a/src/include/stir/ProjDataInfoCylindricalArcCorr.inl b/src/include/stir/ProjDataInfoCylindricalArcCorr.inl index 817bbd5e8..138ef5829 100644 --- a/src/include/stir/ProjDataInfoCylindricalArcCorr.inl +++ b/src/include/stir/ProjDataInfoCylindricalArcCorr.inl @@ -29,12 +29,14 @@ START_NAMESPACE_STIR float ProjDataInfoCylindricalArcCorr::get_s(const Bin& bin) const -{return bin.tangential_pos_num()*bin_size;} - +{ + return bin.tangential_pos_num() * bin_size; +} float ProjDataInfoCylindricalArcCorr::get_tangential_sampling() const -{return bin_size;} +{ + return bin_size; +} END_NAMESPACE_STIR - diff --git a/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h b/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h index 77bf4597b..b1657341b 100644 --- a/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h +++ b/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h @@ -23,7 +23,6 @@ #ifndef __stir_ProjDataInfoCylindricalNoArcCorr_H__ #define __stir_ProjDataInfoCylindricalNoArcCorr_H__ - #include "stir/ProjDataInfoCylindrical.h" #include "stir/DetectionPositionPair.h" #include "stir/VectorWithOffset.h" @@ -33,7 +32,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 @@ -43,7 +42,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 @@ -55,13 +54,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 @@ -74,7 +73,7 @@ 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, @@ -96,30 +95,33 @@ class ProjDataInfoCylindricalNoArcCorr : public ProjDataInfoCylindrical //! 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, - const int tof_mash_factor = 0); + 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, - const int tof_mash_factor = 0); + 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 override; 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 float get_s(const Bin&) const override; @@ -130,17 +132,17 @@ class ProjDataInfoCylindricalNoArcCorr : public ProjDataInfoCylindrical std::string parameter_info() const override; //! \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 /*! \see get_all_det_pos_pairs_for_bin(). This function return the size of its output. */ - unsigned int - get_num_det_pos_pairs_for_bin(const Bin&, bool ignore_non_spatial_dimensions = true) const; + unsigned int get_num_det_pos_pairs_for_bin(const Bin&, bool ignore_non_spatial_dimensions = true) const; //! This routine fills a vector with all the detector pairs that correspond to a bin. /*! @@ -220,32 +209,33 @@ class ProjDataInfoCylindricalNoArcCorr : public ProjDataInfoCylindrical will be set, i.e. only the detection positions are returned, not TOF (nor energy) \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&, - bool ignore_non_spatial_dimensions = true) const; + void get_all_det_pos_pairs_for_bin(std::vector>&, + const Bin&, + bool ignore_non_spatial_dimensions = true) const; - private: +private: // old function, now private. Use get_bin_for_det_pos_pair instead. //! 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 \warning Takes a "TOF-mashed" bin as argument ATM. - */ - 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 mashed_timing_pos_num = 0) const; - public: + */ + 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 mashed_timing_pos_num = 0) const; + +public: //! This routine gets the detector pair corresponding to a bin. /*! \see get_det_pair_for_view_tangential_pos_num() for @@ -254,18 +244,11 @@ class ProjDataInfoCylindricalNoArcCorr : public ProjDataInfoCylindrical \obsolete */ - inline void - get_det_pair_for_bin( - int& det_num1, int& ring_num1, - int& det_num2, int& ring_num2, - const Bin& 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; //@} - - Bin - get_bin(const LOR&,const double delta_time) const override; - + Bin get_bin(const LOR&, const double delta_time) const override; //! \name set of obsolete functions to go between bins<->LORs (will disappear!) //@{ @@ -274,27 +257,31 @@ class ProjDataInfoCylindricalNoArcCorr : public ProjDataInfoCylindrical is zero in the first ring, while for get_m() etc it is zero in the centre of the scanner. \obsolete */ - Succeeded find_scanner_coordinates_given_cartesian_coordinates(int& det1, int& det2, int& ring1, int& ring2, - const CartesianCoordinate3D& c1, - const CartesianCoordinate3D& c2) const; - + 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 int timing_pos_num) const; - + 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 int timing_pos_num) const; + void find_bin_given_cartesian_coordinates_of_detection(Bin& bin, - const CartesianCoordinate3D& coord_1, - const CartesianCoordinate3D& coord_2) const; + const CartesianCoordinate3D& coord_1, + const CartesianCoordinate3D& coord_2) const; //@} private: - float ring_radius; float angular_increment; @@ -302,16 +289,25 @@ class ProjDataInfoCylindricalNoArcCorr : public ProjDataInfoCylindrical float get_psi_offset() const; // 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; @@ -321,8 +317,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; - bool blindly_equals(const root_type * const) const override; - + bool blindly_equals(const root_type* const) const override; }; END_NAMESPACE_STIR diff --git a/src/include/stir/ProjDataInfoCylindricalNoArcCorr.inl b/src/include/stir/ProjDataInfoCylindricalNoArcCorr.inl index 23d7984b5..9f3678de3 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 @@ -27,75 +27,70 @@ 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 +ProjDataInfoCylindricalNoArcCorr::get_s(const Bin& bin) const { - return ring_radius * sin(bin.tangential_pos_num()*angular_increment); + 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(); @@ -104,109 +99,89 @@ 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 +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); + 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 int timing_pos_num) const -{ +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); - } + { + 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 - { - 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); - } + { + 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 +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())); + 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()); + // 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()); //} - //else + // 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 +ProjDataInfoCylindricalNoArcCorr::get_det_pos_pair_for_bin(DetectionPositionPair<>& dp, const Bin& bin) const { // This is a bit complicated as DetectionPositionPair<>::timing_pos() was an unsigned int at some point, // while Bin uses an int. So swap detectors around. - //lousy work around because types don't match (short/int). TODO remove! + // lousy work around because types don't match (short/int). TODO remove! int t1, a1, t2, a2; get_det_pair_for_bin(t1, a1, t2, a2, bin); - if (bin.timing_pos_num()>=0) + if (bin.timing_pos_num() >= 0) { - 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; } else { - dp.pos1().tangential_coord()=t2; - dp.pos1().axial_coord()=a2; - dp.pos2().tangential_coord()=t1; - dp.pos2().axial_coord()=a1; + dp.pos1().tangential_coord() = t2; + dp.pos1().axial_coord() = a2; + dp.pos2().tangential_coord() = t1; + dp.pos2().axial_coord() = a1; } - - dp.timing_pos() = std::abs(bin.timing_pos_num())*this->get_tof_mash_factor(); + dp.timing_pos() = std::abs(bin.timing_pos_num()) * this->get_tof_mash_factor(); } END_NAMESPACE_STIR - diff --git a/src/include/stir/ProjDataInfoGeneric.h b/src/include/stir/ProjDataInfoGeneric.h index cb83c9ac2..713dd0f53 100644 --- a/src/include/stir/ProjDataInfoGeneric.h +++ b/src/include/stir/ProjDataInfoGeneric.h @@ -12,7 +12,7 @@ \file \ingroup projdata \brief Declaration of class stir::ProjDataInfoGeneric - + \author Parisa Khateri \author Michael Roethlisberger \author Kris Thielemans @@ -20,13 +20,13 @@ #ifndef __stir_ProjDataInfoGeneric_H__ #define __stir_ProjDataInfoGeneric_H__ - #include "stir/ProjDataInfoCylindrical.h" START_NAMESPACE_STIR class Succeeded; -template class CartesianCoordinate3D; +template +class CartesianCoordinate3D; /*! \ingroup projdata @@ -47,7 +47,7 @@ template class CartesianCoordinate3D; \todo change hierarchy order, i.e. derive from ProjDataInfoCylindrical from ProjDataInfoGeneric. */ -class ProjDataInfoGeneric: public ProjDataInfoCylindrical +class ProjDataInfoGeneric : public ProjDataInfoCylindrical { private: typedef ProjDataInfo base_type; @@ -55,7 +55,7 @@ class ProjDataInfoGeneric: public ProjDataInfoCylindrical public: //! Type used by get_all_ring_pairs_for_segment_axial_pos_num() - typedef std::vector > RingNumPairs; + typedef std::vector> RingNumPairs; //! Constructors ProjDataInfoGeneric(); @@ -67,11 +67,13 @@ class ProjDataInfoGeneric: public ProjDataInfoCylindrical \warning Most of this library assumes that segment 0 corresponds to an average ring difference of 0. */ - ProjDataInfoGeneric(const shared_ptr& scanner_ptr, - const VectorWithOffset& num_axial_poss_per_segment, //index ranges from min_segment_num to max_segment_num - const VectorWithOffset& min_ring_diff, - const VectorWithOffset& max_ring_diff, - const int num_views,const int num_tangential_poss); + ProjDataInfoGeneric( + const shared_ptr& scanner_ptr, + const VectorWithOffset& num_axial_poss_per_segment, // index ranges from min_segment_num to max_segment_num + const VectorWithOffset& min_ring_diff, + const VectorWithOffset& max_ring_diff, + const int num_views, + const int num_tangential_poss); inline float get_tantheta(const Bin&) const override; @@ -85,15 +87,13 @@ class ProjDataInfoGeneric: public ProjDataInfoCylindrical */ inline float get_m(const Bin&) const override; - void - get_LOR(LORInAxialAndNoArcCorrSinogramCoordinates& lor, const Bin& bin) const override; + void get_LOR(LORInAxialAndNoArcCorrSinogramCoordinates& lor, const Bin& bin) const override; void set_azimuthal_angle_offset(const float angle) = delete; void set_azimuthal_angle_sampling(const float angle) = delete; //! set new number of views (currently calls error() unless nothing changes) - void - set_num_views(const int new_num_views) override; + void set_num_views(const int new_num_views) override; float get_azimuthal_angle_sampling() const = delete; float get_azimuthal_angle_offset() const = delete; @@ -102,7 +102,7 @@ class ProjDataInfoGeneric: public ProjDataInfoCylindrical VectorWithOffset get_ring_radii_for_all_views() const = delete; //! return an average ring-spacing (from Scanner) - //TODOBLOCK what does this mean in a generic case? + // TODOBLOCK what does this mean in a generic case? inline float get_ring_spacing() const; inline float get_sampling_in_t(const Bin&) const override; @@ -116,13 +116,13 @@ class ProjDataInfoGeneric: public ProjDataInfoCylindrical private: //! to be used in get LOR virtual void find_cartesian_coordinates_of_detection(CartesianCoordinate3D& coord_1, - CartesianCoordinate3D& coord_2, - const Bin& bin) const = 0; + CartesianCoordinate3D& coord_2, + const Bin& bin) const = 0; + protected: CartesianCoordinate3D z_shift; }; - END_NAMESPACE_STIR #include "stir/ProjDataInfoGeneric.inl" diff --git a/src/include/stir/ProjDataInfoGeneric.inl b/src/include/stir/ProjDataInfoGeneric.inl index 4d617a80b..10ef54d21 100644 --- a/src/include/stir/ProjDataInfoGeneric.inl +++ b/src/include/stir/ProjDataInfoGeneric.inl @@ -19,7 +19,7 @@ \ingroup projdata \brief Implementation of inline functions of class stir::ProjDataInfoGeneric - + \author Sanida Mustafovic \author Kris Thielemans \author Palak Wadhwa @@ -41,47 +41,45 @@ START_NAMESPACE_STIR - //! find phi from correspoding lor float -ProjDataInfoGeneric::get_phi(const Bin& bin)const +ProjDataInfoGeneric::get_phi(const Bin& bin) const { - LORInAxialAndNoArcCorrSinogramCoordinates lor; - get_LOR(lor, bin); - return lor.phi(); + LORInAxialAndNoArcCorrSinogramCoordinates lor; + get_LOR(lor, bin); + return lor.phi(); } /*! warning In generic geometry m is calculated directly from lor while in - cylindrical geometry m is calculated using m_offset and axial_sampling + cylindrical geometry m is calculated using m_offset and axial_sampling */ float ProjDataInfoGeneric::get_m(const Bin& bin) const { - LORInAxialAndNoArcCorrSinogramCoordinates lor; - get_LOR(lor, bin); - return (static_cast(lor.z1() + lor.z2()))/2.F; + LORInAxialAndNoArcCorrSinogramCoordinates lor; + get_LOR(lor, bin); + return (static_cast(lor.z1() + lor.z2())) / 2.F; } float ProjDataInfoGeneric::get_t(const Bin& bin) const { - return - get_m(bin)*get_costheta(bin); + return get_m(bin) * get_costheta(bin); } /* - theta is copolar angle of normal to projection plane with z axis, i.e. copolar angle of lor with z axis. - tan (theta) = dz/sqrt(dx2+dy2) - cylindrical geometry: - delta_z = delta_ring * ring spacing - generic geometry: - delta_z is calculated from lor + theta is copolar angle of normal to projection plane with z axis, i.e. copolar angle of lor with z axis. + tan (theta) = dz/sqrt(dx2+dy2) + cylindrical geometry: + delta_z = delta_ring * ring spacing + generic geometry: + delta_z is calculated from lor */ float ProjDataInfoGeneric::get_tantheta(const Bin& bin) const { LORInAxialAndNoArcCorrSinogramCoordinates lor; - get_LOR(lor, bin); + get_LOR(lor, bin); return (lor.z2() - lor.z1()) / (2 * lor.radius()); } @@ -90,16 +88,18 @@ float ProjDataInfoGeneric::get_sampling_in_m(const Bin& bin) const { // TODOBLOCK - return get_scanner_ptr()->get_ring_spacing(); // TODO currently restricted to span=1 get_num_axial_poss_per_ring_inc(segment_num); - //return get_axial_sampling(bin.segment_num()); + return get_scanner_ptr() + ->get_ring_spacing(); // TODO currently restricted to span=1 get_num_axial_poss_per_ring_inc(segment_num); + // return get_axial_sampling(bin.segment_num()); } float ProjDataInfoGeneric::get_sampling_in_t(const Bin& bin) const { // TODOBLOCK - return get_scanner_ptr()->get_ring_spacing()*get_costheta(bin); // TODO currently restricted to span=1 get_num_axial_poss_per_ring_inc(segment_num); - //return get_axial_sampling(bin.segment_num())*get_costheta(bin); + return get_scanner_ptr()->get_ring_spacing() + * get_costheta(bin); // TODO currently restricted to span=1 get_num_axial_poss_per_ring_inc(segment_num); + // return get_axial_sampling(bin.segment_num())*get_costheta(bin); } float @@ -109,7 +109,8 @@ ProjDataInfoGeneric::get_axial_sampling(int segment_num) const return get_ring_spacing(); // TODO currently restricted to span=1 get_num_axial_poss_per_ring_inc(segment_num); } -bool ProjDataInfoGeneric::axial_sampling_is_uniform() const +bool +ProjDataInfoGeneric::axial_sampling_is_uniform() const { // TODOBLOCK should check sampling return true; @@ -117,7 +118,8 @@ bool ProjDataInfoGeneric::axial_sampling_is_uniform() const float ProjDataInfoGeneric::get_ring_spacing() const -{ return get_scanner_ptr()->get_ring_spacing();} - +{ + return get_scanner_ptr()->get_ring_spacing(); +} END_NAMESPACE_STIR diff --git a/src/include/stir/ProjDataInfoGenericNoArcCorr.h b/src/include/stir/ProjDataInfoGenericNoArcCorr.h index bd7fd4bf5..d312c1e71 100644 --- a/src/include/stir/ProjDataInfoGenericNoArcCorr.h +++ b/src/include/stir/ProjDataInfoGenericNoArcCorr.h @@ -14,7 +14,7 @@ \ingroup projdata \brief Declaration of class stir::ProjDataInfoGenericNoArcCorr - + \author Kris Thielemans \author Parisa Khateri \author Michael Roethlisberger @@ -22,7 +22,6 @@ #ifndef __stir_ProjDataInfoGenericNoArcCorr_H__ #define __stir_ProjDataInfoGenericNoArcCorr_H__ - #include "stir/ProjDataInfoGeneric.h" #include "stir/GeometryBlocksOnCylindrical.h" #include "stir/DetectionPositionPair.h" @@ -48,7 +47,7 @@ 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. @@ -83,11 +82,12 @@ class ProjDataInfoGenericNoArcCorr : public ProjDataInfoGeneric ProjDataInfoGenericNoArcCorr(); //! Constructor which gets geometry from the scanner - ProjDataInfoGenericNoArcCorr(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); + ProjDataInfoGenericNoArcCorr(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* clone() const override; @@ -128,10 +128,7 @@ class ProjDataInfoGenericNoArcCorr : public ProjDataInfoGeneric \see get_det_num_pair_for_view_tangential_pos_num() */ inline bool - 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; + 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; //! This routine gets \a det_num1 and \a det_num2 /*! It sets the detectors in a particular order (i.e. it fixes the @@ -147,11 +144,7 @@ class ProjDataInfoGenericNoArcCorr : public ProjDataInfoGeneric \warning Will call error() if certain conditions are not met. */ inline void - 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; + 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; //! This gets Bin coordinates for a particular detector pair /*! @@ -163,10 +156,7 @@ class ProjDataInfoGenericNoArcCorr : public ProjDataInfoGeneric \see get_view_tangential_pos_num_for_det_num_pair() for restrictions \todo use member template for the coordT type to support continuous detectors. */ - inline Succeeded - get_bin_for_det_pos_pair(Bin&, - const DetectionPositionPair<>&) const; - + inline Succeeded get_bin_for_det_pos_pair(Bin&, const DetectionPositionPair<>&) const; //! This routine gets the detector pair corresponding to a bin. /*! @@ -176,13 +166,10 @@ class ProjDataInfoGenericNoArcCorr : public ProjDataInfoGeneric \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. /*! @@ -193,11 +180,9 @@ class ProjDataInfoGenericNoArcCorr : public ProjDataInfoGeneric (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; - private: +private: // old function, now private. Use get_bin_for_det_pos_pair instead. //! This gets Bin coordinates for a particular detector pair /*! @@ -206,11 +191,9 @@ class ProjDataInfoGenericNoArcCorr : public ProjDataInfoGeneric \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; + get_bin_for_det_pair(Bin&, const int det1_num, const int ring1_num, const int det2_num, const int ring2_num) const; - public: +public: //! This routine gets the detector pair corresponding to a bin. /*! \see get_det_pair_for_view_tangential_pos_num() for @@ -218,18 +201,11 @@ class ProjDataInfoGenericNoArcCorr : public ProjDataInfoGeneric 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& det1_num, int& ring1_num, int& det2_num, int& ring2_num, const Bin&) const; //@} - - Bin - get_bin(const LOR&, const double delta_time = 0.0) const override; - + Bin get_bin(const LOR&, const double delta_time = 0.0) const override; //! \name set of obsolete functions to go between bins<->LORs (will disappear!) //@{ @@ -240,27 +216,37 @@ class ProjDataInfoGenericNoArcCorr : public ProjDataInfoGeneric */ void find_cartesian_coordinates_of_detection(CartesianCoordinate3D& coord_1, - CartesianCoordinate3D& coord_2, - const Bin& bin) const override; + CartesianCoordinate3D& coord_2, + const Bin& bin) const override; - virtual 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; + virtual 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; private: - // 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; @@ -269,8 +255,9 @@ class ProjDataInfoGenericNoArcCorr : public ProjDataInfoGeneric inline void initialise_uncompressed_view_tangpos_to_det1det2_if_not_done_yet() const; //! build look-up table unless already done before inline void initialise_det1det2_to_uncompressed_view_tangpos_if_not_done_yet() const; - protected: - bool blindly_equals(const root_type * const) const override; + +protected: + bool blindly_equals(const root_type* const) const override; }; END_NAMESPACE_STIR diff --git a/src/include/stir/ProjDataInfoGenericNoArcCorr.inl b/src/include/stir/ProjDataInfoGenericNoArcCorr.inl index 01c0ac5c8..6bddc235a 100644 --- a/src/include/stir/ProjDataInfoGenericNoArcCorr.inl +++ b/src/include/stir/ProjDataInfoGenericNoArcCorr.inl @@ -15,14 +15,13 @@ \ingroup projdata \brief Implementation of inline functions of class stir::ProjDataInfoGenericNoArcCorr - + \author Kris Thielemans \author Parisa Khateri \author Michael Roethlisberger \author Viet Ahn Dao */ - #include "stir/Bin.h" #include "stir/Succeeded.h" #include "stir/LORCoordinates.h" @@ -32,103 +31,93 @@ START_NAMESPACE_STIR void -ProjDataInfoGenericNoArcCorr:: -initialise_uncompressed_view_tangpos_to_det1det2_if_not_done_yet() const +ProjDataInfoGenericNoArcCorr::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 -ProjDataInfoGenericNoArcCorr:: -initialise_det1det2_to_uncompressed_view_tangpos_if_not_done_yet() const +ProjDataInfoGenericNoArcCorr::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(); + } } } /*! warning In cylindrical s is found from bin: sin(beta) = sin(tang_pos*angular_increment) - In block it is calculated directly from corresponding lor + In block it is calculated directly from corresponding lor */ float -ProjDataInfoGenericNoArcCorr:: -get_s(const Bin& bin) const +ProjDataInfoGenericNoArcCorr::get_s(const Bin& bin) const { LORInAxialAndNoArcCorrSinogramCoordinates lor; - get_LOR(lor, bin); + get_LOR(lor, bin); return lor.s(); } void -ProjDataInfoGenericNoArcCorr:: -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 +ProjDataInfoGenericNoArcCorr::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(); + this->initialise_uncompressed_view_tangpos_to_det1det2_if_not_done_yet(); det1_num = uncompressed_view_tangpos_to_det1det2[view_num][tang_pos_num].det1_num; det2_num = uncompressed_view_tangpos_to_det1det2[view_num][tang_pos_num].det2_num; } bool -ProjDataInfoGenericNoArcCorr:: -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 +ProjDataInfoGenericNoArcCorr::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; + 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; } Succeeded -ProjDataInfoGenericNoArcCorr:: -get_bin_for_det_pair(Bin& bin, - const int det_num1, const int ring_num1, - const int det_num2, const int ring_num2) const +ProjDataInfoGenericNoArcCorr::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)) return get_segment_axial_pos_num_for_ring_pair(bin.segment_num(), bin.axial_pos_num(), ring_num1, ring_num2); @@ -137,54 +126,37 @@ get_bin_for_det_pair(Bin& bin, } Succeeded -ProjDataInfoGenericNoArcCorr:: -get_bin_for_det_pos_pair(Bin& bin, - const DetectionPositionPair<>& dp) const +ProjDataInfoGenericNoArcCorr::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()); + return get_bin_for_det_pair( + bin, dp.pos1().tangential_coord(), dp.pos1().axial_coord(), dp.pos2().tangential_coord(), dp.pos2().axial_coord()); } void -ProjDataInfoGenericNoArcCorr:: -get_det_pair_for_bin( - int& det_num1, int& ring_num1, - int& det_num2, int& ring_num2, - const Bin& bin) const +ProjDataInfoGenericNoArcCorr::get_det_pair_for_bin( + int& det_num1, int& ring_num1, int& det_num2, int& ring_num2, const Bin& bin) const { 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()); } void -ProjDataInfoGenericNoArcCorr:: -get_det_pos_pair_for_bin( - DetectionPositionPair<>& dp, - const Bin& bin) const +ProjDataInfoGenericNoArcCorr::get_det_pos_pair_for_bin(DetectionPositionPair<>& dp, const Bin& bin) const { - //lousy work around because types don't match TODO remove! + // 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; #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 } diff --git a/src/include/stir/ProjDataInterfile.h b/src/include/stir/ProjDataInterfile.h index 9b0a040d2..5102b10bd 100644 --- a/src/include/stir/ProjDataInterfile.h +++ b/src/include/stir/ProjDataInterfile.h @@ -19,16 +19,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 @@ -40,9 +38,8 @@ START_NAMESPACE_STIR 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] @@ -51,41 +48,42 @@ 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/Radionuclide.h b/src/include/stir/Radionuclide.h index 16a88a3b9..e19ce592b 100644 --- a/src/include/stir/Radionuclide.h +++ b/src/include/stir/Radionuclide.h @@ -22,7 +22,6 @@ #include "stir/ImagingModality.h" #include "stir/info.h" - START_NAMESPACE_STIR /*! \ingroup ancillary \brief @@ -33,45 +32,41 @@ START_NAMESPACE_STIR class Radionuclide { -public: +public: //! default constructor /*! Set name to "Unknown" and other values to invalid numbers (e.g. -1) */ Radionuclide(); //! A constructor : constructs a radionuclide with all its information - Radionuclide(const std::string& name, float energy, float branching_ratio, float half_life, - ImagingModality modality); - + Radionuclide(const std::string& name, float energy, float branching_ratio, float half_life, ImagingModality modality); + //! get name (normally in DICOM format) - std::string get_name()const; + std::string get_name() const; //! get energy (in keV) /*! if \a check=\c true, calls error() if value not set (i.e. is negative)*/ - float get_energy(bool check=true) const; + float get_energy(bool check = true) const; //! get branching_ratio /*! if \a check=\c true, calls error() if value not set (i.e. is negative)*/ - float get_branching_ratio(bool check=true) const; + float get_branching_ratio(bool check = true) const; //! get half_life (in seconds) /*! if \a check=\c true, calls error() if value not set (i.e. is negative)*/ - float get_half_life(bool check=true) const; + float get_half_life(bool check = true) const; //! get modality /*! if \a check=\c true, calls error() if value not set (i.e. is unknown)*/ - ImagingModality get_modality(bool check=true) const; + ImagingModality get_modality(bool check = true) const; //! Return a string with info on parameters /*! the returned string is not intended for parsing. */ std::string parameter_info() const; - + //! comparison operators bool operator==(const Radionuclide& r) const; - -private : - + +private: std::string name; float energy; float branching_ratio; float half_life; ImagingModality modality; - - }; END_NAMESPACE_STIR diff --git a/src/include/stir/RadionuclideDB.h b/src/include/stir/RadionuclideDB.h index f6430d398..f7add69aa 100644 --- a/src/include/stir/RadionuclideDB.h +++ b/src/include/stir/RadionuclideDB.h @@ -6,7 +6,7 @@ \author Daniel Deidda \author Kris Thielemans - + */ /* Copyright (C) 2021, National Physical Laboratory @@ -17,19 +17,18 @@ #ifndef __stir_RADIONUCLIDEDB_H #define __stir_RADIONUCLIDEDB_H - #include "stir/Radionuclide.h" #include "stir/ImagingModality.h" #ifdef nlohmann_json_FOUND -#include +# include #endif /*! \ingroup ancillary \brief A class in that reads the radionuclide information from a Json file - Values for half life branching ratio are taken from: + Values for half life branching ratio are taken from: http://www.lnhb.fr/donnees-nucleaires/donnees-nucleaires-tableau/ The class also supports using "aliases" for radionuclide names. This is useful @@ -48,7 +47,7 @@ { "name": "^18^Fluorine", - "decays": [ + "decays": [ { "modality": "PET", "keV": 511, "branching_ratio": 0.9686, @@ -65,7 +64,7 @@ "half_life": 21624.12 } ] - + }, # more entries like the above ] @@ -92,7 +91,6 @@ START_NAMESPACE_STIR class RadionuclideDB { public: - //! Default constructor /*! Reads the database from radionuclide_info.json and lookup table from radionuclide_names.json, with their locations found via find_STIR_config_file(). @@ -100,7 +98,7 @@ class RadionuclideDB If STIR is compiled without nlohmann_json support, this constructor does nothing. */ RadionuclideDB(); - + //! set the radionuclide database from a JSON file /*! This function could be used to override the default database information. @@ -120,14 +118,12 @@ class RadionuclideDB used (currently only containing values for the above default radionuclides). */ Radionuclide get_radionuclide(ImagingModality rmodality, const std::string& rname); - -protected: - +protected: private: std::string database_filename; std::string radionuclide_lookup_table_filename; - + #ifdef nlohmann_json_FOUND nlohmann::json radionuclide_json; #endif @@ -140,7 +136,7 @@ class RadionuclideDB a default constructed Radionuclide() object (i.e. unknown). */ Radionuclide get_radionuclide_from_json(ImagingModality rmodality, const std::string& rname) const; - + //! Convert the radionuclide name using the lookup table /*! If \a rname is empty, return \c "default". Otherwise, attempt to find it in the lookup table and translate it. diff --git a/src/include/stir/RegisteredObject.h b/src/include/stir/RegisteredObject.h index 1ad307917..ea533d33e 100644 --- a/src/include/stir/RegisteredObject.h +++ b/src/include/stir/RegisteredObject.h @@ -28,8 +28,6 @@ START_NAMESPACE_STIR - - /*! \brief Helper class to provide registry mechanisms to a \c Base class \ingroup buildblock @@ -37,18 +35,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. @@ -80,14 +78,14 @@ 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. - \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 @@ -100,15 +98,16 @@ class RegisteredObject : public RegisteredObjectBase 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 @@ -120,10 +119,9 @@ 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; @@ -133,12 +131,9 @@ class RegisteredObject : public RegisteredObjectBase RegisteredObject will need explicit instantiations for all derived classes. */ inline 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 8b879638b..d9ab0b346 100644 --- a/src/include/stir/RegisteredObject.inl +++ b/src/include/stir/RegisteredObject.inl @@ -22,16 +22,15 @@ #include "stir/utilities.h" #include -START_NAMESPACE_STIR +START_NAMESPACE_STIR template RegisteredObject::RegisteredObject() {} - template -typename RegisteredObject::RegistryType& -RegisteredObject::registry () +typename RegisteredObject::RegistryType& +RegisteredObject::registry() { static RegistryType the_registry("None", 0); return the_registry; @@ -42,7 +41,7 @@ Root* 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 @@ -54,14 +53,12 @@ RegisteredObject::ask_type_and_parameters() 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 aaa3c84f4..1fb76ee1b 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 - + */ /* @@ -24,11 +24,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. @@ -49,8 +49,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 ff6e3289c..03cd283dd 100644 --- a/src/include/stir/RegisteredParsingObject.h +++ b/src/include/stir/RegisteredParsingObject.h @@ -21,7 +21,6 @@ #ifndef __stir_RegisteredParsingObject_H__ #define __stir_RegisteredParsingObject_H__ - #include "stir/ParsingObject.h" #include @@ -31,7 +30,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. @@ -49,7 +48,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 @@ -64,7 +63,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 @@ -79,14 +78,14 @@ 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 override; @@ -94,20 +93,19 @@ inline static Base* read_from_stream(std::istream*); inline std::string parameter_info() override; public: - //! A helper class to allow automatic registration. 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) +RegisteredParsingObject::read_from_stream(std::istream* in) { - Derived * der_ptr = new Derived; + Derived* der_ptr = new Derived; if (in != NULL) - { - if(der_ptr->parse(*in)==false) { - //parsing failed, return 0 pointer - delete der_ptr; - return 0; + if (der_ptr->parse(*in) == false) + { + // parsing failed, return 0 pointer + delete der_ptr; + return 0; + } } - } else der_ptr->ask_parameters(); return der_ptr; @@ -46,7 +48,7 @@ RegisteredParsingObject::read_from_stream(std::istream* in) 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 f6c632db9..199944c92 100644 --- a/src/include/stir/RelatedViewgrams.h +++ b/src/include/stir/RelatedViewgrams.h @@ -32,10 +32,8 @@ 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 @@ -43,7 +41,7 @@ class RelatedViewgrams { private: #ifdef SWIG -public: +public: #endif typedef RelatedViewgrams self_type; @@ -57,24 +55,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 --- @@ -104,10 +100,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; @@ -116,58 +111,53 @@ class RelatedViewgrams //! Grow each viewgram void grow(const IndexRange<2>& range); - //TODOvoid zoom(const float zoom, const float Xoffp, const float Yoffp, - // const int size, const float itophi); - - + // 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 //@{ @@ -175,34 +165,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 @@ -211,13 +197,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 b3adeeb8f..887518188 100644 --- a/src/include/stir/RelatedViewgrams.inl +++ b/src/include/stir/RelatedViewgrams.inl @@ -25,21 +25,23 @@ START_NAMESPACE_STIR template -RelatedViewgrams::RelatedViewgrams() : - viewgrams(), symmetries_used() - {} - +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(); - } +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 +void +RelatedViewgrams::check_state() const { #ifndef NDEBUG debug_check_state(); @@ -47,115 +49,121 @@ void RelatedViewgrams::check_state() const } 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 +int +RelatedViewgrams::get_basic_view_num() const { - assert(viewgrams.size()>0); + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_view_num(); } template -int RelatedViewgrams::get_basic_segment_num() const +int +RelatedViewgrams::get_basic_segment_num() const { - assert(viewgrams.size()>0); + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_segment_num(); } template -int RelatedViewgrams::get_basic_timing_pos_num() const +int +RelatedViewgrams::get_basic_timing_pos_num() const { - assert(viewgrams.size()>0); + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_timing_pos_num(); } template ViewgramIndices -RelatedViewgrams:: -get_basic_viewgram_indices() const +RelatedViewgrams::get_basic_viewgram_indices() const { - assert(viewgrams.size()>0); + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_viewgram_indices(); } template ViewgramIndices -RelatedViewgrams:: -get_basic_view_segment_num() const +RelatedViewgrams::get_basic_view_segment_num() const { return this->get_basic_viewgram_indices(); } template -int RelatedViewgrams::get_num_axial_poss() const +int +RelatedViewgrams::get_num_axial_poss() const { - assert(viewgrams.size()>0); + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_num_axial_poss(); } template -int RelatedViewgrams::get_num_tangential_poss() const +int +RelatedViewgrams::get_num_tangential_poss() const { - assert(viewgrams.size()>0); + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_num_tangential_poss(); } template -int RelatedViewgrams::get_min_axial_pos_num() const +int +RelatedViewgrams::get_min_axial_pos_num() const { - assert(viewgrams.size()>0); + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_min_axial_pos_num(); } template -int RelatedViewgrams::get_max_axial_pos_num() const +int +RelatedViewgrams::get_max_axial_pos_num() const { - assert(viewgrams.size()>0); + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_max_axial_pos_num(); } template -int RelatedViewgrams::get_min_tangential_pos_num() const +int +RelatedViewgrams::get_min_tangential_pos_num() const { - assert(viewgrams.size()>0); + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_min_tangential_pos_num(); } template -int RelatedViewgrams::get_max_tangential_pos_num() const +int +RelatedViewgrams::get_max_tangential_pos_num() const { - assert(viewgrams.size()>0); + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_max_tangential_pos_num(); } template shared_ptr -RelatedViewgrams:: -get_proj_data_info_sptr() const +RelatedViewgrams::get_proj_data_info_sptr() const { - assert(viewgrams.size()>0); + assert(viewgrams.size() > 0); check_state(); return viewgrams[0].get_proj_data_info_sptr(); } template -const DataSymmetriesForViewSegmentNumbers * +const DataSymmetriesForViewSegmentNumbers* RelatedViewgrams::get_symmetries_ptr() const { return symmetries_used.get(); @@ -169,24 +177,31 @@ RelatedViewgrams::get_symmetries_sptr() const } template -typename RelatedViewgrams::iterator +typename RelatedViewgrams::iterator RelatedViewgrams::begin() -{ return viewgrams.begin();} +{ + return viewgrams.begin(); +} template -typename RelatedViewgrams::iterator +typename RelatedViewgrams::iterator RelatedViewgrams::end() -{return viewgrams.end();} +{ + return viewgrams.end(); +} template -typename RelatedViewgrams::const_iterator +typename RelatedViewgrams::const_iterator RelatedViewgrams::begin() const -{return viewgrams.begin();} +{ + return viewgrams.begin(); +} template -typename RelatedViewgrams::const_iterator +typename RelatedViewgrams::const_iterator RelatedViewgrams::end() const -{return viewgrams.end();} - +{ + return viewgrams.end(); +} END_NAMESPACE_STIR diff --git a/src/include/stir/RunTests.h b/src/include/stir/RunTests.h index c82ca7442..8d6707bca 100644 --- a/src/include/stir/RunTests.h +++ b/src/include/stir/RunTests.h @@ -11,9 +11,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup test - \ingroup buildblock + \ingroup buildblock \brief defines the stir::RunTests class \author Nikos Efthimiou @@ -53,15 +53,15 @@ 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 @@ -71,7 +71,7 @@ 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(); @@ -79,23 +79,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 = ""); @@ -120,93 +120,89 @@ class RunTests bool check_if_equal(const unsigned long long a, const unsigned long long b, const std::string& str = ""); #endif bool check_if_equal(const Bin& a, const Bin& b, const std::string& str = "") - { return this->check_if_equal_generic(a,b,str);} + { + return this->check_if_equal_generic(a, b, str); + } template bool check_if_equal(const DetectionPosition& a, const DetectionPosition& b, const std::string& str = "") - { return this->check_if_equal_generic(a,b,str);} + { + return this->check_if_equal_generic(a, b, str); + } // 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 = "") + 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)) + if (t1.get_min_index() != t2.get_min_index() || t1.get_max_index() != t2.get_max_index()) { - std::cerr << "(at VectorWithOffset<" << typeid(T).name() << "> first mismatch at index " << i << ")\n"; + 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)) + { + std::cerr << "(at VectorWithOffset<" << typeid(T).name() << "> first mismatch at index " << i << ")\n"; + return everything_ok = false; + } + } return true; } // 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 = "") + 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; - } + { + 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++) { - std::cerr << "(at vector<" << typeid(T).name() << "> mismatch at index " << i << ")\n"; - all_equal=false; + if (!check_if_equal(t1[i], t2[i], str)) + { + std::cerr << "(at vector<" << typeid(T).name() << "> mismatch at index " << i << ")\n"; + 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 = "") + 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; - } + { + std::cerr << "Error: unequal ranges. " << str << std::endl; + return everything_ok = false; + } 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; - everything_ok = false; - return false; - } + 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 return true; } @@ -232,30 +228,29 @@ 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++) { - std::cerr << "(at VectorWithOffset<" << typeid(T).name() << "> first mismatch at index " << i << ")\n"; - return false; + 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 = "" ) + 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; - } + { + std::cerr << "Error : Coordinate value is " << a << " expected 0s. " << str << std::endl; + everything_ok = false; + return false; + } else return true; } @@ -263,7 +258,7 @@ class RunTests //! 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 @@ -272,52 +267,48 @@ 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) + : tolerance(tolerance), + everything_ok(true) {} RunTests::~RunTests() { #if defined(_DEBUG) && defined(__MSL__) DebugNewReportLeaks(); -#endif +#endif if (everything_ok) std::cerr << "\nAll tests ok !\n\n" << std::endl; @@ -325,33 +316,46 @@ 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) +bool +RunTests::check(const bool result, const std::string& str) { if (!result) - { - std::cerr << "Error. " << str << std::endl; - everything_ok = false; - } + { + std::cerr << "Error. " << str << std::endl; + everything_ok = false; + } return result; } bool RunTests::check_if_equal(const std::string& a, const std::string& b, const std::string& str) -{ return this->check_if_equal_generic(a,b,str);} +{ + return this->check_if_equal_generic(a, b, str); +} /*! tolerance is used to account for floating point rounding error. First the absolute difference * is checked and afterwards the relative. @@ -370,89 +374,134 @@ RunTests::check_if_equal(const std::string& a, const std::string& b, const std:: 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; + 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; - everything_ok = false; - return false; - } + if (diff > tolerance * largest) + { + std::cerr << "Error : unequal values are " << a << " and " << b << ". " << str << std::endl; + everything_ok = false; + return false; + } 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 ) +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; - } + { + std::cerr << "Error : 0 value is " << a << " ." << str << std::endl; + everything_ok = false; + return false; + } else return true; } - template bool - RunTests::check_if_less(T1 a, T2 b, const std::string& str) +RunTests::check_if_less(T1 a, T2 b, const std::string& str) { - if (a>=b) + if (a >= b) { - std::cerr << "Error : " << a << " is larger than " << b << ", " << str<< std::endl; + 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 4c9a15578..095bd6d8c 100644 --- a/src/include/stir/SSRB.h +++ b/src/include/stir/SSRB.h @@ -35,7 +35,7 @@ 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). @@ -43,55 +43,53 @@ class ProjDataInfo; Default value -1 means 'do all segments'. \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. @@ -103,37 +101,30 @@ 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 \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 - ); +*/ +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 d5f0ab2bc..79c8cbde8 100644 --- a/src/include/stir/Scanner.h +++ b/src/include/stir/Scanner.h @@ -59,13 +59,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 @@ -80,11 +80,11 @@ 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. @@ -100,21 +100,20 @@ class Succeeded; \warning You have to call set_up() after using the \c set_* functions (except set_params()). - \todo + \todo a hierarchy distinguishing between different types of scanners \todo derive from ParsingObject */ -class Scanner +class Scanner { - friend class BlocksTests; - - public: + friend class BlocksTests; - /************* static members*****************************/ - static Scanner * ask_parameters(); +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 a string listing names for all predefined scanners /* \return a string with one line per predefined scanner, listing the predefined names for that scanner (separated by a comma) @@ -134,37 +133,81 @@ 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, test_scanner, Siemens_mMR,Siemens_mCT, Siemens_Vision_600, RPT,HiDAC, - Advance, DiscoveryLS, DiscoveryST, DiscoverySTE, DiscoveryRX, Discovery600, PETMR_Signa, - Discovery690, DiscoveryMI3ring, DiscoveryMI4ring, DiscoveryMI5ring, - HZLR, RATPET, PANDA, HYPERimage, nanoPET, HRRT, Allegro, GeminiTF, SAFIRDualRingPrototype, UPENN_5rings, UPENN_5rings_no_gaps, UPENN_6rings, UPENN_6rings_no_gaps, - User_defined_scanner, - Unknown_scanner}; + enum Type + { + E931, + E951, + E953, + E921, + E925, + E961, + E962, + E966, + E1080, + test_scanner, + Siemens_mMR, + Siemens_mCT, + Siemens_Vision_600, + RPT, + HiDAC, + Advance, + DiscoveryLS, + DiscoveryST, + DiscoverySTE, + DiscoveryRX, + Discovery600, + PETMR_Signa, + Discovery690, + DiscoveryMI3ring, + DiscoveryMI4ring, + DiscoveryMI5ring, + HZLR, + RATPET, + PANDA, + HYPERimage, + nanoPET, + HRRT, + Allegro, + GeminiTF, + SAFIRDualRingPrototype, + UPENN_5rings, + UPENN_5rings_no_gaps, + UPENN_6rings, + UPENN_6rings_no_gaps, + User_defined_scanner, + Unknown_scanner + }; virtual ~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_intrinsic_azimuthal_tilt() \param scanner_geometry_v \see set_scanner_geometry() \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, + 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, + 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, @@ -178,7 +221,7 @@ class Scanner float transaxial_crystal_spacing_v = -1.0f, float axial_block_spacing_v = -1.0f, float transaxial_block_spacing_v = -1.0f, - const std::string& crystal_map_file_name = ""); + const std::string& crystal_map_file_name = ""); //! constructor ( a single name) /*! size info is in mm @@ -186,14 +229,21 @@ class Scanner \param scanner_geometry_v \see set_scanner_geometry() \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, + 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, + 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, @@ -225,12 +275,12 @@ 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? */ @@ -256,7 +306,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; @@ -271,7 +321,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; @@ -287,25 +337,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; @@ -319,7 +369,7 @@ 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. + //! Get the maximum number of TOF bins. /*! \return will be 0 or negative if not known */ inline int get_max_num_timing_poss() const; //! Get the size for one (unmashed) TOF bin in picoseconds @@ -339,7 +389,7 @@ class Scanner This is often written as \f$2\tau\f$ and is usually around 4000ps. It is determined from \c get_max_num_timing_poss() and \c get_size_of_timing_pos(). - \warning This is currently not known yet for many non-TOF scanners. The function will + \warning This is currently not known yet for many non-TOF scanners. The function will then throw an error. */ float get_coincidence_window_width_in_ps() const; @@ -354,7 +404,7 @@ class Scanner You have to call set_up() after using the \c set_* functions. */ - //@{! + //@{! 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); @@ -375,21 +425,21 @@ class Scanner //! get block spacing in transaxial direction inline float get_transaxial_block_spacing() const; //@} (end of get block geometry info) - + //! \name functions to get generic geometry info //! get crystal map file name inline std::string get_crystal_map_file_name() const; - + //@} (end of block/bucket info) //@} (end of get geometrical info) - //! \name Functions to get detector response info + //! \name Functions to get detector response info //@{ //! get the energy resolution as a fraction at the reference energy /*! Values for PET scanners are around 0.1 at 511 keV, depending on the scanner of course. - + If less than or equal to 0, it is assumed to be unknown. */ inline float get_energy_resolution() const; @@ -409,48 +459,48 @@ 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_intrinsic_azimuthal_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. //@{ //! name functions to set block geometry info //! set scanner geometry - /*! + /*! \param new_scanner_geometry: "Cylindrical", "BlocksOnCylindrical" or "Generic" - + Will also read the detector map from file if the geometry is \c "Generic". \warning you need to call set_up() after calling this function. @@ -458,13 +508,13 @@ class Scanner */ void set_scanner_geometry(const std::string& new_scanner_geometry); //! set crystal spacing in axial direction - inline void set_axial_crystal_spacing(const float & new_spacing); + inline void set_axial_crystal_spacing(const float& new_spacing); //! set crystal spacing in transaxial direction - inline void set_transaxial_crystal_spacing(const float & new_spacing); + inline void set_transaxial_crystal_spacing(const float& new_spacing); //! set block spacing in axial direction - inline void set_axial_block_spacing(const float & new_spacing); + inline void set_axial_block_spacing(const float& new_spacing); //! set block spacing in transaxial direction - inline void set_transaxial_block_spacing(const float & new_spacing); + inline void set_transaxial_block_spacing(const float& new_spacing); //! set crystal map file name for the generic geometry /*! \warning, data is not read yet. use set_scanner_geometry() after calling this function */ inline void set_crystal_map_file_name(const std::string& new_crystal_map_file_name); @@ -486,14 +536,13 @@ class Scanner //@} (end of set info) //@} (end of set info) - + //! 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; - + inline int get_singles_bin_index(const DetectionPosition<>& det_pos) const; //! Get the axial singles bin coordinate from a singles bin. inline int get_axial_singles_unit(int singles_bin_index) const; @@ -503,10 +552,10 @@ class Scanner //! True if it is TOF compatible. inline bool is_tof_ready() const; - + //! Get the STIR detection position (det#, ring#, layer#) given the detection position id in the input crystal map // used in CListRecordSAFIR.inl for accessing the coordinates - inline stir::DetectionPosition<> get_det_pos_for_index(const stir::DetectionPosition<> & det_pos) const; + inline stir::DetectionPosition<> get_det_pos_for_index(const stir::DetectionPosition<>& det_pos) const; //! Get the Cartesian coordinates (x,y,z) given the STIR detection position (det#, ring#, layer#) // used in ProjInfoDataGenericNoArcCorr.cxx for accessing the coordinates inline stir::CartesianCoordinate3D get_coordinate_for_det_pos(const stir::DetectionPosition<>& det_pos) const; @@ -514,39 +563,37 @@ class Scanner inline stir::CartesianCoordinate3D get_coordinate_for_index(const stir::DetectionPosition<>& det_pos) const; //! Find detection position at a coordinate // used in ProjInfoDataGenericNoArcCorr.cxx for accessing the get_bin - inline Succeeded - find_detection_position_given_cartesian_coordinate(DetectionPosition<>& det_pos, - const CartesianCoordinate3D& cart_coord) const; + inline Succeeded find_detection_position_given_cartesian_coordinate(DetectionPosition<>& det_pos, + const CartesianCoordinate3D& cart_coord) const; - shared_ptr get_detector_map_sptr() const - { return detector_map_sptr; } + shared_ptr get_detector_map_sptr() const { return detector_map_sptr; } private: bool _already_setup; 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 max_FOV_radius; /*! detector maximum radius in mm - for cylindrical scanner identical to inner radius */ - 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 max_FOV_radius; /*! detector maximum radius in mm - for cylindrical scanner identical to inner radius */ + 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 (FWHM as a fraction of the reference_energy) //! \details This is the energy resolution of the system. //! A negative value indicates, unknown. @@ -566,23 +613,24 @@ class Scanner //! \brief scanner info needed for block geometry //! \author Parisa Khateri //! A negative value indicates unknown. - std::string scanner_geometry; /*! scanner geometry */ - float axial_crystal_spacing; /*! crystal pitch in axial direction in mm*/ - float transaxial_crystal_spacing; /*! crystal pitch in transaxial direction in mm*/ - float axial_block_spacing; /*! block pitch in axial direction in mm*/ - float transaxial_block_spacing; /*! block pitch in transaxial direction in mm*/ - + std::string scanner_geometry; /*! scanner geometry */ + float axial_crystal_spacing; /*! crystal pitch in axial direction in mm*/ + float transaxial_crystal_spacing; /*! crystal pitch in transaxial direction in mm*/ + float axial_block_spacing; /*! block pitch in axial direction in mm*/ + float transaxial_block_spacing; /*! block pitch in transaxial direction in mm*/ + std::string crystal_map_file_name; - shared_ptr detector_map_sptr; /*! effective detection positions including average DOI */ + shared_ptr detector_map_sptr; /*! effective detection positions including average DOI */ - void set_detector_map( const DetectorCoordinateMap::det_pos_to_coord_type& coord_map ); + void set_detector_map(const DetectorCoordinateMap::det_pos_to_coord_type& coord_map); void initialise_max_FOV_radius(); // function to create the maps - void read_detectormap_from_file( const std::string& filename ); + void read_detectormap_from_file(const std::string& filename); // ! set all parameters - void set_params(Type type_v, const std::list& list_of_names_v, + 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, @@ -590,9 +638,12 @@ class Scanner 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, + 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, @@ -607,7 +658,6 @@ class Scanner float axial_block_spacing_v = -1.0f, float transaxial_block_spacing_v = -1.0f, const std::string& crystal_map_file_name = ""); - }; END_NAMESPACE_STIR @@ -615,4 +665,3 @@ END_NAMESPACE_STIR #include "stir/Scanner.inl" #endif - diff --git a/src/include/stir/Scanner.inl b/src/include/stir/Scanner.inl index 97aa66fc3..874f97e45 100644 --- a/src/include/stir/Scanner.inl +++ b/src/include/stir/Scanner.inl @@ -30,40 +30,49 @@ 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;} +{ + return type; +} int Scanner::get_num_rings() const -{ return num_rings;} +{ + return num_rings; +} int Scanner::get_num_detectors_per_ring() const { - return num_detectors_per_ring;} + return num_detectors_per_ring; +} int Scanner::get_max_num_non_arccorrected_bins() const -{ return max_num_non_arccorrected_bins;} +{ + return max_num_non_arccorrected_bins; +} -int +int Scanner::get_max_num_views() const -{ return get_num_detectors_per_ring()/2; } +{ + return get_num_detectors_per_ring() / 2; +} int Scanner::get_default_num_arccorrected_bins() const { - return default_num_arccorrected_bins; + return default_num_arccorrected_bins; } float Scanner::get_inner_ring_radius() const -{ +{ return inner_ring_radius; } @@ -79,24 +88,23 @@ Scanner::get_average_depth_of_interaction() const return average_depth_of_interaction; } - float Scanner::get_effective_ring_radius() const { return inner_ring_radius + average_depth_of_interaction; } - float Scanner::get_ring_spacing() const { return ring_spacing; } - float Scanner::get_default_bin_size() const -{ return bin_size;} +{ + return bin_size; +} float Scanner::get_intrinsic_azimuthal_tilt() const @@ -108,9 +116,9 @@ Scanner::get_intrinsic_azimuthal_tilt() const #endif } -int +int Scanner::get_num_transaxial_blocks_per_bucket() const -{ +{ return num_transaxial_blocks_per_bucket; } @@ -127,27 +135,21 @@ Scanner::get_num_axial_crystals_per_block() const } 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(); + 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(); + return get_num_transaxial_blocks_per_bucket() * get_num_transaxial_crystals_per_block(); } int @@ -161,29 +163,27 @@ 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; + 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; + 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; + return get_num_transaxial_blocks() / num_transaxial_blocks_per_bucket; } - - int Scanner::get_num_axial_crystals_per_singles_unit() const { @@ -196,31 +196,34 @@ 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 ) { - return 0; - } else { - return (num_rings+get_num_virtual_axial_crystals_per_block()) / num_axial_crystals_per_singles_unit; - } + 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; + } } - int 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; - } + 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(); @@ -229,35 +232,37 @@ Scanner::get_num_singles_units () const float Scanner::get_energy_resolution() const { - return energy_resolution; + return energy_resolution; } float Scanner::get_reference_energy() const { - return reference_energy; + return reference_energy; } -int Scanner::get_max_num_timing_poss() const +int +Scanner::get_max_num_timing_poss() const { - return max_num_of_timing_poss; + return max_num_of_timing_poss; } -float Scanner::get_size_of_timing_pos() const +float +Scanner::get_size_of_timing_pos() const { - return size_timing_pos; + return size_timing_pos; } -float Scanner::get_timing_resolution() const +float +Scanner::get_timing_resolution() const { - return timing_resolution; + return timing_resolution; } -bool Scanner::is_tof_ready() const +bool +Scanner::is_tof_ready() const { - return (max_num_of_timing_poss > 0 - && size_timing_pos > 0.0f - && timing_resolution > 0.0f); + return (max_num_of_timing_poss > 0 && size_timing_pos > 0.0f && timing_resolution > 0.0f); } std::string @@ -269,25 +274,25 @@ Scanner::get_scanner_geometry() const float Scanner::get_axial_crystal_spacing() const { - return axial_crystal_spacing; + return axial_crystal_spacing; } float Scanner::get_transaxial_crystal_spacing() const { - return transaxial_crystal_spacing; + return transaxial_crystal_spacing; } float Scanner::get_transaxial_block_spacing() const { - return transaxial_block_spacing; + return transaxial_block_spacing; } float Scanner::get_axial_block_spacing() const { - return axial_block_spacing; + return axial_block_spacing; } std::string @@ -298,231 +303,247 @@ Scanner::get_crystal_map_file_name() const //************************ set ******************************8 -void Scanner::set_type(const Type & new_type) +void +Scanner::set_type(const Type& new_type) { - type = new_type; - _already_setup = false; + type = new_type; + _already_setup = false; } -void Scanner::set_num_rings(const int & new_num) +void +Scanner::set_num_rings(const int& new_num) { num_rings = new_num; - _already_setup = false; + _already_setup = false; } - -void Scanner::set_num_detectors_per_ring(const int & new_num) + +void +Scanner::set_num_detectors_per_ring(const int& new_num) { - num_detectors_per_ring = new_num; - _already_setup = false; + num_detectors_per_ring = new_num; + _already_setup = false; } -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; - _already_setup = false; + _already_setup = false; } -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; - _already_setup = false; + _already_setup = false; } - -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; - _already_setup = false; + _already_setup = false; } -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; - _already_setup = false; + _already_setup = false; } -bool Scanner::has_energy_information() const +bool +Scanner::has_energy_information() const { - return (energy_resolution <= 0.0 || - reference_energy <= 0.0) ? false : true; + 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; - _already_setup = false; + _already_setup = false; } -void Scanner::set_intrinsic_azimuthal_tilt(const float new_tilt) +void +Scanner::set_intrinsic_azimuthal_tilt(const float new_tilt) { intrinsic_tilt = new_tilt; - _already_setup = false; + _already_setup = false; } -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; - _already_setup = false; + _already_setup = false; } -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; - _already_setup = false; + _already_setup = false; } -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; - _already_setup = false; + _already_setup = false; } - -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; - _already_setup = false; + _already_setup = false; } -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; - _already_setup = false; + _already_setup = false; } - - -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; - _already_setup = false; + _already_setup = false; } -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; - _already_setup = false; + _already_setup = false; } void Scanner::set_energy_resolution(const float new_num) { - energy_resolution = new_num; - _already_setup = false; + energy_resolution = new_num; + _already_setup = false; } void Scanner::set_reference_energy(const float new_num) { - reference_energy = new_num; - _already_setup = false; + reference_energy = new_num; + _already_setup = false; } -void Scanner::set_axial_crystal_spacing(const float& new_spacing) +void +Scanner::set_axial_crystal_spacing(const float& new_spacing) { axial_crystal_spacing = new_spacing; - _already_setup = false; + _already_setup = false; } -void Scanner::set_transaxial_crystal_spacing(const float& new_spacing) +void +Scanner::set_transaxial_crystal_spacing(const float& new_spacing) { transaxial_crystal_spacing = new_spacing; - _already_setup = false; + _already_setup = false; } -void Scanner::set_transaxial_block_spacing(const float& new_spacing) +void +Scanner::set_transaxial_block_spacing(const float& new_spacing) { transaxial_block_spacing = new_spacing; - _already_setup = false; + _already_setup = false; } -void Scanner::set_axial_block_spacing(const float& new_spacing) +void +Scanner::set_axial_block_spacing(const float& new_spacing) { axial_block_spacing = new_spacing; - _already_setup = false; + _already_setup = false; } -void Scanner::set_crystal_map_file_name(const std::string& new_crystal_map_file_name) +void +Scanner::set_crystal_map_file_name(const std::string& new_crystal_map_file_name) { crystal_map_file_name = new_crystal_map_file_name; - _already_setup = false; + _already_setup = false; } -void Scanner::set_max_num_timing_poss(const int new_num) +void +Scanner::set_max_num_timing_poss(const int new_num) { - max_num_of_timing_poss = new_num; - _already_setup = false; + max_num_of_timing_poss = new_num; + _already_setup = false; } -void Scanner::set_size_of_timing_poss(const float new_num) +void +Scanner::set_size_of_timing_poss(const float new_num) { - size_timing_pos = new_num; - _already_setup = false; + size_timing_pos = new_num; + _already_setup = false; } -void Scanner::set_timing_resolution(const float new_num_in_ps) +void +Scanner::set_timing_resolution(const float new_num_in_ps) { - timing_resolution = new_num_in_ps; - _already_setup = false; + timing_resolution = new_num_in_ps; + _already_setup = false; } /******** Calculate singles bin index from detection position *********/ - int -Scanner::get_singles_bin_index(int axial_index, int transaxial_index) const { +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 { +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 -Scanner::get_axial_singles_unit(int singles_bin_index) const { +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 -Scanner::get_transaxial_singles_unit(int singles_bin_index) const { +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()); } // For retrieving the coordinates / detector, ring id from the scanner stir::DetectionPosition<> -Scanner::get_det_pos_for_index(const stir::DetectionPosition<> & det_pos) const +Scanner::get_det_pos_for_index(const stir::DetectionPosition<>& det_pos) const { - if (!detector_map_sptr) - stir::error("Scanner: detector_map not defined. Did you run set_up()?"); + if (!detector_map_sptr) + stir::error("Scanner: detector_map not defined. Did you run set_up()?"); - return detector_map_sptr->get_det_pos_for_index(det_pos); + return detector_map_sptr->get_det_pos_for_index(det_pos); } stir::CartesianCoordinate3D @@ -560,4 +581,3 @@ Scanner::find_detection_position_given_cartesian_coordinate(DetectionPosition<>& } END_NAMESPACE_STIR - diff --git a/src/include/stir/Segment.h b/src/include/stir/Segment.h index fd6ffe260..a1cdc4d88 100644 --- a/src/include/stir/Segment.h +++ b/src/include/stir/Segment.h @@ -20,17 +20,17 @@ #ifndef __Segment_H__ #define __Segment_H__ - -#include "stir/ProjDataInfo.h" +#include "stir/ProjDataInfo.h" #include "stir/SegmentIndices.h" #include "stir/SinogramIndices.h" #include "stir/ViewgramIndices.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 @@ -42,10 +42,10 @@ 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 { @@ -54,14 +54,18 @@ class Segment public: #endif typedef Segment self_type; + public: - - enum StorageOrder{ StorageByView, StorageBySino }; - - virtual ~Segment() {} + 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; inline SegmentIndices get_segment_indices() const; @@ -73,12 +77,12 @@ class Segment 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; @@ -93,7 +97,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; @@ -103,32 +107,29 @@ 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; SegmentIndices _indices; - - inline Segment(const shared_ptr& proj_data_info_sptr_v,const SegmentIndices&); + + inline Segment(const shared_ptr& proj_data_info_sptr_v, const SegmentIndices&); }; END_NAMESPACE_STIR @@ -136,5 +137,3 @@ END_NAMESPACE_STIR #include "stir/Segment.inl" #endif - - diff --git a/src/include/stir/Segment.inl b/src/include/stir/Segment.inl index bc1f3958e..3f6cfd837 100644 --- a/src/include/stir/Segment.inl +++ b/src/include/stir/Segment.inl @@ -25,27 +25,31 @@ START_NAMESPACE_STIR template -Segment:: -Segment( const shared_ptr& proj_data_info_sptr_v,const SegmentIndices& ind) - : - proj_data_info_sptr(proj_data_info_sptr_v), - _indices(ind) - {} +Segment::Segment(const shared_ptr& proj_data_info_sptr_v, const SegmentIndices& ind) + : proj_data_info_sptr(proj_data_info_sptr_v), + _indices(ind) +{} template SegmentIndices -Segment:: get_segment_indices() const -{ return _indices; } +Segment::get_segment_indices() const +{ + return _indices; +} template int -Segment:: get_segment_num() const -{ return _indices.segment_num(); } +Segment::get_segment_num() const +{ + return _indices.segment_num(); +} template int -Segment:: get_timing_pos_num() const -{ return _indices.timing_pos_num(); } +Segment::get_timing_pos_num() const +{ + return _indices.timing_pos_num(); +} template shared_ptr diff --git a/src/include/stir/SegmentBySinogram.h b/src/include/stir/SegmentBySinogram.h index 3a949a171..602e66c49 100644 --- a/src/include/stir/SegmentBySinogram.h +++ b/src/include/stir/SegmentBySinogram.h @@ -19,7 +19,7 @@ \author Sanida Mustafovic \author Kris Thielemans - \author Claire Labbe + \author Claire Labbe \author PARAPET project @@ -33,9 +33,9 @@ START_NAMESPACE_STIR -//forward declaration for use in convertion -template class SegmentByView; - +// forward declaration for use in convertion +template +class SegmentByView; /*! \ingroup projdata @@ -44,10 +44,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; @@ -57,33 +57,33 @@ 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 SegmentIndices& ind); + SegmentBySinogram(const Array<3, elemT>& v, + const shared_ptr& proj_data_info_ptr_v, + const SegmentIndices& ind); //! Constructor that sets sizes via the ProjDataInfo object, initialising data to 0 - SegmentBySinogram(const shared_ptr& proj_data_info_ptr_v, - const SegmentIndices& ind); + SegmentBySinogram(const shared_ptr& proj_data_info_ptr_v, const SegmentIndices& ind); //! Constructor that sets the data to a given 3d Array /*! \deprecated Use version with SegmentIndices instead */ - SegmentBySinogram(const Array<3,elemT>& v, - const shared_ptr& proj_data_info_ptr_v, - const int segment_num, const int timing_pos_num = 0); - + 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 /*! \deprecated Use version with SegmentIndices instead */ SegmentBySinogram(const shared_ptr& proj_data_info_ptr_v, - const int segment_num, const int timing_pos_num = 0); + 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 override; //! Get number of axial positions inline int get_num_axial_poss() const override; @@ -100,9 +100,9 @@ class SegmentBySinogram : public Segment, public Array<3,elemT> //! Get maximum view number inline int get_max_view_num() const override; //! Get minimum tangetial position number - inline int get_min_tangential_pos_num() const override; + inline int get_min_tangential_pos_num() const override; //! Get maximum tangential position number - inline int get_max_tangential_pos_num() const override; + inline int get_max_tangential_pos_num() const override; using Segment::get_sinogram; using Segment::get_viewgram; //! Get sinogram @@ -112,7 +112,7 @@ class SegmentBySinogram : public Segment, public Array<3,elemT> //! Set viewgram void set_viewgram(const Viewgram&) override; //! Set sinogram - inline void set_sinogram(Sinogram const &s, int axial_pos_num) override; + inline void set_sinogram(Sinogram const& s, int axial_pos_num) override; inline void set_sinogram(const Sinogram& s) override; //! Overloading Array::grow @@ -120,7 +120,7 @@ class SegmentBySinogram : public Segment, public Array<3,elemT> //! Overloading Array::resize void resize(const IndexRange<3>& range) override; - bool operator ==(const Segment&) const override; + bool operator==(const Segment&) const override; }; END_NAMESPACE_STIR diff --git a/src/include/stir/SegmentBySinogram.inl b/src/include/stir/SegmentBySinogram.inl index 3b6e128a2..637a1b217 100644 --- a/src/include/stir/SegmentBySinogram.inl +++ b/src/include/stir/SegmentBySinogram.inl @@ -28,10 +28,10 @@ START_NAMESPACE_STIR template -int -SegmentBySinogram ::get_num_axial_poss() const +int +SegmentBySinogram::get_num_axial_poss() const { - return this->get_length(); + return this->get_length(); } template @@ -42,7 +42,7 @@ SegmentBySinogram::get_min_axial_pos_num() const } template -int +int SegmentBySinogram::get_max_axial_pos_num() const { return this->get_max_index(); @@ -52,69 +52,74 @@ template int SegmentBySinogram::get_num_views() const { - return this->get_length()==0 ? 0 : (*this)[get_min_axial_pos_num()].get_length(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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, +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()); } + 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 be8d94168..822cb349b 100644 --- a/src/include/stir/SegmentByView.h +++ b/src/include/stir/SegmentByView.h @@ -18,7 +18,7 @@ \author Sanida Mustafovic \author Kris Thielemans - \author Claire Labbe + \author Claire Labbe \author PARAPET project @@ -26,15 +26,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 @@ -43,10 +44,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; @@ -56,43 +58,38 @@ 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_sptr, - const SegmentIndices&); + SegmentByView(const Array<3, elemT>& v, const shared_ptr& proj_data_info_sptr, const SegmentIndices&); //! Constructor that sets sizes via the ProjDataInfo object, initialising data to 0 - SegmentByView(const shared_ptr& proj_data_info_sptr, - const SegmentIndices&); + SegmentByView(const shared_ptr& proj_data_info_sptr, const SegmentIndices&); //! Constructor that sets the data to a given 3d Array /*! \deprecated Use version with SegmentIndices instead */ - SegmentByView(const Array<3,elemT>& v, - const shared_ptr& proj_data_info_ptr, - const int segment_num, - const int timing_pos_num = 0); + 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 /*! \deprecated Use version with SegmentIndices instead */ - SegmentByView(const shared_ptr& proj_data_info_ptr, - const int segment_num, - const int timing_pos_num = 0); - + 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 override; - //! Get view number + //! Get view number inline int get_num_views() const override; //! Get number of axial positions inline int get_num_axial_poss() const override; //! Get number of tangetial positions - inline int get_num_tangential_poss() const override; + inline int get_num_tangential_poss() const override; //! Get minimum view number inline int get_min_view_num() const override; //! Get maximum view number @@ -105,7 +102,7 @@ template class SegmentByView : public Segment, public Ar inline int get_min_tangential_pos_num() const override; //! Get maximum tangetial position number inline int get_max_tangential_pos_num() const override; - + using Segment::get_sinogram; using Segment::get_viewgram; //! Get sinogram @@ -113,18 +110,18 @@ template class SegmentByView : public Segment, public Ar //! Get viewgram inline Viewgram get_viewgram(int view_num) const override; //! Set sinogram - inline void set_sinogram(const Sinogram &s) override; + inline void set_sinogram(const Sinogram& s) override; //! Set sinogram - void set_sinogram(Sinogram const &s, int axial_pos_num) override; + void set_sinogram(Sinogram const& s, int axial_pos_num) override; //! Set viewgram - inline void set_viewgram(const Viewgram &v) override; + inline void set_viewgram(const Viewgram& v) override; //! Overloading Array::grow void grow(const IndexRange<3>& range) override; //! Overloading Array::resize void resize(const IndexRange<3>& range) override; - bool operator ==(const Segment&) const override; + bool operator==(const Segment&) const override; }; END_NAMESPACE_STIR diff --git a/src/include/stir/SegmentByView.inl b/src/include/stir/SegmentByView.inl index 80341d498..4897a083a 100644 --- a/src/include/stir/SegmentByView.inl +++ b/src/include/stir/SegmentByView.inl @@ -34,14 +34,14 @@ SegmentByView::get_num_views() const } template -int +int SegmentByView::get_min_view_num() const { return this->get_min_index(); } template -int +int SegmentByView::get_max_view_num() const { return this->get_max_index(); @@ -50,67 +50,75 @@ SegmentByView::get_max_view_num() const template int SegmentByView::get_num_axial_poss() const - { - return this->get_length()==0 ? 0 : (*this)[get_min_view_num()].get_length(); - } +{ + 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(); + 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(); + return this->get_length() == 0 ? 0 : (*this)[get_min_view_num()].get_max_index(); } template -int +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(); + 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(); + 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 +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(); + return this->get_length() == 0 ? 0 : (*this)[get_min_view_num()][get_min_axial_pos_num()].get_max_index(); } template -typename SegmentByView::StorageOrder +typename SegmentByView::StorageOrder SegmentByView::get_storage_order() const -{ return Segment::StorageByView; } +{ + return Segment::StorageByView; +} template -Viewgram +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()); } +{ + 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/SegmentIndices.inl b/src/include/stir/SegmentIndices.inl index 91092c0de..b2bd29fd8 100644 --- a/src/include/stir/SegmentIndices.inl +++ b/src/include/stir/SegmentIndices.inl @@ -24,7 +24,8 @@ START_NAMESPACE_STIR SegmentIndices::SegmentIndices(const int segment_num, const int timing_pos_num) - : _segment(segment_num), _timing_pos(timing_pos_num) + : _segment(segment_num), + _timing_pos(timing_pos_num) {} int diff --git a/src/include/stir/SeparableArrayFunctionObject.h b/src/include/stir/SeparableArrayFunctionObject.h index 55fcbddd4..e40519ecf 100644 --- a/src/include/stir/SeparableArrayFunctionObject.h +++ b/src/include/stir/SeparableArrayFunctionObject.h @@ -18,7 +18,6 @@ See STIR/LICENSE.txt for details */ - #ifndef __stir_SeparableArrayFunctionObject_H__ #define __stir_SeparableArrayFunctionObject_H__ @@ -28,46 +27,38 @@ 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 override; protected: - - VectorWithOffset< shared_ptr > > all_1d_array_filters; - void do_it(Array& array) const override; - + VectorWithOffset>> all_1d_array_filters; + void do_it(Array& array) const override; }; - END_NAMESPACE_STIR - -#endif //SeparableArrayFunctionObject - +#endif // SeparableArrayFunctionObject diff --git a/src/include/stir/SeparableCartesianMetzImageFilter.h b/src/include/stir/SeparableCartesianMetzImageFilter.h index be0c094e2..448362381 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 @@ -22,13 +22,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 @@ -36,14 +34,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. @@ -55,56 +53,49 @@ START_NAMESPACE_STIR */ template -class SeparableCartesianMetzImageFilter : - public - RegisteredParsingObject< - SeparableCartesianMetzImageFilter, - DataProcessor >, - DataProcessor > - > +class SeparableCartesianMetzImageFilter : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { - private: - typedef - RegisteredParsingObject< - SeparableCartesianMetzImageFilter, - DataProcessor >, - DataProcessor > - > - base_type; +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; void set_defaults() override; void initialise_keymap() override; - - Succeeded virtual_set_up(const DiscretisedDensity& image) override; + + Succeeded virtual_set_up(const DiscretisedDensity& image) override; // new - void virtual_apply(DiscretisedDensity& out_density, const DiscretisedDensity& in_density) const override; - void virtual_apply(DiscretisedDensity& density) const override ; - + void virtual_apply(DiscretisedDensity& out_density, + const DiscretisedDensity& in_density) const override; + void virtual_apply(DiscretisedDensity& density) const override; }; #undef num_dimensions @@ -112,5 +103,3 @@ class SeparableCartesianMetzImageFilter : END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir/SeparableConvolutionImageFilter.h b/src/include/stir/SeparableConvolutionImageFilter.h index 091ea6aee..ddd81471b 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 @@ -21,7 +21,6 @@ #ifndef __stir_SeparableConvolutionImageFilter_H__ #define __stir_SeparableConvolutionImageFilter_H__ - #include "stir/SeparableArrayFunctionObject.h" #include "stir/RegisteredParsingObject.h" #include "stir/DataProcessor.h" @@ -32,38 +31,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 @@ -78,37 +77,31 @@ START_NAMESPACE_STIR The filter is implemented using the class ArrayFilter1DUsingConvolution. */ template -class SeparableConvolutionImageFilter : - public - RegisteredParsingObject< - SeparableConvolutionImageFilter, - DataProcessor >, - DataProcessor > - > +class SeparableConvolutionImageFilter : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { - private: - typedef - RegisteredParsingObject< - SeparableConvolutionImageFilter, - DataProcessor >, - DataProcessor > - > - base_type; +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); //! Overloaded get and set methods the filter coefficients for axis or set of filter coefficients //@{ @@ -122,21 +115,20 @@ class SeparableConvolutionImageFilter : 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; void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - - Succeeded virtual_set_up(const DiscretisedDensity& image) override; - void virtual_apply(DiscretisedDensity& out_density, - const DiscretisedDensity& in_density) const override; - void virtual_apply(DiscretisedDensity& density) const override ; - + + Succeeded virtual_set_up(const DiscretisedDensity& image) override; + void virtual_apply(DiscretisedDensity& out_density, + const DiscretisedDensity& in_density) const override; + void virtual_apply(DiscretisedDensity& density) const override; }; #undef num_dimensions @@ -144,5 +136,3 @@ class SeparableConvolutionImageFilter : END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir/SeparableGaussianArrayFilter.h b/src/include/stir/SeparableGaussianArrayFilter.h index 95e6670ac..0ef0862f0 100644 --- a/src/include/stir/SeparableGaussianArrayFilter.h +++ b/src/include/stir/SeparableGaussianArrayFilter.h @@ -44,43 +44,38 @@ START_NAMESPACE_STIR */ template -class SeparableGaussianArrayFilter: - public SeparableArrayFunctionObject +class SeparableGaussianArrayFilter : public SeparableArrayFunctionObject { -public: - +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, + SeparableGaussianArrayFilter(const BasicCoordinate& fwhm, + const BasicCoordinate& max_kernel_sizes, bool normalise = true); - - SeparableGaussianArrayFilter(const float fwhm, - const float max_kernel_sizes, - bool normalise = true); -private: + SeparableGaussianArrayFilter(const float fwhm, const float max_kernel_sizes, bool normalise = true); + +private: void construct_filter(bool normalise = true); void calculate_coefficients(VectorWithOffset& filter_coefficients, - const int max_kernel_sizes, - const float fwhm, bool normalise); + 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 7f97e73c8..d9892bb12 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,49 @@ START_NAMESPACE_STIR */ template -class SeparableGaussianImageFilter : - public - RegisteredParsingObject< - SeparableGaussianImageFilter, - DataProcessor >, - DataProcessor > - > +class SeparableGaussianImageFilter : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { - private: - typedef - RegisteredParsingObject< - SeparableGaussianImageFilter, - DataProcessor >, - DataProcessor > - > - base_type; +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; void set_defaults() override; void initialise_keymap() override; - //virtual bool post_processing(); - - Succeeded virtual_set_up(const DiscretisedDensity& image) override; + // virtual bool post_processing(); + + Succeeded virtual_set_up(const DiscretisedDensity& image) override; // new - void virtual_apply(DiscretisedDensity& out_density, const DiscretisedDensity& in_density) const override; - void virtual_apply(DiscretisedDensity& density) const override ; + void virtual_apply(DiscretisedDensity& out_density, + const DiscretisedDensity& in_density) const override; + void virtual_apply(DiscretisedDensity& density) const override; }; #undef num_dimensions @@ -106,5 +98,3 @@ class SeparableGaussianImageFilter : END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir/SeparableMetzArrayFilter.h b/src/include/stir/SeparableMetzArrayFilter.h index a95f70e14..d499bd382 100644 --- a/src/include/stir/SeparableMetzArrayFilter.h +++ b/src/include/stir/SeparableMetzArrayFilter.h @@ -27,34 +27,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 @@ -62,14 +60,14 @@ 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: /*! @@ -77,28 +75,26 @@ class SeparableMetzArrayFilter: public SeparableArrayFunctionObject & fwhms, - const VectorWithOffset& metz_powers, - const BasicCoordinate& sampling_distances, - const VectorWithOffset& max_kernel_sizes); - - - + const VectorWithOffset& metz_powers, + const BasicCoordinate& sampling_distances, + const VectorWithOffset& max_kernel_sizes); + private: VectorWithOffset fwhms; VectorWithOffset metz_powers; @@ -106,9 +102,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 9429ea05c..1199e9b19 100644 --- a/src/include/stir/Shape/Box3D.h +++ b/src/include/stir/Shape/Box3D.h @@ -11,9 +11,9 @@ /*! \file \ingroup Shape - + \brief Declaration of class stir::Box3D - + \author C. Ross Schmidtlein */ @@ -35,7 +35,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:= @@ -46,13 +46,12 @@ START_NAMESPACE_STIR End:= \endverbatim */ -class Box3D: -public RegisteredParsingObject +class Box3D : public RegisteredParsingObject { - public: +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, @@ -64,39 +63,37 @@ 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 override; // float get_geometric_area() const; - + bool is_inside_shape(const CartesianCoordinate3D& coord) const override; - + Shape3D* clone() const override; //! 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; - bool - operator==(const Shape3D& shape) const override; - - protected: + bool operator==(const Shape3D& shape) const override; + +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: - void set_defaults() override; + +private: + void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - }; END_NAMESPACE_STIR diff --git a/src/include/stir/Shape/CombinedShape3D.h b/src/include/stir/Shape/CombinedShape3D.h index a3e70219b..db5f38076 100644 --- a/src/include/stir/Shape/CombinedShape3D.h +++ b/src/include/stir/Shape/CombinedShape3D.h @@ -26,21 +26,17 @@ START_NAMESPACE_STIR - -template +template struct logical_and_not - { - inline bool operator()(const T& x, const T& y) const - { return x && !y; } - }; - +{ + inline bool operator()(const T& x, const T& y) const { return x && !y; } +}; -template +template struct logical_and - { - inline bool operator()(const T& x, const T& y) const - { return x || y; } - }; +{ + 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 @@ -48,15 +44,14 @@ struct logical_and \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); @@ -65,10 +60,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 90dda580b..fd9b2f2df 100644 --- a/src/include/stir/Shape/CombinedShape3D.inl +++ b/src/include/stir/Shape/CombinedShape3D.inl @@ -19,22 +19,22 @@ */ 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 @@ -43,14 +43,15 @@ 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) +template +void +CombinedShape3D::translate(const CartesianCoordinate3D& direction) { - // TODO alright ? + // TODO alright ? shared_ptr new_object1_ptr = object1_ptr->clone(); shared_ptr new_object2_ptr = object2_ptr->clone(); object1_ptr = new_object1_ptr; @@ -59,11 +60,11 @@ void CombinedShape3D::translate(const CartesianCoordinate3D& d object2_ptr->translate(direction); } - -template -void CombinedShape3D::scale(const CartesianCoordinate3D& scale3D) +template +void +CombinedShape3D::scale(const CartesianCoordinate3D& scale3D) { - // TODO alright ? + // 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 1d1d249a8..6dbaeea8e 100644 --- a/src/include/stir/Shape/DiscretisedShape3D.h +++ b/src/include/stir/Shape/DiscretisedShape3D.h @@ -27,7 +27,8 @@ START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; /*! \ingroup Shape \brief A class for shapes that have been discretised as a volume @@ -48,17 +49,16 @@ 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. @@ -66,41 +66,45 @@ 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() */ - bool - operator==(const Shape3D&) const override - { error("DiscretisedShape3D::operator== not implemented. Sorry"); return false;} + bool operator==(const Shape3D&) const override + { + error("DiscretisedShape3D::operator== not implemented. Sorry"); + return false; + } //! set origin of the shape void set_origin(const CartesianCoordinate3D&) override; //! Scale shape /*! \todo Not implemented (will call error()) */ - void scale(const CartesianCoordinate3D& scale3D) override - { error ("TODO: DiscretisedShape3D::scale not implemented. Sorry.");} + void scale(const CartesianCoordinate3D& scale3D) override + { + 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 override; //! 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 @@ -109,47 +113,45 @@ class DiscretisedShape3D: If get_label_index() >= 0, the weight will be 1 for those voxels whose value is equal to the label_index and zero otherwise. If get_label_index() < 0 (default), the weight will be the actual voxel value. */ - float get_voxel_weight( - const CartesianCoordinate3D& coord, - const CartesianCoordinate3D& voxel_size, - const CartesianCoordinate3D& num_samples) const override; - - //! Construct a new image from the underlying density - /*! - If get_label_index() >= 0, the imags need to have the same characteristics, but in the other case, - zoom_image is called for interpolation. - The result is then 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 override; - //void construct_slice(PixelsOnCartesianGrid &plane, const CartesianCoordinate3D& num_samples) const; - - - Shape3D* clone() const override; - - //! 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; - - //! Return label index - int get_label_index() const; - //! Set label index - void set_label_index(int label_index); - + float get_voxel_weight(const CartesianCoordinate3D& coord, + const CartesianCoordinate3D& voxel_size, + const CartesianCoordinate3D& num_samples) const override; + + //! Construct a new image from the underlying density + /*! + If get_label_index() >= 0, the imags need to have the same characteristics, but in the other case, + zoom_image is called for interpolation. + The result is then 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 override; + // void construct_slice(PixelsOnCartesianGrid &plane, const CartesianCoordinate3D& num_samples) const; + + Shape3D* clone() const override; + + //! 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; + + //! Return label index + int get_label_index() const; + //! Set label index + void set_label_index(int label_index); + private: int _label_index; - shared_ptr > density_sptr; - + shared_ptr> density_sptr; + inline const VoxelsOnCartesianGrid& image() const; // inline VoxelsOnCartesianGrid& image(); //! \name Parsing functions //@{ //! Sets defaults i.e. label index=-1 and reset density_sptr - void set_defaults() override; + void set_defaults() override; void initialise_keymap() override; //! Checks validity of parameters /*! As currently there are 2 origin parameters (in Shape3D and @@ -161,7 +163,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 07d3dd4f1..c39ea962b 100644 --- a/src/include/stir/Shape/DiscretisedShape3D.inl +++ b/src/include/stir/Shape/DiscretisedShape3D.inl @@ -20,14 +20,12 @@ 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 2ad3d57cf..355e79c39 100644 --- a/src/include/stir/Shape/Ellipsoid.h +++ b/src/include/stir/Shape/Ellipsoid.h @@ -19,7 +19,6 @@ #ifndef __stir_Shape_Ellipsoid_h__ #define __stir_Shape_Ellipsoid_h__ - #include "stir/RegisteredParsingObject.h" #include "stir/Shape/Shape3DWithOrientation.h" @@ -28,7 +27,7 @@ START_NAMESPACE_STIR /*! \ingroup Shape \brief Three-dimensional ellipsoid - + \par Description A point with coordinates \a coord is inside the shape if for @@ -49,17 +48,16 @@ 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 override; #if 0 @@ -73,36 +71,39 @@ class Ellipsoid: //! Compare cylinders /*! Uses a tolerance determined by the smallest dimension of the object divided by 1000.*/ - bool - operator==(const Ellipsoid&) const; + bool operator==(const Ellipsoid&) const; - bool - operator==(const Shape3D& shape) const override; + bool operator==(const Shape3D& shape) const override; inline float get_radius_x() const - { return radii.x(); } + { + return radii.x(); + } inline float get_radius_y() const - { return radii.y(); } + { + return radii.y(); + } inline float get_radius_z() const - { return radii.z(); } + { + return radii.z(); + } inline CartesianCoordinate3D get_radii() const - { return radii; } + { + return radii; + } void set_radii(const CartesianCoordinate3D& new_radii); - protected: //! Radii in 3 directions (before using the direction vectors) CartesianCoordinate3D radii; //! set defaults before parsing /*! sets radii to 0 and calls Shape3DWithOrientation::set_defaults() */ - void set_defaults() override; + void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir/Shape/EllipsoidalCylinder.h b/src/include/stir/Shape/EllipsoidalCylinder.h index b4c83ebee..17530c9e4 100644 --- a/src/include/stir/Shape/EllipsoidalCylinder.h +++ b/src/include/stir/Shape/EllipsoidalCylinder.h @@ -27,7 +27,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 @@ -48,10 +48,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:= @@ -64,46 +64,43 @@ 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, + 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, + EllipsoidalCylinder(const float length_z, const float radius_y, const float radius_x, - const float theta_1, - const float theta_2, + 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 override; + Shape3D* clone() const override; //! 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; - bool - operator==(const Shape3D& shape) const override; + bool operator==(const Shape3D& shape) const override; //! get volume float get_geometric_volume() const override; @@ -113,20 +110,25 @@ class EllipsoidalCylinder: #endif bool is_inside_shape(const CartesianCoordinate3D& coord) const override; - + inline float get_length() const - { return length; } + { + return length; + } inline float get_radius_x() const - { return radius_x; } + { + return radius_x; + } inline float get_radius_y() const - { return radius_y; } - //TODOXXX add theta_1,2 + { + 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 @@ -134,14 +136,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() */ - void set_defaults() override; - void initialise_keymap() override; + void set_defaults() override; + void initialise_keymap() override; bool post_processing() override; }; diff --git a/src/include/stir/Shape/EllipsoidalCylinder.inl b/src/include/stir/Shape/EllipsoidalCylinder.inl index e0424ecee..fe72671f0 100644 --- a/src/include/stir/Shape/EllipsoidalCylinder.inl +++ b/src/include/stir/Shape/EllipsoidalCylinder.inl @@ -19,16 +19,18 @@ */ START_NAMESPACE_STIR -float EllipsoidalCylinder:: get_geometric_volume()const - { - return (radius_a*radius_b*_PI*length); - } +float +EllipsoidalCylinder::get_geometric_volume() const +{ + return (radius_a * radius_b * _PI * length); +} -Shape3D* EllipsoidalCylinder:: clone() const +Shape3D* +EllipsoidalCylinder::clone() const { - return static_cast(new EllipsoidalCylinder(*this)); + return static_cast(new EllipsoidalCylinder(*this)); } -void +void EllipsoidalCylinder::scale(const CartesianCoordinate3D& scale3D) { origin *= scale3D; diff --git a/src/include/stir/Shape/GenerateImage.h b/src/include/stir/Shape/GenerateImage.h index aab03d51f..5c7ac8d71 100644 --- a/src/include/stir/Shape/GenerateImage.h +++ b/src/include/stir/Shape/GenerateImage.h @@ -113,64 +113,60 @@ #include "stir/VoxelsOnCartesianGrid.h" #include - #ifndef __stir_Shape_GenerateImage_h__ -#define __stir_Shape_GenerateImage_h__ - - +# define __stir_Shape_GenerateImage_h__ START_NAMESPACE_STIR class GenerateImage : public KeyParser { public: - //! Constructor requires a parameter filename passed. - explicit GenerateImage(const char * const par_filename); + //! Constructor requires a parameter filename passed. + explicit GenerateImage(const char* const par_filename); - //! Computes the shapes onto a discretised density - Succeeded compute(); + //! Computes the shapes onto a discretised density + Succeeded compute(); - //! Writes the discretised density to file. Filename is set by initial parameters. - Succeeded save_image(); + //! Writes the discretised density to file. Filename is set by initial parameters. + Succeeded save_image(); - //! Returns the discretised density with computed shapes. - shared_ptr> get_output_sptr(); + //! Returns the discretised density with computed shapes. + shared_ptr> get_output_sptr(); private: - - virtual void set_defaults(); - virtual void initialise_keymap(); - bool post_processing() override; - void set_imaging_modality(); - shared_ptr exam_info_sptr; - std::string imaging_modality_as_string; - ASCIIlist_type patient_orientation_values; - ASCIIlist_type patient_rotation_values; - int patient_orientation_index; - int patient_rotation_index; - - shared_ptr > out_density_ptr; - - 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; - - void increment_current_shape_num(); - - int output_image_size_x; - int output_image_size_y; - int output_image_size_z; - float output_voxel_size_x; - float output_voxel_size_y; - float output_voxel_size_z; - - CartesianCoordinate3D num_samples; - - double image_duration; - double rel_start_time; + virtual void set_defaults(); + virtual void initialise_keymap(); + bool post_processing() override; + void set_imaging_modality(); + shared_ptr exam_info_sptr; + std::string imaging_modality_as_string; + ASCIIlist_type patient_orientation_values; + ASCIIlist_type patient_rotation_values; + int patient_orientation_index; + int patient_rotation_index; + + shared_ptr> out_density_ptr; + + 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; + + void increment_current_shape_num(); + + int output_image_size_x; + int output_image_size_y; + int output_image_size_z; + float output_voxel_size_x; + float output_voxel_size_y; + float output_voxel_size_z; + + CartesianCoordinate3D num_samples; + + double image_duration; + double rel_start_time; }; END_NAMESPACE_STIR diff --git a/src/include/stir/Shape/Shape3D.h b/src/include/stir/Shape/Shape3D.h index 65b0de019..b3738f5ab 100644 --- a/src/include/stir/Shape/Shape3D.h +++ b/src/include/stir/Shape/Shape3D.h @@ -27,8 +27,8 @@ START_NAMESPACE_STIR -template class VoxelsOnCartesianGrid; - +template +class VoxelsOnCartesianGrid; /*! \ingroup Shape @@ -39,12 +39,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 @@ -62,29 +62,25 @@ template class VoxelsOnCartesianGrid; origin (in mm):= ;defaults to {0,0,0} \endverbatim */ -class Shape3D : - public RegisteredObject +class Shape3D : public RegisteredObject { public: - - ~Shape3D() override {} - + //! 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, @@ -97,36 +93,34 @@ 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. @@ -139,10 +133,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 @@ -157,12 +151,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; @@ -174,17 +168,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() std::string parameter_info() override; @@ -195,13 +188,12 @@ class Shape3D : //! \name Parsing functions //@{ - void set_defaults() override; + void set_defaults() override; void initialise_keymap() override; //@} 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 b85e9145e..e8fda32aa 100644 --- a/src/include/stir/Shape/Shape3D.inl +++ b/src/include/stir/Shape/Shape3D.inl @@ -21,41 +21,39 @@ START_NAMESPACE_STIR Shape3D::Shape3D() -: origin(0,0,0) + : origin(0, 0, 0) {} Shape3D::Shape3D(const CartesianCoordinate3D& origin) -: origin(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 + +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 f1b96b7f8..a7a670cda 100644 --- a/src/include/stir/Shape/Shape3DWithOrientation.h +++ b/src/include/stir/Shape/Shape3DWithOrientation.h @@ -39,7 +39,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 @@ -55,19 +55,17 @@ class Succeeded; */ -class Shape3DWithOrientation: public Shape3D +class Shape3DWithOrientation : public Shape3D { typedef Shape3D base_type; public: - bool operator==(const Shape3DWithOrientation& s) const; void scale(const CartesianCoordinate3D& scale3D) override; //! 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. @@ -75,7 +73,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 @@ -85,20 +83,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( @@ -112,12 +108,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. */ - void set_defaults() override; + void set_defaults() override; void initialise_keymap() override; bool post_processing() override; void set_key_values() override; @@ -130,11 +125,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 dcdccc302..20fd184c0 100644 --- a/src/include/stir/Sinogram.h +++ b/src/include/stir/Sinogram.h @@ -27,33 +27,29 @@ #ifndef __Sinogram_h__ #define __Sinogram_h__ - #include "stir/Array.h" -#include "stir/ProjDataInfo.h" +#include "stir/ProjDataInfo.h" #include "stir/SinogramIndices.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. SegmentIndices and axial_pos_num + This represents a subset of the full projection. SegmentIndices 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 @@ -63,31 +59,34 @@ class Sinogram : public Array<2,elemT> public: //! Construct sinogram from proj_data_info pointe and indices. Data are set to 0. - inline Sinogram(const shared_ptr& proj_data_info_sptr, - const SinogramIndices&); + inline Sinogram(const shared_ptr& proj_data_info_sptr, const SinogramIndices&); //! Construct sinogram with data set to the array. - inline Sinogram(const Array<2,elemT>& p,const shared_ptr& proj_data_info_sptr, - const SinogramIndices&); + inline Sinogram(const Array<2, elemT>& p, const shared_ptr& proj_data_info_sptr, const SinogramIndices&); //! Construct sinogram from proj_data_info pointer, axial position and segment number. Data are set to 0. /*! \deprecated Use version with SinogramIndices instead. */ - inline Sinogram(const shared_ptr& proj_data_info_ptr, - const int ax_pos_num, const int segment_num, const int timing_pos_num = 0); + 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. /*! \deprecated Use version with SinogramIndices instead. */ - 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); + 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 indices inline SinogramIndices get_sinogram_indices() const; //! 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 @@ -104,20 +103,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) override; //! Overloading Array::resize void resize(const IndexRange<2>& range) override; //! 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 //@{ @@ -125,32 +123,27 @@ 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; SinogramIndices _indices; - }; END_NAMESPACE_STIR diff --git a/src/include/stir/Sinogram.inl b/src/include/stir/Sinogram.inl index d8feda9ce..d8fb5bbb5 100644 --- a/src/include/stir/Sinogram.inl +++ b/src/include/stir/Sinogram.inl @@ -28,7 +28,6 @@ START_NAMESPACE_STIR - template SinogramIndices Sinogram::get_sinogram_indices() const @@ -39,49 +38,65 @@ Sinogram::get_sinogram_indices() const template int Sinogram::get_segment_num() const -{ return this->_indices.segment_num(); } +{ + return this->_indices.segment_num(); +} template int Sinogram::get_axial_pos_num() const -{ return this->_indices.axial_pos_num(); } +{ + return this->_indices.axial_pos_num(); +} template int Sinogram::get_timing_pos_num() const -{ return this->_indices.timing_pos_num(); } +{ + return this->_indices.timing_pos_num(); +} template int Sinogram::get_min_view_num() const - {return this->get_min_index();} +{ + return this->get_min_index(); +} template int Sinogram::get_max_view_num() const - { return this->get_max_index(); } +{ + return this->get_max_index(); +} template int Sinogram::get_num_views() const - { return this->get_length();} +{ + return this->get_length(); +} template int -Sinogram::get_num_tangential_poss()const - { return this->get_length()==0 ? 0 : (*this)[get_min_view_num()].get_length();} +Sinogram::get_num_tangential_poss() const +{ + return this->get_length() == 0 ? 0 : (*this)[get_min_view_num()].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();} +{ + 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(); } - - +{ + return this->get_length() == 0 ? 0 : (*this)[get_min_view_num()].get_max_index(); +} template Sinogram @@ -99,38 +114,29 @@ Sinogram::get_proj_data_info_sptr() const } template -Sinogram:: -Sinogram(const Array<2,elemT>& p, - const shared_ptr& pdi_ptr, - const SinogramIndices& ind) - : - Array<2,elemT>(p), - proj_data_info_ptr(pdi_ptr), - _indices(ind) +Sinogram::Sinogram(const Array<2, elemT>& p, const shared_ptr& pdi_ptr, const SinogramIndices& ind) + : Array<2, elemT>(p), + proj_data_info_ptr(pdi_ptr), + _indices(ind) { assert(ind.axial_pos_num() <= proj_data_info_ptr->get_max_axial_pos_num(ind.segment_num())); assert(ind.axial_pos_num() >= proj_data_info_ptr->get_min_axial_pos_num(ind.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 SinogramIndices& ind) - : - 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), - _indices(ind) +Sinogram::Sinogram(const shared_ptr& pdi_ptr, const SinogramIndices& ind) + : 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), + _indices(ind) { assert(ind.axial_pos_num() <= proj_data_info_ptr->get_max_axial_pos_num(ind.segment_num())); assert(ind.axial_pos_num() >= proj_data_info_ptr->get_min_axial_pos_num(ind.segment_num())); @@ -138,18 +144,17 @@ Sinogram(const shared_ptr& pdi_ptr, } template -Sinogram:: -Sinogram(const Array<2,elemT>& p, - const shared_ptr& pdi_sptr, - const int ax_pos_num, const int s_num, const int t_num) - : Sinogram(p, pdi_sptr, SinogramIndices(ax_pos_num, s_num, t_num)) +Sinogram::Sinogram(const Array<2, elemT>& p, + const shared_ptr& pdi_sptr, + const int ax_pos_num, + const int s_num, + const int t_num) + : Sinogram(p, pdi_sptr, SinogramIndices(ax_pos_num, s_num, t_num)) {} template -Sinogram:: -Sinogram(const shared_ptr& pdi_sptr, - const int ax_pos_num, const int s_num, const int t_num) - : Sinogram(pdi_sptr, SinogramIndices(ax_pos_num, s_num, t_num)) +Sinogram::Sinogram(const shared_ptr& pdi_sptr, const int ax_pos_num, const int s_num, const int t_num) + : Sinogram(pdi_sptr, SinogramIndices(ax_pos_num, s_num, t_num)) {} END_NAMESPACE_STIR diff --git a/src/include/stir/SinogramIndices.h b/src/include/stir/SinogramIndices.h index e4d2f8781..a0dbc809d 100644 --- a/src/include/stir/SinogramIndices.h +++ b/src/include/stir/SinogramIndices.h @@ -7,7 +7,7 @@ \brief Definition of class stir::SinogramIndices \author Kris Thielemans - + */ /* Copyright (C) 2023, University College London @@ -18,8 +18,6 @@ See STIR/LICENSE.txt for details */ - - #ifndef __stir_SinogramIndices_h__ #define __stir_SinogramIndices_h__ @@ -30,17 +28,17 @@ START_NAMESPACE_STIR /*! \brief A very simple class to store all dincies to get a (2D) Sinogram - \ingroup projdata + \ingroup projdata */ class SinogramIndices : public SegmentIndices { typedef SegmentIndices base_type; -public: +public: //! an empty constructor (sets everything to 0) - inline SinogramIndices(); + inline SinogramIndices(); //! constructor specifying indices - inline SinogramIndices( const int axial_pos_num,const int segment_num, const int timing_pos_num); + inline SinogramIndices(const int axial_pos_num, const int segment_num, const int timing_pos_num); //! constructor from Bin inline SinogramIndices(const Bin&); @@ -49,9 +47,8 @@ class SinogramIndices : public SegmentIndices inline int axial_pos_num() const; //! get reference to view number - inline int& axial_pos_num(); + inline int& axial_pos_num(); - //! comparison operator, only useful for sorting /*! order : (0,1) < (0,-1) < (1,1) ...*/ inline bool operator<(const SinogramIndices& other) const; @@ -62,7 +59,6 @@ class SinogramIndices : public SegmentIndices private: int _axial_pos; - }; END_NAMESPACE_STIR diff --git a/src/include/stir/SinogramIndices.inl b/src/include/stir/SinogramIndices.inl index 4a0a390a9..d70ecd81e 100644 --- a/src/include/stir/SinogramIndices.inl +++ b/src/include/stir/SinogramIndices.inl @@ -7,7 +7,7 @@ \author Kris Thielemans \author Sanida Mustafovic \author PARAPET project - + */ /* @@ -20,49 +20,49 @@ See STIR/LICENSE.txt for details */ - START_NAMESPACE_STIR SinogramIndices::SinogramIndices() -:SegmentIndices(),_axial_pos(0) - {} + : SegmentIndices(), + _axial_pos(0) +{} -SinogramIndices::SinogramIndices( const int axial_pos_num,const int segment_num, const int timing_pos_num) - : SegmentIndices(segment_num, timing_pos_num),_axial_pos(axial_pos_num) - {} +SinogramIndices::SinogramIndices(const int axial_pos_num, const int segment_num, const int timing_pos_num) + : SegmentIndices(segment_num, timing_pos_num), + _axial_pos(axial_pos_num) +{} SinogramIndices::SinogramIndices(const Bin& bin) - : SegmentIndices(bin),_axial_pos(bin.axial_pos_num()) - {} + : SegmentIndices(bin), + _axial_pos(bin.axial_pos_num()) +{} -int +int SinogramIndices::axial_pos_num() const { - return _axial_pos;} - + return _axial_pos; +} -int& -SinogramIndices::axial_pos_num() -{ return _axial_pos;} +int& +SinogramIndices::axial_pos_num() +{ + return _axial_pos; +} -bool -SinogramIndices:: -operator<(const SinogramIndices& other) const +bool +SinogramIndices::operator<(const SinogramIndices& other) const { - return (_axial_pos< other._axial_pos) || - ((_axial_pos == other._axial_pos) && base_type::operator<(other)); + return (_axial_pos < other._axial_pos) || ((_axial_pos == other._axial_pos) && base_type::operator<(other)); } -bool -SinogramIndices:: -operator==(const SinogramIndices& other) const +bool +SinogramIndices::operator==(const SinogramIndices& other) const { return (_axial_pos == other._axial_pos) && base_type::operator==(other); } -bool -SinogramIndices:: -operator!=(const SinogramIndices& other) const +bool +SinogramIndices::operator!=(const SinogramIndices& other) const { return !(*this == other); } diff --git a/src/include/stir/StirException.h b/src/include/stir/StirException.h index 1d3a76d35..781d38d20 100644 --- a/src/include/stir/StirException.h +++ b/src/include/stir/StirException.h @@ -6,37 +6,32 @@ #include #include -class StirException : public std::exception { +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 57306aec6..99feca1ba 100644 --- a/src/include/stir/Succeeded.h +++ b/src/include/stir/Succeeded.h @@ -27,9 +27,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: @@ -43,12 +43,19 @@ START_NAMESPACE_STIR class Succeeded { public: - enum value { yes, no }; - Succeeded(const value& v = yes) : v(v) {} - bool operator==(const Succeeded &v2) const { return v == v2.v; } - bool operator!=(const Succeeded &v2) const { return v != v2.v; } + enum value + { + yes, + no + }; + Succeeded(const value& v = yes) + : v(v) + {} + bool operator==(const Succeeded& v2) const { return v == v2.v; } + bool operator!=(const Succeeded& v2) const { return v != v2.v; } //! convenience function returns if it is equal to Succeeded::yes bool succeeded() const { return this->v == yes; } + private: value v; }; diff --git a/src/include/stir/TOF_conversions.h b/src/include/stir/TOF_conversions.h index ac6e35d98..d80d97a99 100644 --- a/src/include/stir/TOF_conversions.h +++ b/src/include/stir/TOF_conversions.h @@ -19,15 +19,16 @@ #include "stir/common.h" START_NAMESPACE_STIR -inline double mm_to_tof_delta_time(const float dist) +inline double +mm_to_tof_delta_time(const float dist) { return dist / speed_of_light_in_mm_per_ps_div2; } -inline float tof_delta_time_to_mm(const double delta_time) +inline float +tof_delta_time_to_mm(const double delta_time) { return static_cast(delta_time * speed_of_light_in_mm_per_ps_div2); } END_NAMESPACE_STIR - diff --git a/src/include/stir/TextWriter.h b/src/include/stir/TextWriter.h index b420abfda..f4a5f3905 100644 --- a/src/include/stir/TextWriter.h +++ b/src/include/stir/TextWriter.h @@ -13,107 +13,117 @@ START_NAMESPACE_STIR -enum OUTPUT_CHANNEL {INFORMATION_CHANNEL, WARNING_CHANNEL, ERROR_CHANNEL}; +enum OUTPUT_CHANNEL +{ + INFORMATION_CHANNEL, + WARNING_CHANNEL, + ERROR_CHANNEL +}; -class aTextWriter { +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 { +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; - } - } - void write(const char* text) const override { - 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; + } + } + void write(const char* text) const override + { + 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 { +class TextWriter : public aTextWriter +{ public: - std::ostream* out; - TextWriter(std::ostream* os = 0) : out(os) {} - void write(const char* text) const override { - if (out) { - (*out) << text; - (*out).flush(); - } - } + std::ostream* out; + TextWriter(std::ostream* os = 0) + : out(os) + {} + void write(const char* text) const override + { + if (out) + { + (*out) << text; + (*out).flush(); + } + } }; -class TextWriterHandle { +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 42cb1a973..6b9322376 100644 --- a/src/include/stir/ThresholdMinToSmallPositiveValueDataProcessor.h +++ b/src/include/stir/ThresholdMinToSmallPositiveValueDataProcessor.h @@ -11,30 +11,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 @@ -51,46 +49,35 @@ 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; - + void set_defaults() override; void initialise_keymap() override; - + Succeeded virtual_set_up(const DataT&) override; - void virtual_apply(DataT& out_data, const DataT& in_data) const override; - void virtual_apply(DataT& data) const override ; - + void virtual_apply(DataT& out_data, const DataT& in_data) const override; + void virtual_apply(DataT& data) const override; }; - END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir/TimeFrameDefinitions.h b/src/include/stir/TimeFrameDefinitions.h index 8ea48ba7b..87a58d507 100644 --- a/src/include/stir/TimeFrameDefinitions.h +++ b/src/include/stir/TimeFrameDefinitions.h @@ -10,9 +10,9 @@ /*! \file - \ingroup buildblock + \ingroup buildblock \brief Declaration of class stir::TimeFrameDefinitions - + \author Kris Thielemans */ #ifndef __stir_TimeFrameDefinitions_H__ @@ -42,7 +42,7 @@ class TimeFrameDefinitions 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. @@ -54,22 +54,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) @@ -88,25 +88,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 745fa6e5e..3f35422fe 100644 --- a/src/include/stir/TimeGateDefinitions.h +++ b/src/include/stir/TimeGateDefinitions.h @@ -3,21 +3,21 @@ Copyright (C) 2000- 2008, Hammersmith Imanet Ltd Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + 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__ @@ -41,16 +41,15 @@ START_NAMESPACE_STIR */ class TimeGateDefinitions { - public: +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 @@ -58,7 +57,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. */ @@ -67,7 +66,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; //@} @@ -76,9 +75,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 a82771b83..f5d5e72ac 100644 --- a/src/include/stir/TimedBlock.h +++ b/src/include/stir/TimedBlock.h @@ -10,7 +10,7 @@ */ /*! - \file + \file \ingroup buildblock \brief Class stir::TimedBlock @@ -21,76 +21,73 @@ */ #ifndef _stir_TimedBlock_H_ #define _stir_TimedBlock_H_ -namespace stir { +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 a5d6c4eb9..6dd361349 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 */ @@ -26,16 +26,15 @@ 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(); @@ -58,17 +57,15 @@ class TimedObject inline double get_wall_clock_timer_value() const; private: - //! A timer that measures CPU time. /*! Note: member is mutable such that it can be modified in a const function. - */ + */ mutable CPUTimer cpu_timer; //! A timer that measures wall clock time. /*! Note: member is mutable such that it can be modified in a const function. - */ + */ mutable HighResWallClockTimer wall_clock_timer; - }; END_NAMESPACE_STIR diff --git a/src/include/stir/TimedObject.inl b/src/include/stir/TimedObject.inl index 29e0f610b..cc092c845 100644 --- a/src/include/stir/TimedObject.inl +++ b/src/include/stir/TimedObject.inl @@ -22,32 +22,35 @@ START_NAMESPACE_STIR -void TimedObject::reset_timers() +void +TimedObject::reset_timers() { cpu_timer.reset(); wall_clock_timer.reset(); } -void TimedObject::start_timers(bool do_reset) const +void +TimedObject::start_timers(bool do_reset) const { cpu_timer.start(do_reset); wall_clock_timer.start(do_reset); } - -void TimedObject::stop_timers() const +void +TimedObject::stop_timers() const { cpu_timer.stop(); wall_clock_timer.stop(); } - -double TimedObject::get_CPU_timer_value() const +double +TimedObject::get_CPU_timer_value() const { return cpu_timer.value(); } -double TimedObject::get_wall_clock_timer_value() const +double +TimedObject::get_wall_clock_timer_value() const { return wall_clock_timer.value(); } diff --git a/src/include/stir/Timer.h b/src/include/stir/Timer.h index 84ff82a6c..c881b6c2c 100644 --- a/src/include/stir/Timer.h +++ b/src/include/stir/Timer.h @@ -1,4 +1,4 @@ -// +// // /* Copyright (C) 2000 PARAPET partners @@ -47,14 +47,14 @@ 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 -{ +{ public: inline Timer(); - inline virtual ~Timer(); + inline virtual ~Timer(); //! start stopwatch, optionally resetting first /*! the stopwatch should not be running already if asking to reset */ inline void start(bool do_reset = false); @@ -70,13 +70,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 b4c733d51..b56f10da3 100644 --- a/src/include/stir/Timer.inl +++ b/src/include/stir/Timer.inl @@ -26,59 +26,62 @@ START_NAMESPACE_STIR Timer::Timer() -{ +{ running = false; previous_total_value = 0.; - } Timer::~Timer() {} -void Timer::start(bool do_reset) -{ +void +Timer::start(bool do_reset) +{ if (!running) - { - if (do_reset) - reset(); - running = true; - previous_value = get_current_value(); - } + { + if (do_reset) + reset(); + running = true; + previous_value = get_current_value(); + } else if (do_reset) error("Timer::start called requesting reset, but the timer is running"); } -void Timer::stop() -{ +void +Timer::stop() +{ if (running) - { - previous_total_value += get_current_value() - previous_value; - running = false; - } + { + 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 c342f7703..c762dc8d8 100644 --- a/src/include/stir/TrivialDataSymmetriesForViewSegmentNumbers.h +++ b/src/include/stir/TrivialDataSymmetriesForViewSegmentNumbers.h @@ -37,9 +37,7 @@ START_NAMESPACE_STIR class TrivialDataSymmetriesForViewSegmentNumbers : public DataSymmetriesForViewSegmentNumbers { public: - - inline DataSymmetriesForViewSegmentNumbers * clone() const override; - + inline DataSymmetriesForViewSegmentNumbers* clone() const override; #if 0 // TODO @@ -48,23 +46,19 @@ class TrivialDataSymmetriesForViewSegmentNumbers : public DataSymmetriesForViewS get_basic_view_segment_index_range() const; #endif - inline void - get_related_view_segment_numbers(std::vector&, const ViewSegmentNumbers& v_s) const override; + inline void get_related_view_segment_numbers(std::vector&, const ViewSegmentNumbers& v_s) const override; - inline int - num_related_view_segment_numbers(const ViewSegmentNumbers& v_s) const override; + inline int num_related_view_segment_numbers(const ViewSegmentNumbers& v_s) const override; /*! \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). - */ - inline bool - find_basic_view_segment_numbers(ViewSegmentNumbers& v_s) const override; + */ + inline bool find_basic_view_segment_numbers(ViewSegmentNumbers& v_s) const override; private: - bool blindly_equals(const root_type * const) const override; - + bool blindly_equals(const root_type* const) const override; }; END_NAMESPACE_STIR @@ -72,4 +66,3 @@ END_NAMESPACE_STIR #include "stir/TrivialDataSymmetriesForViewSegmentNumbers.inl" #endif - diff --git a/src/include/stir/TrivialDataSymmetriesForViewSegmentNumbers.inl b/src/include/stir/TrivialDataSymmetriesForViewSegmentNumbers.inl index 9508f5f50..882f43ea4 100644 --- a/src/include/stir/TrivialDataSymmetriesForViewSegmentNumbers.inl +++ b/src/include/stir/TrivialDataSymmetriesForViewSegmentNumbers.inl @@ -22,39 +22,33 @@ 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 782e72400..c3d41680c 100644 --- a/src/include/stir/TruncateToCylindricalFOVImageProcessor.h +++ b/src/include/stir/TruncateToCylindricalFOVImageProcessor.h @@ -11,11 +11,11 @@ /*! \file - \ingroup ImageProcessor + \ingroup ImageProcessor \brief Declaration of class stir::TruncateToCylindricalFOVImageProcessor - + \author Kris Thielemans - + */ #ifndef __stir_TruncateToCylindricalFOVImageProcessor_H__ @@ -25,63 +25,43 @@ #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 > - > +class TruncateToCylindricalFOVImageProcessor : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { - private: - typedef - RegisteredParsingObject< - TruncateToCylindricalFOVImageProcessor, - DataProcessor >, - DataProcessor > - > - base_type; +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_truncate_rim(const int truncate_rim) - { - this->_truncate_rim = truncate_rim; - } - - int get_truncate_rim() - { - return this->_truncate_rim; - } - - 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_truncate_rim(const int truncate_rim) { this->_truncate_rim = truncate_rim; } + + int get_truncate_rim() { return this->_truncate_rim; } + + 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; @@ -89,17 +69,13 @@ class TruncateToCylindricalFOVImageProcessor : void set_defaults() override; void initialise_keymap() override; - - Succeeded virtual_set_up(const DiscretisedDensity<3,elemT>& image) override; + + Succeeded virtual_set_up(const DiscretisedDensity<3, elemT>& image) override; // new - void virtual_apply(DiscretisedDensity<3,elemT>& out_density, const DiscretisedDensity<3,elemT>& in_density) const override; - void virtual_apply(DiscretisedDensity<3,elemT>& density) const override ; - + void virtual_apply(DiscretisedDensity<3, elemT>& out_density, const DiscretisedDensity<3, elemT>& in_density) const override; + void virtual_apply(DiscretisedDensity<3, elemT>& density) const override; }; - END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir/VectorWithOffset.h b/src/include/stir/VectorWithOffset.h index f8cf52fdf..81b8c85d8 100644 --- a/src/include/stir/VectorWithOffset.h +++ b/src/include/stir/VectorWithOffset.h @@ -14,8 +14,8 @@ #define __stir_VectorWithOffset_H__ /*! - \file - \ingroup Array + \file + \ingroup Array \brief defines the stir::VectorWithOffset class \author Kris Thielemans @@ -29,7 +29,8 @@ START_NAMESPACE_STIR -namespace detail { +namespace detail +{ /*! \ingroup Array \brief templated class for the iterators used by VectorWithOffset. @@ -37,42 +38,45 @@ 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 - > +class VectorWithOffset_iter : public boost::iterator_adaptor // Derived + , + elemT* // Base + , + boost::use_default // Value + , + boost::random_access_traversal_tag // CategoryOrTraversal + > { - private: +private: // abbreviation of the type of this class typedef VectorWithOffset_iter self_t; - public: + +public: VectorWithOffset_iter() - : VectorWithOffset_iter::iterator_adaptor_(0) {} - + : 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) {} - + : 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 @@ -80,7 +84,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 @@ -89,7 +93,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(). @@ -123,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; @@ -179,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); @@ -209,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); @@ -222,55 +218,54 @@ 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); - //! Sets elements below value to the value - inline void apply_lower_threshold(const T &lower); + //! Sets elements below value to the value + inline void apply_lower_threshold(const T& lower); //! Sets elements above value to the value - inline void apply_upper_threshold(const T &upper); + inline void apply_upper_threshold(const T& upper); //! \name access to the data via a pointer //@{ @@ -278,7 +273,7 @@ class VectorWithOffset inline T* get_data_ptr(); //! member function for access to the data via a const T* - inline const T * get_const_data_ptr() const; + inline const T* get_const_data_ptr() const; //! signal end of access to T* inline void release_data_ptr(); @@ -305,20 +300,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 @@ -345,38 +340,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; @@ -386,7 +380,7 @@ 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. mutable bool pointer_access; diff --git a/src/include/stir/VectorWithOffset.inl b/src/include/stir/VectorWithOffset.inl index 00eaa34db..71193eaa3 100644 --- a/src/include/stir/VectorWithOffset.inl +++ b/src/include/stir/VectorWithOffset.inl @@ -11,7 +11,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup Array \brief inline implementations of stir::VectorWithOffset @@ -29,12 +29,12 @@ 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; } @@ -51,42 +51,39 @@ This function (only non-empty when debugging) is used before and after any modification of the object */ template -void +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(); @@ -94,59 +91,61 @@ VectorWithOffset::recycle() } 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) +T& +VectorWithOffset::at(int i) { - if (length==0 || iget_min_index() || i>this->get_max_index()) + 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]; } @@ -154,128 +153,125 @@ template bool VectorWithOffset::empty() const { - return length==0; + 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)); } 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 +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 +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; + : _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) -{ + : 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 + { + num = new T[hsz]; + begin_allocated_memory = num; + end_allocated_memory = num + length; + } + 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) - { - num = new T[length]; - begin_allocated_memory = num; - end_allocated_memory = num + length; - num -= min_index; - } - else - this->init(); +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(); 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; @@ -283,14 +279,12 @@ 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; @@ -299,155 +293,139 @@ VectorWithOffset(const int min_index, const int max_index, template 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 +VectorWithOffset::capacity() const { - return size_t(end_allocated_memory-begin_allocated_memory); + 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 -// but this should change in the future +// 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) -{ +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); + 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; + length = 0; + start = 0; + num = begin_allocated_memory; return; } const unsigned old_length = length; - if (old_length>0) + if (old_length > 0) { if (min_index == this->get_min_index() && max_index == this->get_max_index()) - return; + 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; - } + 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; - } + { + // do not change num as num[0] should remain the same + start = overlap_min_index; + } } // 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) + if (overlapping_length > 0) { // do not change num as num[0] should remain the same } @@ -460,50 +438,52 @@ resize(const int min_index, const int max_index) } template -void -VectorWithOffset::resize(const unsigned new_size) +void +VectorWithOffset::resize(const unsigned new_size) { - if (new_size==0) + if (new_size == 0) { - length = 0; start = 0; num = begin_allocated_memory; + length = 0; + start = 0; + num = begin_allocated_memory; } else - this->resize(0,static_cast(new_size-1)); + 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) +void +VectorWithOffset::grow(const unsigned new_size) { - this->grow(0,static_cast(new_size-1)); + 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 == &il) + return *this; // in case of x=x + { if (this->capacity() < il.size()) - { - // first truncate current and then reserve space - length = 0; - start = 0; - num = begin_allocated_memory; - this->reserve(il.get_min_index(), il.get_max_index()); - } + { + // first truncate current and then reserve space + length = 0; + start = 0; + num = begin_allocated_memory; + this->reserve(il.get_min_index(), il.get_max_index()); + } length = il.length; this->set_offset(il.get_min_index()); std::copy(il.begin(), il.end(), this->begin()); @@ -513,60 +493,63 @@ 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(); } - template inline void -VectorWithOffset::apply_lower_threshold(const T &lower) +VectorWithOffset::apply_lower_threshold(const T& lower) { this->check_state(); threshold_lower(this->begin(), this->end(), lower); @@ -575,22 +558,20 @@ VectorWithOffset::apply_lower_threshold(const T &lower) template inline void -VectorWithOffset::apply_upper_threshold(const T &upper) +VectorWithOffset::apply_upper_threshold(const T& upper) { this->check_state(); threshold_upper(this->begin(), this->end(), upper); 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() @@ -599,20 +580,20 @@ VectorWithOffset::apply_upper_threshold(const T &upper) (This is checked with assert() in DEBUG mode.) */ template -T* +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 @@ -621,38 +602,38 @@ VectorWithOffset::get_data_ptr() \see get_data_ptr() */ template -const T * +const T* VectorWithOffset::get_const_data_ptr() const { 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 +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() @@ -663,106 +644,102 @@ void VectorWithOffset::release_const_data_ptr() const { 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) - { - return *this = v; - } - this->grow (std::min(get_min_index(),v.get_min_index()), std::max(get_max_index(),v.get_max_index())); + { + return *this = v; + } + 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) - { - *this = v; - return *this *= -1; - } - grow (std::min(get_min_index(),v.get_min_index()), std::max(get_max_index(),v.get_max_index())); + { + *this = v; + return *this *= -1; + } + 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; - return *this *= 0; - } - grow (std::min(get_min_index(),v.get_min_index()), std::max(get_max_index(),v.get_max_index())); + { + // 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())); #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; - return *this *= 0; - } - grow (std::min(get_min_index(),v.get_min_index()), std::max(get_max_index(),v.get_max_index())); + { + // 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())); #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 *****/ @@ -814,37 +791,37 @@ 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); diff --git a/src/include/stir/Verbosity.h b/src/include/stir/Verbosity.h index cc28a1437..2718ef9b7 100644 --- a/src/include/stir/Verbosity.h +++ b/src/include/stir/Verbosity.h @@ -33,11 +33,11 @@ START_NAMESPACE_STIR */ class Verbosity { - public: +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 2b359d0b2..c7938fec3 100644 --- a/src/include/stir/ViewSegmentNumbers.h +++ b/src/include/stir/ViewSegmentNumbers.h @@ -35,9 +35,11 @@ class ViewSegmentNumbers : public ViewgramIndices public: using ViewgramIndices::ViewgramIndices; // default constructor (needed for Visual Studio) - ViewSegmentNumbers() : ViewgramIndices() {} + ViewSegmentNumbers() + : ViewgramIndices() + {} ViewSegmentNumbers(const ViewgramIndices& ind) - : ViewgramIndices(ind) + : ViewgramIndices(ind) {} }; diff --git a/src/include/stir/ViewSegmentNumbers.inl b/src/include/stir/ViewSegmentNumbers.inl index f9c965250..f4dbae8d8 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 - + */ /* @@ -20,61 +20,67 @@ See STIR/LICENSE.txt for details */ - START_NAMESPACE_STIR ViewSegmentNumbers::ViewSegmentNumbers() -:segment(0),view(0) - {} + : segment(0), + view(0) +{} -ViewSegmentNumbers::ViewSegmentNumbers( const int view_num,const int segment_num, - const int tof_num) - : segment(segment_num),view(view_num),tof(tof_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 + return segment; +} +int ViewSegmentNumbers::view_num() const { - return view;} + return view; +} int ViewSegmentNumbers::tof_pos_num() const { - return tof;} + return tof; +} int& -ViewSegmentNumbers::segment_num() -{ return segment;} -int& -ViewSegmentNumbers::view_num() -{ return view;} +ViewSegmentNumbers::segment_num() +{ + return segment; +} +int& +ViewSegmentNumbers::view_num() +{ + return view; +} int& ViewSegmentNumbers::tof_pos_num() -{ return tof;} +{ + return tof; +} -bool -ViewSegmentNumbers:: -operator<(const ViewSegmentNumbers& other) const +bool +ViewSegmentNumbers::operator<(const ViewSegmentNumbers& other) const { - return (view< other.view) || - ((view == other.view) && (segment > other.segment)); + return (view < other.view) || ((view == other.view) && (segment > other.segment)); } -bool -ViewSegmentNumbers:: -operator==(const ViewSegmentNumbers& other) const +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); } diff --git a/src/include/stir/Viewgram.h b/src/include/stir/Viewgram.h index 0a2770443..191e21653 100644 --- a/src/include/stir/Viewgram.h +++ b/src/include/stir/Viewgram.h @@ -27,33 +27,31 @@ #ifndef __Viewgram_h__ #define __Viewgram_h__ - #include "stir/Array.h" #include "stir/ProjDataInfo.h" #include "stir/ViewgramIndices.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. SegmentIndices and view_num + This represents a subset of the full projection. SegmentIndices 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 @@ -63,39 +61,43 @@ class Viewgram : public Array<2,elemT> public: //! Construct from proj_data_info pointer and indices. Data are set to 0. - inline Viewgram(const shared_ptr& proj_data_info_ptr, - const ViewgramIndices& ind); + inline Viewgram(const shared_ptr& proj_data_info_ptr, const ViewgramIndices& ind); //! Construct with data set to the array. - inline Viewgram(const Array<2,elemT>& p,const shared_ptr& proj_data_info_sptr, + inline Viewgram(const Array<2, elemT>& p, + const shared_ptr& proj_data_info_sptr, const ViewgramIndices& ind); //! Construct from proj_data_info pointer, view and segment number. Data are set to 0. /*! \deprecated Use version with ViewgramIndices instead */ - inline Viewgram(const shared_ptr& proj_data_info_ptr, - const int v_num, const int s_num, const int t_num = 0); + 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. /*! \deprecated Use version with ViewgramIndices instead */ - 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); - + 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 indices inline ViewgramIndices get_viewgram_indices() const; //! 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; @@ -105,9 +107,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) override; @@ -115,38 +117,33 @@ class Viewgram : public Array<2,elemT> void resize(const IndexRange<2>& range) override; //! 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; ViewgramIndices _indices; }; diff --git a/src/include/stir/Viewgram.inl b/src/include/stir/Viewgram.inl index 41d2d433a..aab535fff 100644 --- a/src/include/stir/Viewgram.inl +++ b/src/include/stir/Viewgram.inl @@ -38,57 +38,72 @@ Viewgram::get_viewgram_indices() const template int Viewgram::get_segment_num() const -{ return this->_indices.segment_num(); } +{ + return this->_indices.segment_num(); +} template int Viewgram::get_view_num() const -{ return this->_indices.view_num(); } +{ + return this->_indices.view_num(); +} template int Viewgram::get_timing_pos_num() const -{ return this->_indices.timing_pos_num(); } +{ + return this->_indices.timing_pos_num(); +} template int Viewgram::get_min_axial_pos_num() const - {return this->get_min_index();} +{ + return this->get_min_index(); +} template int Viewgram::get_max_axial_pos_num() const - { return this->get_max_index(); } +{ + return this->get_max_index(); +} template int Viewgram::get_num_axial_poss() const - { return this->get_length();} - +{ + return this->get_length(); +} template int Viewgram::get_num_tangential_poss() const - { return this->get_length()==0 ? 0 : (*this)[get_min_axial_pos_num()].get_length();} - +{ + return this->get_length() == 0 ? 0 : (*this)[get_min_axial_pos_num()].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();} +{ + 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(); } - +{ + 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_viewgram_indices()); - return copy; + Viewgram copy(proj_data_info_sptr, get_viewgram_indices()); + return copy; } template @@ -98,37 +113,30 @@ 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 ViewgramIndices& ind) - : - Array<2,elemT>(p), proj_data_info_sptr(pdi_sptr), - _indices(ind) +Viewgram::Viewgram(const Array<2, elemT>& p, const shared_ptr& pdi_sptr, const ViewgramIndices& ind) + : Array<2, elemT>(p), + proj_data_info_sptr(pdi_sptr), + _indices(ind) { assert(ind.view_num() <= proj_data_info_sptr->get_max_view_num()); assert(ind.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(ind.segment_num())); - assert( get_max_axial_pos_num() == pdi_sptr->get_max_axial_pos_num(ind.segment_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(ind.segment_num())); + assert(get_max_axial_pos_num() == pdi_sptr->get_max_axial_pos_num(ind.segment_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 ViewgramIndices& ind) - : - Array<2,elemT>(IndexRange2D (pdi_sptr->get_min_axial_pos_num(ind.segment_num()), - pdi_sptr->get_max_axial_pos_num(ind.segment_num()), - pdi_sptr->get_min_tangential_pos_num(), - pdi_sptr->get_max_tangential_pos_num())), - proj_data_info_sptr(pdi_sptr), - _indices(ind) +Viewgram::Viewgram(const shared_ptr& pdi_sptr, const ViewgramIndices& ind) + : Array<2, elemT>(IndexRange2D(pdi_sptr->get_min_axial_pos_num(ind.segment_num()), + pdi_sptr->get_max_axial_pos_num(ind.segment_num()), + pdi_sptr->get_min_tangential_pos_num(), + pdi_sptr->get_max_tangential_pos_num())), + proj_data_info_sptr(pdi_sptr), + _indices(ind) { assert(ind.view_num() <= proj_data_info_sptr->get_max_view_num()); assert(ind.view_num() >= proj_data_info_sptr->get_min_view_num()); @@ -136,20 +144,14 @@ Viewgram(const shared_ptr& pdi_sptr, } template -Viewgram:: -Viewgram(const Array<2,elemT>& p, - const shared_ptr& pdi_sptr, - const int v_num, const int s_num, const int t_num) - : - Viewgram(p, pdi_sptr, ViewgramIndices(v_num, s_num, t_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) + : Viewgram(p, pdi_sptr, ViewgramIndices(v_num, s_num, t_num)) {} template -Viewgram:: -Viewgram(const shared_ptr& pdi_sptr, - const int v_num, const int s_num, const int t_num) - : - Viewgram(pdi_sptr, ViewgramIndices(v_num, s_num, t_num)) +Viewgram::Viewgram(const shared_ptr& pdi_sptr, const int v_num, const int s_num, const int t_num) + : Viewgram(pdi_sptr, ViewgramIndices(v_num, s_num, t_num)) {} END_NAMESPACE_STIR diff --git a/src/include/stir/ViewgramIndices.h b/src/include/stir/ViewgramIndices.h index 6150ae22c..51b9764f2 100644 --- a/src/include/stir/ViewgramIndices.h +++ b/src/include/stir/ViewgramIndices.h @@ -35,10 +35,10 @@ class ViewgramIndices : public SegmentIndices public: //! an empty constructor (sets everything to 0) - //TODOTOF remove default + // TODOTOF remove default inline ViewgramIndices(); //! constructor taking view and segment number as arguments - inline ViewgramIndices(const int view_num, const int segment_num, const int timing_pos_num=0); + inline ViewgramIndices(const int view_num, const int segment_num, const int timing_pos_num = 0); //! get view number for const objects inline int view_num() const; diff --git a/src/include/stir/ViewgramIndices.inl b/src/include/stir/ViewgramIndices.inl index b6bc88c65..00186b5b4 100644 --- a/src/include/stir/ViewgramIndices.inl +++ b/src/include/stir/ViewgramIndices.inl @@ -28,7 +28,7 @@ ViewgramIndices::ViewgramIndices() {} ViewgramIndices::ViewgramIndices(const int view_num, const int segment_num, const int timing_pos_num) - : SegmentIndices(segment_num, timing_pos_num), + : SegmentIndices(segment_num, timing_pos_num), _view(view_num) {} diff --git a/src/include/stir/VoxelsOnCartesianGrid.h b/src/include/stir/VoxelsOnCartesianGrid.h index 9ad6c60de..dd06b6291 100644 --- a/src/include/stir/VoxelsOnCartesianGrid.h +++ b/src/include/stir/VoxelsOnCartesianGrid.h @@ -15,11 +15,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 @@ -31,7 +31,8 @@ START_NAMESPACE_STIR class ProjDataInfo; -template class PixelsOnCartesianGrid; +template +class PixelsOnCartesianGrid; /*! \ingroup densitydata @@ -40,183 +41,167 @@ 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 override; + get_empty_copy() const override; -//! 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 -VoxelsOnCartesianGrid* + VoxelsOnCartesianGrid* #endif -clone() const override; + clone() const override; -//! 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 12e9ec684..dda78bb60 100644 --- a/src/include/stir/VoxelsOnCartesianGrid.inl +++ b/src/include/stir/VoxelsOnCartesianGrid.inl @@ -10,83 +10,86 @@ 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 +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 2890edf8b..86f74b321 100644 --- a/src/include/stir/ZoomOptions.h +++ b/src/include/stir/ZoomOptions.h @@ -8,7 +8,7 @@ */ #ifndef __stir_ZOOMOPTIONS_H__ -#define __stir_ZOOMOPTIONS_H__ +#define __stir_ZOOMOPTIONS_H__ /*! \file @@ -18,7 +18,7 @@ \author Ludovica Brusaferri \author Kris Thielemans - + */ #include "stir/error.h" @@ -29,33 +29,40 @@ 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 51461d404..28454a159 100644 --- a/src/include/stir/analytic/FBP2D/FBP2DReconstruction.h +++ b/src/include/stir/analytic/FBP2D/FBP2DReconstruction.h @@ -13,9 +13,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup FBP2D - + \brief declares the stir::FBP2DReconstruction class \author Kris Thielemans @@ -31,7 +31,8 @@ START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; class Succeeded; class ProjData; @@ -59,7 +60,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 @@ -68,73 +69,63 @@ 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 - > +class FBP2DReconstruction + : public RegisteredParsingObject>, AnalyticReconstruction> { - //typedef AnalyticReconstruction base_type; - typedef - RegisteredParsingObject< - FBP2DReconstruction, - Reconstruction < DiscretisedDensity < 3,float> >, - AnalyticReconstruction - > base_type; + // 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); + std::string method_info() const override; virtual void ask_parameters(); - Succeeded set_up(shared_ptr const& target_data_sptr) override; + Succeeded set_up(shared_ptr const& target_data_sptr) override; - 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 @@ -145,25 +136,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) override; + +private: + Succeeded actual_reconstruct(shared_ptr> const& target_image_ptr) override; shared_ptr back_projector_sptr; void set_defaults() override; void initialise_keymap() override; - bool post_processing() override; + bool post_processing() override; }; - - - END_NAMESPACE_STIR - #endif - diff --git a/src/include/stir/analytic/FBP2D/RampFilter.h b/src/include/stir/analytic/FBP2D/RampFilter.h index a4bfe6921..5a65cebc0 100644 --- a/src/include/stir/analytic/FBP2D/RampFilter.h +++ b/src/include/stir/analytic/FBP2D/RampFilter.h @@ -23,10 +23,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 @@ -35,36 +35,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 d027a2003..53e2000d4 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 @@ -24,15 +24,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 /*! @@ -41,92 +42,95 @@ 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() {} + 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); + 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() override {} + ~ColsherFilter() override + {} - 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 4cd250118..2ff916876 100644 --- a/src/include/stir/analytic/FBP3DRP/FBP3DRPReconstruction.h +++ b/src/include/stir/analytic/FBP3DRP/FBP3DRPReconstruction.h @@ -10,8 +10,8 @@ See STIR/LICENSE.txt for details */ -/*! - \file +/*! + \file \ingroup FBP3DRP \brief Declaration of class stir::FBP3DRPReconstruction \author Claire LABBE @@ -22,8 +22,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" @@ -35,11 +33,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 @@ -51,7 +54,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 @@ -61,8 +64,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. @@ -72,47 +75,38 @@ 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 - > +class FBP3DRPReconstruction + : public RegisteredParsingObject>, 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; + // 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. @@ -120,96 +114,80 @@ class FBP3DRPReconstruction: public // because it doesn't know ~DiscretisedDensity. ~FBP3DRPReconstruction() override; -//! 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 std::string method_info() const override; - Succeeded - set_up(shared_ptr > const& target_image_sptr) override; + Succeeded set_up(shared_ptr> const& target_image_sptr) override; 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 + */ - Succeeded actual_reconstruct(shared_ptr > const&) override; - -//! Best fit of forward projected sinograms - void do_best_fit(const Sinogram &sino_measured, const Sinogram &sino_calculated); + Succeeded actual_reconstruct(shared_ptr> const&) override; + //! 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 @@ -217,58 +195,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: void set_defaults() override; void initialise_keymap() override; - //! 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 ead839e49..0ef850433 100644 --- a/src/include/stir/array_index_functions.h +++ b/src/include/stir/array_index_functions.h @@ -13,50 +13,42 @@ #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 - + /* \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 /*! @@ -67,17 +59,14 @@ 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); //@} diff --git a/src/include/stir/array_index_functions.inl b/src/include/stir/array_index_functions.inl index eef53e466..835ee6bfa 100644 --- a/src/include/stir/array_index_functions.inl +++ b/src/include/stir/array_index_functions.inl @@ -9,9 +9,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup Array - + \brief implementation of functions in stir/array_index_functions.h \author Kris Thielemans @@ -28,22 +28,21 @@ 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 { template -inline -BasicCoordinate +inline BasicCoordinate get_min_indices_help(is_not_1d, const Array& a) { - if (a.get_min_index()<=a.get_max_index()) + 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); @@ -52,8 +51,7 @@ get_min_indices_help(is_not_1d, const Array& a) } template -inline -BasicCoordinate<1, int> +inline BasicCoordinate<1, int> get_min_indices_help(is_1d, const Array<1, T>& a) { BasicCoordinate<1, int> result; @@ -62,85 +60,73 @@ get_min_indices_help(is_1d, const Array<1, T>& a) } template -inline -bool -next_help(is_1d, BasicCoordinate<1, int>& index, - const Array& a) +inline bool +next_help(is_1d, BasicCoordinate<1, int>& index, const Array& a) { - if (a.get_min_index()>a.get_max_index()) + 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) +inline bool +next_help(is_not_1d, BasicCoordinate& index, const Array& a) { - if (a.get_min_index()>a.get_max_index()) + 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 +inline BasicCoordinate get_min_indices(const Array& a) { return detail::get_min_indices_help(detail::test_if_1d(), a); } 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) +inline const Array& +get(const Array& a, const BasicCoordinate& c) { - return get(a[c[1]],cut_first_dimension(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) +inline const Array& +get(const Array& a, const BasicCoordinate<1, int>& c) { - return a[c[1]]; -} + return a[c[1]]; +} END_NAMESPACE_STIR diff --git a/src/include/stir/assign.h b/src/include/stir/assign.h index 9a99390c7..135295943 100644 --- a/src/include/stir/assign.h +++ b/src/include/stir/assign.h @@ -12,26 +12,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 @@ -45,62 +45,58 @@ START_NAMESPACE_STIR //@{ template - inline - void assign(T& x, const T2& y) +inline void +assign(T& x, const T2& y) { - x=y; + x = y; } template -inline -void assign(std::vector& v, const T2& y) +inline void +assign(std::vector& v, const T2& y) { - for (typename std::vector::iterator iter = v.begin(); - iter != v.end(); ++iter) + for (typename std::vector::iterator iter = v.begin(); iter != v.end(); ++iter) assign(*iter, y); } template -inline -void assign(BasicCoordinate& v, const T2& y) +inline void +assign(BasicCoordinate& v, const T2& y) { - for (typename BasicCoordinate::iterator iter = v.begin(); - iter != v.end(); ++iter) + for (typename BasicCoordinate::iterator iter = v.begin(); iter != v.end(); ++iter) assign(*iter, y); } template -inline -void assign(VectorWithOffset& v, const T2& y) +inline void +assign(VectorWithOffset& v, const T2& y) { - for (typename VectorWithOffset::iterator iter = v.begin(); - iter != v.end(); ++iter) + 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) +inline void +assign(Array& v, const T2& y) { - for (typename Array::full_iterator iter = v.begin_all(); - iter != v.end_all(); ++iter) + 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) +inline void +assign(double& x, const int y) { - x=static_cast(y); + x = static_cast(y); } -inline -void assign(float& x, const int y) +inline void +assign(float& x, const int y) { - x=static_cast(y); + x = static_cast(y); } //@} diff --git a/src/include/stir/assign_to_subregion.h b/src/include/stir/assign_to_subregion.h index 575117d15..64daa2d80 100644 --- a/src/include/stir/assign_to_subregion.h +++ b/src/include/stir/assign_to_subregion.h @@ -12,8 +12,8 @@ #define __stir_assign_to_subregion_H__ /*! - \file - \ingroup Array + \file + \ingroup Array \brief declares the stir::assign_to_subregion function \author Kris Thielemans @@ -23,23 +23,20 @@ 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 8da2bb833..6cd4ddf20 100644 --- a/src/include/stir/assign_to_subregion.inl +++ b/src/include/stir/assign_to_subregion.inl @@ -8,8 +8,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 @@ -19,30 +19,33 @@ 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, +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) + 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) + 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) + 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 - - + } +} +END_NAMESPACE_STIR diff --git a/src/include/stir/centre_of_gravity.h b/src/include/stir/centre_of_gravity.h index c2fccd9d6..3a1fc6017 100644 --- a/src/include/stir/centre_of_gravity.h +++ b/src/include/stir/centre_of_gravity.h @@ -9,9 +9,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 @@ -22,11 +22,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 @@ -36,8 +41,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 @@ -47,17 +51,15 @@ 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\>. -*/ +*/ template -T -find_unweighted_centre_of_gravity(const Array<1,T>& ); +T find_unweighted_centre_of_gravity(const Array<1, T>&); //! Compute centre of gravity of an Array /*! \ingroup Array @@ -68,8 +70,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 @@ -84,17 +85,15 @@ 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 bb3c8a41c..dfe270b61 100644 --- a/src/include/stir/common.h +++ b/src/include/stir/common.h @@ -7,15 +7,15 @@ SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license - 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 @@ -26,18 +26,18 @@ - 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: \c \#defines \c START_NAMESPACE_STIR etc.
        • -
        • preprocessor definitions which attempt to determine the +
        • preprocessor definitions which attempt to determine the operating system this is going to run on. use as \c "#ifdef __OS_WIN__ ... #elif ... #endif" Possible values are __OS_WIN__, __OS_MAC__, __OS_VAX__, __OS_UNIX__ @@ -56,13 +56,13 @@

          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
          • @@ -84,165 +84,207 @@ #include //*************** namespace macros -# 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; //*************** 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 -#endif // __OS_UNIX_ case +# 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 // !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 #endif // #ifdef STIR_SPEED_UP_STD_COPY - //*************** assert #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 @@ -252,9 +294,13 @@ constexpr double speed_of_light_in_mm_per_ps_div2 = speed_of_light_in_mm_per_ps //! 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 -#endif +#endif diff --git a/src/include/stir/config/gcc.h b/src/include/stir/config/gcc.h index f167fd76d..f11adfa25 100644 --- a/src/include/stir/config/gcc.h +++ b/src/include/stir/config/gcc.h @@ -7,15 +7,15 @@ SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license - 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 @@ -33,4 +33,4 @@ #if defined __GNUC__ #endif -#endif +#endif diff --git a/src/include/stir/config/visualc.h b/src/include/stir/config/visualc.h index c12292056..a67bd50ee 100644 --- a/src/include/stir/config/visualc.h +++ b/src/include/stir/config/visualc.h @@ -7,15 +7,15 @@ SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license - 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 @@ -30,25 +30,25 @@ It is included by stir/common.h. You should never include it directly. */ -#if defined(_MSC_VER) && _MSC_VER<=1300 -#error Compiler no longer supported +#if defined(_MSC_VER) && _MSC_VER <= 1300 +# error Compiler no longer supported #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 ec2781586..b8bcbb5c3 100644 --- a/src/include/stir/convert_array.h +++ b/src/include/stir/convert_array.h @@ -10,12 +10,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. @@ -29,30 +29,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 @@ -64,9 +65,7 @@ template class Array; */ template inline 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); /*! \ingroup Array @@ -74,23 +73,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. @@ -101,16 +100,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 @@ -119,15 +116,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 e4d9b0278..d424751a1 100644 --- a/src/include/stir/convert_array.inl +++ b/src/include/stir/convert_array.inl @@ -9,7 +9,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup Array \brief implementation of stir::convert_array @@ -25,35 +25,26 @@ 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) +convert_array(scaleT& scale_factor, const Array& data_in, const NumericInfo info_for_out_type) { - Array data_out(data_in.get_index_range()); + 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) +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()); + 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 4bfd7589a..cd421935e 100644 --- a/src/include/stir/convert_range.h +++ b/src/include/stir/convert_range.h @@ -12,9 +12,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 @@ -26,7 +26,8 @@ START_NAMESPACE_STIR -template class NumericInfo; +template +class NumericInfo; /*! \ingroup Array @@ -36,19 +37,20 @@ 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 @@ -56,15 +58,13 @@ 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 120fb904c..3e3277a24 100644 --- a/src/include/stir/convert_range.inl +++ b/src/include/stir/convert_range.inl @@ -10,7 +10,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup Array \brief implementation of stir::convert_range @@ -28,152 +28,153 @@ START_NAMESPACE_STIR // anonymous namespace for local functions -namespace +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; } +/* 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) + 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()) - { - // TODO could use different scale factor in this case as well, but at the moment we don't) - scale_factor = scaleT(1); - return; - } + { + // 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()); + 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_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) - { - // We need to convert to the maximum range in T2 - scale_factor = scaleT(tmp_scale); - } + { + // 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) +convert_range(const OutputIteratorT& out_begin, + scaleT& scale_factor, + const InputIteratorT& in_begin, + const InputIteratorT& in_end) { - typedef typename boost::iterator_value::type OutType; + typedef typename boost::iterator_value::type OutType; - find_scale_factor(scale_factor, in_begin, in_end, NumericInfo()); - if (scale_factor == 0) + 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); - } + 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)); - } - } - } + + // 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)); + } + } + } } // specialisation for equal Iterator types @@ -181,13 +182,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); } - END_NAMESPACE_STIR diff --git a/src/include/stir/copy_fill.h b/src/include/stir/copy_fill.h index 79d80c8c1..1ba374eec 100644 --- a/src/include/stir/copy_fill.h +++ b/src/include/stir/copy_fill.h @@ -27,22 +27,19 @@ 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> +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()); } @@ -51,58 +48,58 @@ 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<> +template <> struct CopyFill { - template < typename iterT> - static - iterT copy_to(const ProjData& stir_object, iterT iter) - { + 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); - } - } + { + // 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); - } + 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) +inline void +fill_from(T& stir_object, iterT iter, iterT iter_end) { - //return + // 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 1f1750fbf..2707fb1e2 100644 --- a/src/include/stir/cross_product.h +++ b/src/include/stir/cross_product.h @@ -11,11 +11,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 */ @@ -27,23 +27,19 @@ 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) +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()); + 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 c821ef48c..0e9e5b5df 100644 --- a/src/include/stir/data/SinglesRates.h +++ b/src/include/stir/data/SinglesRates.h @@ -34,7 +34,6 @@ START_NAMESPACE_STIR class TimeFrameDefinitions; - /*! \ingroup singles_buildblock @@ -46,73 +45,57 @@ class TimeFrameDefinitions; 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 @@ -128,9 +111,8 @@ class FrameSinglesRates */ class SinglesRates : public RegisteredObject { -public: - - ~SinglesRates () override {} +public: + ~SinglesRates() override {} //! Get the (average) 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 @@ -138,31 +120,23 @@ class SinglesRates : public RegisteredObject Default implementation uses `get_singles(...)/(end_time-start_time)`. */ - virtual float - get_singles_rate(const int singles_bin_index, - const double start_time, - const double end_time) const; + virtual float get_singles_rate(const int singles_bin_index, const double start_time, const double end_time) const; //! Get the number of singles 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(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(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). Default implementation uses Scanner::get_singles_bin_index() and get_singles_rate(int,double,double). */ - 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; //! Virtual function that returns the number of singles given the detection positions and time-interval of detection /*! The behaviour of this function is specified by the derived classes. @@ -172,19 +146,16 @@ class SinglesRates : public RegisteredObject Default implementation uses Scanner::get_singles_bin_index() and get_singles(int,double,double). */ - virtual float get_singles(const DetectionPosition<>& det_pos, - const double start_time, - const double end_time) const; + virtual float get_singles(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; - + #if 0 //! return time-intervals for singles that are recorded virtual TimeFrameDefinitions @@ -193,18 +164,9 @@ class SinglesRates : public RegisteredObject 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 920f19cc4..a5437a857 100644 --- a/src/include/stir/data/SinglesRates.inl +++ b/src/include/stir/data/SinglesRates.inl @@ -17,23 +17,18 @@ \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 4b57567bc..3b3b5788f 100644 --- a/src/include/stir/data/SinglesRatesForTimeFrames.h +++ b/src/include/stir/data/SinglesRatesForTimeFrames.h @@ -31,65 +31,51 @@ 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 for a particular singles unit and frame number. - /*! - The singles returned is the rate for a whole singles unit. - */ - float get_singles(int singles_bin_index, unsigned int frame_number) const; - - - /*! \brief get the singles for a particular singles unit and a frame with - the specified start and end times. - + //! Default constructor + SinglesRatesForTimeFrames(); + + // SinglesRatesForTimeFrames(const TimeFrameDefinitions& time_frame_definitions, + // const shared_ptr& scanner_sptr); + + //! get the singles for a particular singles unit and frame number. + /*! The singles returned is the rate for a whole singles unit. - - \warning Currently returns -1 if the \a start_time, \a end_time - does not correspond to a time frame. - */ - float get_singles(const int singles_bin_index, - const double start_time, const double end_time) const override; - - //! Generate a FramesSinglesRate - containing the average rates - // for a frame begining at start_time and ending at end_time. - FrameSinglesRates STIR_DEPRECATED 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(const int singles_bin_index, - const unsigned time_frame_num, - const float new_singles); - - //! 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; + */ + float get_singles(int singles_bin_index, unsigned int frame_number) const; -protected: + /*! \brief get the singles for a particular singles unit and a frame with + the specified start and end times. - Array<2,float> _singles; - TimeFrameDefinitions _time_frame_defs; + The singles returned is the rate for a whole singles unit. + + \warning Currently returns -1 if the \a start_time, \a end_time + does not correspond to a time frame. + */ + float get_singles(const int singles_bin_index, const double start_time, const double end_time) const override; + + //! Generate a FramesSinglesRate - containing the average rates + // for a frame begining at start_time and ending at end_time. + FrameSinglesRates STIR_DEPRECATED 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(const int singles_bin_index, const unsigned time_frame_num, const float new_singles); - + //! 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; + TimeFrameDefinitions _time_frame_defs; }; END_NAMESPACE_STIR - #endif diff --git a/src/include/stir/data/SinglesRatesForTimeSlices.h b/src/include/stir/data/SinglesRatesForTimeSlices.h index 1f12124ad..5a98e38e8 100644 --- a/src/include/stir/data/SinglesRatesForTimeSlices.h +++ b/src/include/stir/data/SinglesRatesForTimeSlices.h @@ -27,7 +27,6 @@ #include "stir/Array.h" #include "stir/TimeFrameDefinitions.h" - START_NAMESPACE_STIR /*! @@ -35,136 +34,118 @@ START_NAMESPACE_STIR \brief A class for singles that are recorded at equal time intervals */ -class SinglesRatesForTimeSlices : -public SinglesRates +class SinglesRatesForTimeSlices : public SinglesRates -{ +{ public: - - //! Default constructor - SinglesRatesForTimeSlices(); - - // implementation of pure virtual in SinglesRates - float - get_singles(const int singles_bin_index, - const double start_time, const double end_time) const override; - - - //! Generate a FramesSinglesRate - containing the average rates - // for a frame begining at start_time and ending at end_time. - FrameSinglesRates STIR_DEPRECATED 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; - - - #if 0 + //! Default constructor + SinglesRatesForTimeSlices(); + + // implementation of pure virtual in SinglesRates + float get_singles(const int singles_bin_index, const double start_time, const double end_time) const override; + + //! Generate a FramesSinglesRate - containing the average rates + // for a frame begining at start_time and ending at end_time. + FrameSinglesRates STIR_DEPRECATED 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; + +#if 0 //! 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; #endif - //! Set a singles by singles bin index and time slice. - void set_singles(int singles_bin_index, int time_slice, int new_singles); + //! Set a singles by singles bin index and time slice. + void set_singles(int singles_bin_index, int time_slice, int new_singles); + //! Rebin the sgl slices into a different set of consecutive slices. + // + // Returns the number of new bins. + int rebin(std::vector& new_end_times); - //! 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; + //! Get the vector of time values for each time slice index. + std::vector get_times() const; + // Some inspectors - // Some inspectors + //! Return the number of time slices. + int get_num_time_slices() const; - //! 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; - - //! Return the time interval per slice of singles data. - double get_singles_time_interval() const; + //! return time-intervals for every slice + TimeFrameDefinitions get_time_frame_definitions() const; - //! return time-intervals for every slice - TimeFrameDefinitions - get_time_frame_definitions() const; +protected: + //! total singles per time slice and singles-bin + /*!Indexed by time slice and singles bin index.*/ + Array<2, int> _singles; + //! end times of each time slice (in secs) + /*! expected to use equidistant sampling */ + std::vector _times; -protected: - - //! total singles per time slice and singles-bin - /*!Indexed by time slice and singles bin index.*/ - Array<2, int> _singles; - - //! end times of each time slice (in secs) - /*! expected to use equidistant sampling */ - std::vector _times; - - int _num_time_slices; - - //! time interval in secs - /*! \warning A value of zero for _singles_time_interval indicates that the time slices - are of different lengths. - However, some of the code probably doesn't check for this. - */ - double _singles_time_interval; - - //! Calculate and set _singles_time_interval from _times - void set_time_interval(); - - //! get slice start time. - double get_slice_start_time(int slice_index) const; - + int _num_time_slices; + + //! time interval in secs + /*! \warning A value of zero for _singles_time_interval indicates that the time slices + are of different lengths. + However, some of the code probably doesn't check for this. + */ + double _singles_time_interval; + + //! Calculate and set _singles_time_interval from _times + void set_time_interval(); + + //! get slice start time. + double get_slice_start_time(int slice_index) const; }; END_NAMESPACE_STIR - #endif diff --git a/src/include/stir/data/SinglesRatesFromECAT7.h b/src/include/stir/data/SinglesRatesFromECAT7.h index b25ea022d..3dd0805e6 100644 --- a/src/include/stir/data/SinglesRatesFromECAT7.h +++ b/src/include/stir/data/SinglesRatesFromECAT7.h @@ -30,36 +30,29 @@ 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 a19cbe3df..a2141a5b2 --- a/src/include/stir/data/SinglesRatesFromGEHDF5.h +++ b/src/include/stir/data/SinglesRatesFromGEHDF5.h @@ -24,10 +24,11 @@ #include "stir/data/SinglesRatesForTimeSlices.h" #include "stir/RegisteredParsingObject.h" - START_NAMESPACE_STIR -namespace GE { -namespace RDF_HDF5 { +namespace GE +{ +namespace RDF_HDF5 +{ class GEHDF5Wrapper; @@ -41,40 +42,33 @@ class GEHDF5Wrapper; \todo expose GE::RDF_HDF5::GEHDF5Wrapper.get_exam_info_sptr() */ -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; - //! Name which will be used when parsing a SinglesRatesFromGEHDF5 object - static const char * const registered_name; - - //! Default constructor - SinglesRatesFromGEHDF5(); + //! Default constructor + SinglesRatesFromGEHDF5(); - //! construct from filename - explicit SinglesRatesFromGEHDF5(const std::string& rdf_filename) - { read_from_file(rdf_filename); } + //! construct from filename + explicit SinglesRatesFromGEHDF5(const std::string& rdf_filename) { read_from_file(rdf_filename); } - void read_from_file(const std::string& rdf_filename); - + void read_from_file(const std::string& rdf_filename); private: + shared_ptr m_input_sptr; - shared_ptr m_input_sptr; - - std::string _rdf_filename; + std::string _rdf_filename; - void set_defaults() override; - void initialise_keymap() override; - bool post_processing() override; - + void set_defaults() override; + void initialise_keymap() override; + bool post_processing() override; }; -} // 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 f5976c8ec..2cc393d2a 100644 --- a/src/include/stir/data/SinglesRatesFromSglFile.h +++ b/src/include/stir/data/SinglesRatesFromSglFile.h @@ -25,79 +25,63 @@ #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 ECAT HR+ and HR++ (aka EXACT3D) 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. + }; - 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; - static const unsigned SIZE_OF_SINGLES_RECORD; + //! Name which will be used when parsing a SinglesRatesFromSglFile object + static const char* const registered_name; - //! Name which will be used when parsing a SinglesRatesFromSglFile object - static const char * const registered_name; + //! Default constructor + SinglesRatesFromSglFile(); + // IO Methods - //! Default constructor - SinglesRatesFromSglFile(); - - // IO Methods - - //! The function that reads singles from *.sgl file. - int read_singles_from_sgl_file(const std::string& sgl_filename); + //! The function that reads singles from *.sgl file. + int read_singles_from_sgl_file(const std::string& sgl_filename); /*! - * \brief Write the object to a stream in SGL format. - * \param[in] output The ostream to which the object will be written. - */ - std::ostream& write(std::ostream& output); + * \brief Write the object to a stream in SGL format. + * \param[in] output The ostream to which the object will be written. + */ + std::ostream& write(std::ostream& output); private: - - std::vector _total_prompts; - std::vector _total_randoms; - + std::vector _total_prompts; + std::vector _total_randoms; #ifdef HAVE_LLN_MATRIX - Main_header _singles_main_header; + Main_header _singles_main_header; #endif - - std::string _sgl_filename; - - virtual void set_defaults(); - virtual void initialise_keymap(); - virtual bool post_processing(); - -}; - - - - - + std::string _sgl_filename; + 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/data/randoms_from_singles.h b/src/include/stir/data/randoms_from_singles.h index 43a4b7370..ce5865331 100644 --- a/src/include/stir/data/randoms_from_singles.h +++ b/src/include/stir/data/randoms_from_singles.h @@ -19,7 +19,6 @@ #include "stir/common.h" - START_NAMESPACE_STIR class ProjData; @@ -68,7 +67,9 @@ class SinglesRates; \todo Dead-time is currently completely ignored. */ -void randoms_from_singles(ProjData& proj_data, const SinglesRates& singles, - float coincidence_time_window=-1.F, float radionuclide_halflife=-1.F); +void randoms_from_singles(ProjData& proj_data, + const SinglesRates& singles, + float coincidence_time_window = -1.F, + float radionuclide_halflife = -1.F); END_NAMESPACE_STIR diff --git a/src/include/stir/date_time_functions.h b/src/include/stir/date_time_functions.h index 699701dea..58137ca9d 100644 --- a/src/include/stir/date_time_functions.h +++ b/src/include/stir/date_time_functions.h @@ -8,9 +8,9 @@ */ /*! - \file + \file \ingroup date_time - + \brief Functions for date-time conversions \author Kris Thielemans @@ -45,7 +45,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) @@ -56,26 +56,25 @@ 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 \c time) \ingroup date_time */ struct DateTimeStrings { - DateTimeStrings() - {} + DateTimeStrings() {} DateTimeStrings(const std::string& date, const std::string& time) - : date(date), time(time) + : date(date), + time(time) {} std::string date, time; @@ -84,14 +83,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) @@ -101,15 +98,15 @@ 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) \ingroup date_time */ -DateTimeStrings -secs_since_Unix_epoch_to_Interfile_datetime(double secs, - int time_zone_offset_in_secs = current_time_zone_and_DST_offset_in_secs()); +DateTimeStrings secs_since_Unix_epoch_to_Interfile_datetime(double secs, + int time_zone_offset_in_secs + = current_time_zone_and_DST_offset_in_secs()); END_NAMESPACE_STIR diff --git a/src/include/stir/decay_correction_factor.h b/src/include/stir/decay_correction_factor.h index ea8bd2616..14e505baa 100644 --- a/src/include/stir/decay_correction_factor.h +++ b/src/include/stir/decay_correction_factor.h @@ -11,9 +11,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 @@ -27,22 +27,20 @@ START_NAMESPACE_STIR //! Compute decay-correction factor for a time frame /*! - \ingroup buildblock + \ingroup buildblock This function computes the factor needed 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; - - 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)); +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)); } //! Computes the decay-correction factor for activity at a given time point @@ -50,9 +48,10 @@ 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 d548649a2..04fa806b0 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. SPDX-License-Identifier: Apache-2.0 See STIR/LICENSE.txt for details @@ -8,7 +8,7 @@ #ifndef __stir_deprecated_H__ #define __stir_deprecated_H__ /*! - \file + \file \ingroup buildblock \brief This file declares a deprecation macro. */ @@ -16,15 +16,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 c4dbaec48..b98c26f7d 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 @@ -17,57 +17,67 @@ #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 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 +{ +}; - /*! \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 d678aad8e..a30dec31f 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 @@ -25,13 +25,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. @@ -43,24 +42,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. @@ -73,116 +72,91 @@ START_NAMESPACE_STIR */ // TODO, make version with CHARP ='string' but requires function overloading template -void display(const Array<3,elemT>& plane_stack, +void display(const Array<3, elemT>& plane_stack, const VectorWithOffset& scale_factors, const VectorWithOffset& text, double maxi = 0, - const char * const title = 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, +void display(const Array<3, elemT>& plane_stack, const VectorWithOffset& scale_factors, const VectorWithOffset& text, double maxi, - const char * const title , + 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 92b1d0fba..1e71f7cc2 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 @@ -30,126 +30,133 @@ 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); - } - - display(plane_stack, scale_factors, text, - maxi, title,zoom); + 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); // 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 af8f7ac4b..733f14f9e 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 @@ -24,7 +24,7 @@ */ /*! \namespace boost - \brief Namespace for the boost library + \brief Namespace for the boost library see http://www.boost.org */ @@ -40,31 +40,37 @@ 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 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) @@ -76,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.
            @@ -84,8 +90,8 @@ template \par Example: \code - - { + + { // ok shared_ptr i_ptr1(new int (2)); shared_ptr i_ptr2(i_ptr1); @@ -98,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); @@ -107,7 +113,8 @@ 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 d79f549f9..91d729dd7 100644 --- a/src/include/stir/doxygengroups.h +++ b/src/include/stir/doxygengroups.h @@ -34,7 +34,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. */ @@ -42,16 +42,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. */ @@ -59,7 +59,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) @@ -86,11 +85,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 */ /*! @@ -138,7 +137,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 @@ -177,7 +176,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 */ @@ -186,18 +185,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. */ /*! @@ -214,19 +213,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 @@ -244,18 +243,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. @@ -266,7 +265,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. */ /*! @@ -355,7 +354,7 @@ building blocks for scatter estimation Library for displaying of images */ /*! -\defgroup para Parallel library +\defgroup para Parallel library \ingroup STIR_library */ @@ -376,9 +375,6 @@ Library for displaying of images \ingroup alltest */ - - - /*! \defgroup main_programs Executables \ingroup STIR @@ -398,8 +394,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 5e50366c5..4305a286d 100644 --- a/src/include/stir/doxygenmain.h +++ b/src/include/stir/doxygenmain.h @@ -16,16 +16,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 @@ -33,16 +33,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 28bc75077..88fe00a20 100644 --- a/src/include/stir/error.h +++ b/src/include/stir/error.h @@ -31,7 +31,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 @@ -46,9 +46,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 @@ -76,9 +74,7 @@ inline void error(const STRING& string) { std::stringstream sstr; - sstr << "\nERROR: " - << string - << std::endl; + sstr << "\nERROR: " << string << std::endl; writeText(sstr.str().c_str(), ERROR_CHANNEL); throw std::runtime_error(sstr.str()); } diff --git a/src/include/stir/evaluation/ROIValues.h b/src/include/stir/evaluation/ROIValues.h index a2548a2cf..8af54b91d 100644 --- a/src/include/stir/evaluation/ROIValues.h +++ b/src/include/stir/evaluation/ROIValues.h @@ -29,81 +29,69 @@ 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 { 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; - 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); - 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; @@ -114,7 +102,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 70bb2a181..e4430f470 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 */ @@ -24,72 +24,62 @@ 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 can be first discretised using Shape3D::construct_volume or a Shape3D parsed. 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 + 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); - -void -compute_ROI_values_per_plane(VectorWithOffset& values, - const DiscretisedDensity<3,float>& image, - const DiscretisedDensity<3,float>& discretised_shape); - - -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 - ); - -ROIValues -compute_total_ROI_values(const DiscretisedDensity<3,float>& image, - const DiscretisedDensity<3,float>& discretised_shape); - -// 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); + +void compute_ROI_values_per_plane(VectorWithOffset& values, + const DiscretisedDensity<3, float>& image, + const DiscretisedDensity<3, float>& discretised_shape); + +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); + +ROIValues compute_total_ROI_values(const DiscretisedDensity<3, float>& image, + const DiscretisedDensity<3, float>& discretised_shape); + +// 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 c50597826..fef294edc 100644 --- a/src/include/stir/extend_projdata.h +++ b/src/include/stir/extend_projdata.h @@ -12,7 +12,7 @@ /* \ingroup projdata \file Functions that extend a direct sinogram or segment. - + \author Charalampos Tsoumpas \author Kris Thielemans \author Markus Jehl @@ -20,11 +20,11 @@ START_NAMESPACE_STIR //@{ -/*! +/*! \ingroup projdata \brief Extension of direct projection data. -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. @@ -42,9 +42,10 @@ This is probably only useful before calling interpolation routines, or for FORE. \param[in] axial_extension how many axial bins to add either side of the segment \param[in] tangential_extension how many tangential bins to add either side of the segment */ -Array<3,float> -extend_segment(const SegmentBySinogram& segment, const int view_extension = 5, - const int axial_extension = 5, const int tangential_extension = 5); +Array<3, float> extend_segment(const SegmentBySinogram& segment, + const int view_extension = 5, + const int axial_extension = 5, + const int tangential_extension = 5); //@} END_NAMESPACE_STIR diff --git a/src/include/stir/extract_line.h b/src/include/stir/extract_line.h index 36c691240..10b6b93dd 100644 --- a/src/include/stir/extract_line.h +++ b/src/include/stir/extract_line.h @@ -23,18 +23,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 e40e06b68..45e3429fd 100644 --- a/src/include/stir/extract_line.inl +++ b/src/include/stir/extract_line.inl @@ -21,24 +21,22 @@ 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_STIR_config.h b/src/include/stir/find_STIR_config.h index be2d19c05..e69d1c96e 100644 --- a/src/include/stir/find_STIR_config.h +++ b/src/include/stir/find_STIR_config.h @@ -18,7 +18,6 @@ #ifndef __stir_FINDSTIRCONFIG_H #define __stir_FINDSTIRCONFIG_H - #include #include "stir/common.h" START_NAMESPACE_STIR @@ -37,7 +36,7 @@ std::string find_STIR_config_file(const std::string& filename); \brief find string with the (full) path of the directory where looks for STIR configuration files \return path name - First checks an environment variable `STIR_CONFIG_DIR`. If that isn't set, + First checks an environment variable `STIR_CONFIG_DIR`. If that isn't set, it returns the value of the `STIR_CONFIG_DIR` CMake variable set at build time (which has a default location in the installation directory). diff --git a/src/include/stir/find_fwhm_in_image.h b/src/include/stir/find_fwhm_in_image.h index f517e2d0e..5e7b89cd4 100644 --- a/src/include/stir/find_fwhm_in_image.h +++ b/src/include/stir/find_fwhm_in_image.h @@ -18,8 +18,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" @@ -27,18 +27,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. @@ -48,9 +48,9 @@ START_NAMESPACE_STIR */ template inline float find_level_width(const RandomAccessIterType& begin_iterator, - const RandomAccessIterType& max_iterator, - const RandomAccessIterType& end_iterator, - const float level_height); + const RandomAccessIterType& max_iterator, + const RandomAccessIterType& end_iterator, + const float level_height); /*! \ingroup resolution \brief find width at a level @@ -59,42 +59,38 @@ 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 @@ -103,44 +99,44 @@ interpolate_line(const Array<3,elemT>& input_array, template struct ResolutionIndex { - elemT voxel_value; - BasicCoordinate voxel_location; - BasicCoordinate resolution; -}; + 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 a0a8c3ea8..7ea498078 100644 --- a/src/include/stir/find_fwhm_in_image.inl +++ b/src/include/stir/find_fwhm_in_image.inl @@ -22,18 +22,19 @@ #include "stir/warning.h" 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) + 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!"); @@ -41,32 +42,29 @@ float find_level_width(const RandomAccessIterType& begin_iterator, --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) + 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; -} - + 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; +} + template -float find_level_width(const RandomAccessIterType& begin_iterator, - const RandomAccessIterType& end_iterator, - const float 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); + 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 35efdbf0c..91d18aa3b 100644 --- a/src/include/stir/geometry/line_distances.h +++ b/src/include/stir/geometry/line_distances.h @@ -1,8 +1,8 @@ // // -/*! - \file +/*! + \file \ingroup geometry \brief A few functions to compute distances between lines etc \todo move implementations to .cxx @@ -24,10 +24,13 @@ #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 @@ -35,15 +38,14 @@ 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 +inline coordT coordinate_between_2_lines(CartesianCoordinate3D& result, - const LORAs2Points& line0, - const LORAs2Points& line1) + const LORAs2Points& line0, + const LORAs2Points& line1) { /* Rationale: parametrise points on the lines as @@ -55,71 +57,65 @@ 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; + // 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; + 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; + return 0; else - { - assert(false); - return std::sqrt(distance_squared); // will return NaN - } + { + 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 @@ -132,28 +128,28 @@ 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; + if (-distance_squared < d0d0 * 10E-5) + return 0; else - { - assert(false); - return std::sqrt(distance_squared); // will return NaN - } + { + assert(false); + return std::sqrt(distance_squared); // will return NaN + } } } @@ -164,24 +160,22 @@ distance_between_line_and_point( */ template inline void -project_point_on_a_line( - const CartesianCoordinate3D& p1, - const CartesianCoordinate3D& p2, - CartesianCoordinate3D& r1 ) +project_point_on_a_line(const CartesianCoordinate3D& p1, + const CartesianCoordinate3D& p2, + CartesianCoordinate3D& r1) { - const CartesianCoordinate3D difference = p2 - p1; - - const CartesianCoordinate3D r10 = r1 - p1; + const CartesianCoordinate3D difference = p2 - p1; - float inner_prod = inner_product(difference, difference); + const CartesianCoordinate3D r10 = r1 - p1; - const float u = inner_product(r10, difference) / inner_prod ; + float inner_prod = inner_product(difference, difference); - r1.x() = p1.x() + u * difference.x(); - r1.y() = p1.y() + u * difference.y(); - r1.z() = p1.z() + u * difference.z(); + 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(); } END_NAMESPACE_STIR diff --git a/src/include/stir/getopt.h b/src/include/stir/getopt.h index e937537e2..aa75c86bd 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,155 +36,154 @@ 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 +extern "C" +{ +# endif -#ifdef __cplusplus -extern "C" { -#endif + /* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - 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 + and for communication between successive calls to `getopt'. -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. + On entry to `getopt', zero means this is the first call; initialize. - On entry to `getopt', zero means this is the first call; initialize. + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ + extern int optind; -extern int optind; + /* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ + extern int opterr; -extern int opterr; + /* Set to an option character which was unrecognized. */ -/* Set to an option character which was unrecognized. */ + extern int optopt; -extern int optopt; +# 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 + zero. -#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 - zero. + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - 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 + /* 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 val; + }; -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 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 */ - - -/* Get definitions and prototypes for functions to process the - arguments in ARGV (ARGC of them, minus the program name) for - options given in OPTS. - - Return the option character from OPTS just read. Return -1 when - there are no more options. For unrecognized options, or options - missing arguments, `optopt' is set to the option letter, and '?' is - returned. - - The OPTS string is a list of characters which are recognized option - letters, optionally followed by colons, specifying that that letter - takes an argument, to be placed in `optarg'. - - If a letter in OPTS is followed by two colons, its argument is - optional. This behavior is specific to the GNU `getopt'. - - The argument `--' causes premature termination of argument - scanning, explicitly telling `getopt' that there are no more - options. - - If OPTS begins with `--', then non-option arguments are treated as - arguments to the option '\0'. This behavior is specific to the GNU - `getopt'. */ - -#if (defined __STDC__ && __STDC__) || defined __cplusplus + /* 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 */ + + /* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + +# 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); + /* 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 (); + // 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 +# 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 } -#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 63c1710c5..bdda53760 100644 --- a/src/include/stir/index_at_maximum.h +++ b/src/include/stir/index_at_maximum.h @@ -38,63 +38,64 @@ 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) + 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; - } + 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 27aaf3194..b10792d4e 100644 --- a/src/include/stir/info.h +++ b/src/include/stir/info.h @@ -33,7 +33,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. @@ -50,11 +50,12 @@ 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); - } + 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 9c6a1f914..da53c8907 100644 --- a/src/include/stir/interfile_keyword_functions.h +++ b/src/include/stir/interfile_keyword_functions.h @@ -15,11 +15,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 START_NAMESPACE_STIR @@ -29,17 +28,16 @@ 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. @@ -49,9 +47,7 @@ struct interfile_less { bool operator()(const std::string& a, const std::string& b) const { - return - standardise_interfile_keyword(a) < - standardise_interfile_keyword(b); + return standardise_interfile_keyword(a) < standardise_interfile_keyword(b); } }; diff --git a/src/include/stir/interpolate.h b/src/include/stir/interpolate.h index ebbf4f1a5..c2f24a2eb 100644 --- a/src/include/stir/interpolate.h +++ b/src/include/stir/interpolate.h @@ -12,9 +12,9 @@ #ifndef __interpolate_H__ #define __interpolate_H__ /*! - \file + \file \ingroup buildblock - + \brief declares functions for interpolation \warning will be moved to numerics @@ -23,7 +23,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 9e0a691f9..43889ca8a 100644 --- a/src/include/stir/interpolate_projdata.h +++ b/src/include/stir/interpolate_projdata.h @@ -11,7 +11,7 @@ /* \ingroup projdata \file Declaration of stir::interpolate_projdata - + \author Charalampos Tsoumpas \author Kris Thielemans @@ -22,46 +22,43 @@ 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); -Succeeded -interpolate_projdata(ProjData& proj_data_out, - const ProjData& proj_data_in, - const BasicCoordinate<3, BSpline::BSplineType> & these_types, - const bool remove_interleaving); +Succeeded interpolate_projdata(ProjData& proj_data_out, + const ProjData& proj_data_in, + const BSpline::BSplineType spline_type, + const bool remove_interleaving = false); +Succeeded interpolate_projdata(ProjData& proj_data_out, + const ProjData& proj_data_in, + const BasicCoordinate<3, BSpline::BSplineType>& these_types, + const bool remove_interleaving); //@} END_NAMESPACE_STIR - - - diff --git a/src/include/stir/inverse_SSRB.h b/src/include/stir/inverse_SSRB.h index b6b832cef..12995dc72 100644 --- a/src/include/stir/inverse_SSRB.h +++ b/src/include/stir/inverse_SSRB.h @@ -11,13 +11,12 @@ /* \ingroup projdata \file Declaration of stir::inverse_SSRB - + \author Charalampos Tsoumpas \author Kris Thielemans */ - #include "stir/common.h" START_NAMESPACE_STIR @@ -25,16 +24,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. @@ -42,11 +41,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 483c83dd8..186e4fd76 100644 --- a/src/include/stir/is_null_ptr.h +++ b/src/include/stir/is_null_ptr.h @@ -26,38 +26,38 @@ 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 +inline bool is_null_ptr(shared_ptr const& sptr) -{ return is_null_ptr(sptr.get()); } +{ + return is_null_ptr(sptr.get()); +} template -inline -bool +inline bool is_null_ptr(unique_ptr const& aptr) -{ return is_null_ptr(aptr.get()); } +{ + return is_null_ptr(aptr.get()); +} #ifndef BOOST_NO_CXX11_NULLPTR -inline -bool +inline bool is_null_ptr(const std::nullptr_t) { return true; diff --git a/src/include/stir/line.h b/src/include/stir/line.h index f0f1cc7f3..b08db1433 100644 --- a/src/include/stir/line.h +++ b/src/include/stir/line.h @@ -24,7 +24,6 @@ #ifndef __stir_LINE_H__ #define __stir_LINE_H__ - #include "stir/common.h" #include @@ -39,28 +38,27 @@ START_NAMESPACE_STIR 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); +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 2c48e0d8b..4fd3112ab 100644 --- a/src/include/stir/linear_regression.h +++ b/src/include/stir/linear_regression.h @@ -31,35 +31,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 @@ -69,21 +69,20 @@ 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 @@ -103,29 +102,28 @@ 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 477ad1af3..bab79aaec 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 @@ -25,136 +25,141 @@ 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 +/* + 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 +inline void linear_regression_compute_S(double& S, - double& Sx, + double& Sx, double& Sy, double& Syy, double& Stt, double& Sty, - const DataIter data_begin, const DataIter data_end, - const CoordinatesIter coords_begin, + 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) - { - const double weight = static_cast(*weights_iter); - S += weight; - Sx += weight * (*coords_iter); - Sy += weight * (*data_iter); - Syy += weight * square(static_cast(*data_iter)); - } + { + const double weight = static_cast(*weights_iter); + S += weight; + Sx += weight * (*coords_iter); + Sy += weight * (*data_iter); + Syy += weight * square(static_cast(*data_iter)); + } 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; - Sty += *weights_iter * wti * *data_iter; - } + { + const double wti = (*coords_iter - Sx / S); + Stt += *weights_iter * wti * wti; + Sty += *weights_iter * wti * *data_iter; + } } } // end namespace detail template -inline void -linear_regression(Value& constant, Value& scale, +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, + 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); - detail::linear_regression_compute_fit_from_S(constant, scale, + 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, + S, + Sx, + Sy, + Syy, + Stt, + Sty, static_cast(data_end - data_begin), use_estimated_variance); - } template -inline void -linear_regression(Value& constant, Value& scale, +inline void +linear_regression(Value& constant, + Value& scale, Value& chi_square, Value& variance_of_constant, Value& variance_of_scale, @@ -162,55 +167,61 @@ linear_regression(Value& constant, Value& scale, const VectorWithOffset& measured_data, const VectorWithOffset& coordinates, const VectorWithOffset& weights, - const bool use_estimated_variance - ) + 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, + linear_regression(constant, + scale, chi_square, variance_of_constant, variance_of_scale, covariance_of_constant_with_scale, - measured_data.begin(), measured_data.end(), + measured_data.begin(), + measured_data.end(), coordinates.begin(), weights.begin(), use_estimated_variance); } template -inline void +inline void linear_regression(ValueIter value_begin, - DataIter data_begin, DataIter data_end, - CoordinatesIter coords_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); - - 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, + detail::linear_regression_compute_S(S, Sx, Sy, Syy, Stt, Sty, data_begin, data_end, coords_begin, weights_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; + *(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 2956a4367..2d121b672 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) 2023, University College London @@ -28,10 +28,12 @@ START_NAMESPACE_STIR /*! \ingroup listmode At present, could just as well be a `typedef`. */ -class CListEventCylindricalScannerWithDiscreteDetectors : public CListEventScannerWithDiscreteDetectors +class CListEventCylindricalScannerWithDiscreteDetectors + : public CListEventScannerWithDiscreteDetectors { - private: +private: typedef CListEventScannerWithDiscreteDetectors base_type; + public: using base_type::base_type; }; diff --git a/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.h b/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.h index a90d8fa78..7c54a9111 100644 --- a/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.h +++ b/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.h @@ -12,9 +12,9 @@ \file \ingroup listmode \brief Definition of class stir::CListEventCylindricalScannerWithViewTangRingRingEncoding - + \author Kris Thielemans - + */ #ifndef __stir_listmode_CListEventCylindricalScannerWithViewTangRingRingEncoding_H__ @@ -25,15 +25,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 @@ -50,33 +49,30 @@ 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 +class CListEventCylindricalScannerWithViewTangRingRingEncoding : public CListEventCylindricalScannerWithDiscreteDetectors { - public: - CListEventCylindricalScannerWithViewTangRingRingEncoding(const shared_ptr& proj_data_info) : - CListEventCylindricalScannerWithDiscreteDetectors(proj_data_info) - {} +public: + CListEventCylindricalScannerWithViewTangRingRingEncoding(const shared_ptr& proj_data_info) + : CListEventCylindricalScannerWithDiscreteDetectors(proj_data_info) + {} - //! This routine returns the corresponding detector pair + //! 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() @@ -84,7 +80,6 @@ public CListEventCylindricalScannerWithDiscreteDetectors * this check avoids a crash when an unsupported template is used as input. */ inline virtual bool is_valid_template(const ProjDataInfo&) const; - }; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.inl b/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.inl index aedc72710..ca7897649 100644 --- a/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.inl +++ b/src/include/stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.inl @@ -13,113 +13,101 @@ \file \ingroup listmode \brief Implementation for stir::CListEventCylindricalScannerWithViewTangRingRingEncoding - + \author Kris Thielemans \author Elise Emond \author Nikos Efthimiou - + */ START_NAMESPACE_STIR template -void -CListEventCylindricalScannerWithViewTangRingRingEncoding:: -get_detection_position(DetectionPositionPair<>& det_pos) const +void +CListEventCylindricalScannerWithViewTangRingRingEncoding::get_detection_position(DetectionPositionPair<>& det_pos) const { - det_pos.pos1().radial_coord()=0; - det_pos.pos2().radial_coord()=0; + 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()); + 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()); - } + { + 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_cast(this)->get_data().set_sinogram_and_ring_coordinates( + view_num, tangential_pos_num, det_pos.pos2().axial_coord(), det_pos.pos1().axial_coord()); + } if (this->get_uncompressed_proj_data_info_sptr()->is_tof_data()) - error("TODO: CListEventCylindricalScannerWithViewTangRingRingEncoding::set_detection_position needs to be implemented for TOF"); + error( + "TODO: CListEventCylindricalScannerWithViewTangRingRingEncoding::set_detection_position needs to be implemented for TOF"); } 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) + 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; } 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 +void +CListEventCylindricalScannerWithViewTangRingRingEncoding::get_bin(Bin& bin, const ProjDataInfo& proj_data_info) const { - assert (dynamic_cast(&proj_data_info)!=0); + 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)); bin.timing_pos_num() = proj_data_info.get_tof_bin(delta_time); } template bool -CListEventCylindricalScannerWithViewTangRingRingEncoding:: -is_valid_template(const ProjDataInfo& proj_data_info) const +CListEventCylindricalScannerWithViewTangRingRingEncoding::is_valid_template(const ProjDataInfo& proj_data_info) const { - if (dynamic_cast(&proj_data_info)!= 0) - return true; + if (dynamic_cast(&proj_data_info) != 0) + return true; - return false; + return false; } - + END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListEventScannerWithDiscreteDetectors.h b/src/include/stir/listmode/CListEventScannerWithDiscreteDetectors.h index 3a186245f..1e170ee95 100644 --- a/src/include/stir/listmode/CListEventScannerWithDiscreteDetectors.h +++ b/src/include/stir/listmode/CListEventScannerWithDiscreteDetectors.h @@ -4,9 +4,9 @@ \file \ingroup listmode \brief Declarations of class stir::CListEventScannerWithDiscreteDetectors - + \author Kris Thielemans - + */ /* Copyright (C) 2003- 2011, Hammersmith Imanet Ltd @@ -36,13 +36,11 @@ template class CListEventScannerWithDiscreteDetectors : public CListEvent { public: - explicit CListEventScannerWithDiscreteDetectors(const shared_ptr& proj_data_info); - const Scanner * get_scanner_ptr() const - { return this->uncompressed_proj_data_info_sptr->get_scanner_ptr(); } + 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" @@ -58,7 +56,7 @@ class CListEventScannerWithDiscreteDetectors : 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 ProjDataInfoT. However, because of efficiency reasons this is only checked in debug mode (NDEBUG not defined). */ @@ -71,19 +69,13 @@ class CListEventScannerWithDiscreteDetectors : public CListEvent */ inline bool is_valid_template(const ProjDataInfo&) const override; - protected: - shared_ptr - get_uncompressed_proj_data_info_sptr() const - { - return uncompressed_proj_data_info_sptr; - } - - //shared_ptr scanner_sptr; +protected: + shared_ptr get_uncompressed_proj_data_info_sptr() const { return uncompressed_proj_data_info_sptr; } - private: - shared_ptr - uncompressed_proj_data_info_sptr; + // shared_ptr scanner_sptr; +private: + shared_ptr uncompressed_proj_data_info_sptr; }; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListEventScannerWithDiscreteDetectors.inl b/src/include/stir/listmode/CListEventScannerWithDiscreteDetectors.inl index ee29616bd..a2c91bcc9 100644 --- a/src/include/stir/listmode/CListEventScannerWithDiscreteDetectors.inl +++ b/src/include/stir/listmode/CListEventScannerWithDiscreteDetectors.inl @@ -4,7 +4,7 @@ \file \ingroup listmode \brief Implementations of class stir::CListEventScannerWithDiscreteDetectors - + \author Kris Thielemans \author Nikos Efthimiou \author Elise Emond @@ -28,23 +28,24 @@ START_NAMESPACE_STIR template -CListEventScannerWithDiscreteDetectors:: -CListEventScannerWithDiscreteDetectors(const shared_ptr& proj_data_info_sptr) +CListEventScannerWithDiscreteDetectors::CListEventScannerWithDiscreteDetectors( + const shared_ptr& proj_data_info_sptr) { if (!proj_data_info_sptr) error("CListEventScannerWithDiscreteDetectors constructor called with zero pointer"); auto scanner_sptr = proj_data_info_sptr->get_scanner_sptr(); // get bare pointer of uncompressed ProjDataInfo - auto pdi_ptr = - ProjDataInfo::construct_proj_data_info(scanner_sptr, - 1, scanner_sptr->get_num_rings()-1, - scanner_sptr->get_num_detectors_per_ring()/2, - scanner_sptr->get_max_num_non_arccorrected_bins(), - /* arc correction = */ false, - /* TOF mashing = */ 1).release(); + auto pdi_ptr = ProjDataInfo::construct_proj_data_info(scanner_sptr, + 1, + scanner_sptr->get_num_rings() - 1, + scanner_sptr->get_num_detectors_per_ring() / 2, + scanner_sptr->get_max_num_non_arccorrected_bins(), + /* arc correction = */ false, + /* TOF mashing = */ 1) + .release(); // check type - auto pdi_ptr_cast = dynamic_cast(pdi_ptr); + auto pdi_ptr_cast = dynamic_cast(pdi_ptr); if (!pdi_ptr_cast) { delete pdi_ptr; @@ -56,8 +57,7 @@ CListEventScannerWithDiscreteDetectors(const shared_ptr& pro template LORAs2Points -CListEventScannerWithDiscreteDetectors:: -get_LOR() const +CListEventScannerWithDiscreteDetectors::get_LOR() const { LORAs2Points lor; const bool swap = true; @@ -67,53 +67,50 @@ 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(), - det_pos.timing_pos()); + 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(), + det_pos.timing_pos()); // find shift in z - 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; + 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; } - template -void -CListEventScannerWithDiscreteDetectors:: -get_bin(Bin& bin, const ProjDataInfo& proj_data_info) const +void +CListEventScannerWithDiscreteDetectors::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 - { - bin.set_bin_value(1); - } + { + bin.set_bin_value(1); + } } template bool -CListEventScannerWithDiscreteDetectors:: -is_valid_template(const ProjDataInfo& proj_data_info) const +CListEventScannerWithDiscreteDetectors::is_valid_template(const ProjDataInfo& proj_data_info) const { - if (dynamic_cast(&proj_data_info)!= 0) - return true; + if (dynamic_cast(&proj_data_info) != 0) + return true; - return false; + return false; } END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListModeData.h b/src/include/stir/listmode/CListModeData.h index 58fc88139..902b4eaf6 100644 --- a/src/include/stir/listmode/CListModeData.h +++ b/src/include/stir/listmode/CListModeData.h @@ -12,7 +12,7 @@ \file \ingroup listmode \brief Declaration of class stir::CListModeData - + \author Daniel Deidda \author Kris Thielemans */ @@ -28,8 +28,11 @@ #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 @@ -51,13 +54,11 @@ class CListModeData : public ListModeData /*! 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) bool has_delayeds() const override = 0; @@ -65,12 +66,12 @@ class CListModeData : public ListModeData protected: shared_ptr get_empty_record_helper_sptr() const override { - shared_ptr sptr(this->get_empty_record_sptr()); - shared_ptr sptr1(static_pointer_cast(sptr)); - return sptr1;} + shared_ptr sptr(this->get_empty_record_sptr()); + shared_ptr sptr1(static_pointer_cast(sptr)); + return sptr1; + } - Succeeded get_next(ListRecord& event) const override - {return this->get_next_record((CListRecord&)(event));} + Succeeded get_next(ListRecord& event) const override { 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 b9817aaa0..f18a80429 100644 --- a/src/include/stir/listmode/CListModeDataECAT.h +++ b/src/include/stir/listmode/CListModeDataECAT.h @@ -11,7 +11,7 @@ \file \ingroup listmode \brief Declaration of class stir::CListModeDataECAT - + \author Kris Thielemans */ @@ -21,9 +21,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 @@ -37,7 +37,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. @@ -50,29 +50,23 @@ 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 */ @@ -81,16 +75,16 @@ class CListModeDataECAT : public CListModeData 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 69eb1affc..c51f5f89c 100644 --- a/src/include/stir/listmode/CListModeDataECAT8_32bit.h +++ b/src/include/stir/listmode/CListModeDataECAT8_32bit.h @@ -10,7 +10,7 @@ \file \ingroup listmode \brief Declaration of class stir::ecat::CListModeDataECAT8_32bit - + \author Kris Thielemans */ @@ -26,11 +26,12 @@ #include START_NAMESPACE_STIR -namespace ecat { +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. @@ -44,23 +45,17 @@ class CListModeDataECAT8_32bit : public CListModeData //! Construct fron the filename of the Interfile header CListModeDataECAT8_32bit(const std::string& listmode_filename_prefix); - std::string - get_name() const override; + std::string get_name() const override; - - shared_ptr get_empty_record_sptr() const override; + shared_ptr get_empty_record_sptr() const override; - - Succeeded get_next_record(CListRecord& record) const override; + Succeeded get_next_record(CListRecord& record) const override; - - Succeeded reset() override; + Succeeded reset() override; - - SavedPosition save_get_position() override; + SavedPosition save_get_position() override; - - Succeeded set_get_position(const SavedPosition&) override; + Succeeded set_get_position(const SavedPosition&) override; //! returns \c true, as ECAT listmode data stores delayed events (and prompts) /*! \todo this might depend on the acquisition parameters */ @@ -69,15 +64,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 4e24c9cbc..aac7011b7 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,10 +24,11 @@ #include #include - START_NAMESPACE_STIR -namespace GE { -namespace RDF_HDF5 { +namespace GE +{ +namespace RDF_HDF5 +{ //! A class that reads the listmode data for GE scanners using the RDF9 format /*! \ingroup listmode @@ -41,46 +42,38 @@ class CListModeDataGEHDF5 : public CListModeData //! Constructor taking a filename CListModeDataGEHDF5(const std::string& listmode_filename); - std::string - get_name() const override; + std::string get_name() const override; - 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; - - shared_ptr get_empty_record_sptr() const override; + shared_ptr get_empty_record_sptr() const override; - - Succeeded get_next_record(CListRecord& record) const override; + Succeeded get_next_record(CListRecord& record) const override; - - Succeeded reset() override; + Succeeded reset() override; - - SavedPosition save_get_position() override; + SavedPosition save_get_position() override; - - Succeeded set_get_position(const SavedPosition&) override; + Succeeded set_get_position(const SavedPosition&) override; //! returns \c false, as GEHDF5 listmode data does not store delayed events (and prompts) /*! \todo this depends on the acquisition parameters */ bool has_delayeds() const override { 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> 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/CListModeDataPENN.h b/src/include/stir/listmode/CListModeDataPENN.h index f1d06d5a4..a981d26cf 100644 --- a/src/include/stir/listmode/CListModeDataPENN.h +++ b/src/include/stir/listmode/CListModeDataPENN.h @@ -27,66 +27,56 @@ START_NAMESPACE_STIR class CListModeDataPENN : public CListModeData { public: - //! Construct fron the filename of the Interfile header - CListModeDataPENN(const std::string& listmode_filename_prefix); + //! Construct fron the filename of the Interfile header + CListModeDataPENN(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&); - //! The safest way to get the total number of events is to count them. - virtual inline - unsigned long int get_total_number_of_events() const - { - shared_ptr sptr(new CListRecordT(this->get_proj_data_info_sptr()->get_scanner_sptr())); - CListRecordPENN& record = static_cast(*sptr); + //! The safest way to get the total number of events is to count them. + virtual inline unsigned long int get_total_number_of_events() const + { + shared_ptr sptr(new CListRecordT(this->get_proj_data_info_sptr()->get_scanner_sptr())); + CListRecordPENN& record = static_cast(*sptr); - return lm_data_sptr->get_total_number_of_events(record); - } + return lm_data_sptr->get_total_number_of_events(record); + } - virtual bool has_delayeds() const { return true; } + virtual bool has_delayeds() const { return true; } -// inline const PET::ListFileHeader* get_file_header() const -// { -// return current_lm_data_ptr->get_file_header(); -// } + // inline const PET::ListFileHeader* get_file_header() const + // { + // return current_lm_data_ptr->get_file_header(); + // } - inline void set_output_filename(const std::string ofname) - { - lm_data_sptr->create_output_file(ofname); - } + inline void set_output_filename(const std::string ofname) { lm_data_sptr->create_output_file(ofname); } - inline void set_event() - { - lm_data_sptr->set_current_record(); - } + inline void set_event() { lm_data_sptr->set_current_record(); } - void set_event(const bool& is_delay, - const short int& _dt, - const unsigned short int& _xa, const unsigned short int& _xb, - const unsigned short int& _za, const unsigned short int& _zb, - const unsigned short int& _ea, const unsigned short int& _eb); + void set_event(const bool& is_delay, + const short int& _dt, + const unsigned short int& _xa, + const unsigned short int& _xb, + const unsigned short int& _za, + const unsigned short int& _zb, + const unsigned short int& _ea, + const unsigned short int& _eb); private: - typedef CListRecordPENN CListRecordT; - std::string listmode_filename; - shared_ptr lm_data_sptr; + typedef CListRecordPENN CListRecordT; + std::string listmode_filename; + shared_ptr lm_data_sptr; - std::string filename; + std::string filename; }; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/CListModeDataROOT.h b/src/include/stir/listmode/CListModeDataROOT.h index a14beadf2..86760b5e8 100644 --- a/src/include/stir/listmode/CListModeDataROOT.h +++ b/src/include/stir/listmode/CListModeDataROOT.h @@ -38,7 +38,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 @@ -61,7 +61,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) @@ -73,11 +73,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 @@ -100,112 +100,102 @@ 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 { 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 - std::string - get_name() const override; - //! Set private members default values; - void set_defaults(); + //! returns the header filename + std::string get_name() const override; + //! Set private members default values; + void set_defaults(); - - shared_ptr get_empty_record_sptr() const override; + shared_ptr get_empty_record_sptr() const override; - - Succeeded get_next_record(CListRecord& record) const override; + Succeeded get_next_record(CListRecord& record) const override; - - Succeeded reset() override; + Succeeded reset() override; - - SavedPosition save_get_position() override; + SavedPosition save_get_position() override; - - Succeeded set_get_position(const SavedPosition&) override; + Succeeded set_get_position(const SavedPosition&) override; - - bool has_delayeds() const override { return true; } + bool has_delayeds() const override { return true; } - inline - unsigned long int - get_total_number_of_events() const override ; + inline unsigned long int get_total_number_of_events() const override; 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 etc. -//! 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; - //! \name Geometry - //@{ - //! 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; - //@} - - //! \name TOF information - /*! These describe the maximum capabilities of the scanner, i.e. in - list-mode data, even if vendors often never construct sinogram with - this TOF resolution. - */ - //@{ - int max_num_timing_bins; - - float size_timing_bin; - - float timing_resolution; - - int tof_mash_factor; - //@} - - //! \name energy information - //@{ - float energy_resolution; - - float reference_energy; - //@} - //@} - - 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 etc. + //! 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; + //! \name Geometry + //@{ + //! 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; + //@} + + //! \name TOF information + /*! These describe the maximum capabilities of the scanner, i.e. in + list-mode data, even if vendors often never construct sinogram with + this TOF resolution. + */ + //@{ + int max_num_timing_bins; + + float size_timing_bin; + + float timing_resolution; + + int tof_mash_factor; + //@} + + //! \name energy information + //@{ + float energy_resolution; + + float reference_energy; + //@} + //@} + + 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 84e1c4199..66ca4344e 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,50 +50,54 @@ 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); - CListModeDataSAFIR(const std::string& listmode_filename, const shared_ptr& proj_data_info_sptr); - - std::string get_name() const override; - shared_ptr get_empty_record_sptr() const override; - Succeeded get_next_record(CListRecord& record_of_general_type) const override; - Succeeded reset() override; - - /*! - 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? - */ - SavedPosition save_get_position() override - { return static_cast(current_lm_data_ptr->save_get_position()); } - Succeeded set_get_position(const SavedPosition& pos) override - { 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. - */ - bool has_delayeds() const override { 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); + CListModeDataSAFIR(const std::string& listmode_filename, const shared_ptr& proj_data_info_sptr); + + std::string get_name() const override; + shared_ptr get_empty_record_sptr() const override; + Succeeded get_next_record(CListRecord& record_of_general_type) const override; + Succeeded reset() override; + + /*! + 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? + */ + SavedPosition save_get_position() override { return static_cast(current_lm_data_ptr->save_get_position()); } + Succeeded set_get_position(const SavedPosition& pos) override { 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. + */ + bool has_delayeds() const override { 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 c728bde6d..d61cba4ea 100644 --- a/src/include/stir/listmode/CListRecord.h +++ b/src/include/stir/listmode/CListRecord.h @@ -5,7 +5,7 @@ \ingroup listmode \brief Declarations of classes stir::CListRecord, and stir::CListEvent which are used for list mode data. - + \author Nikos Efthimiou \author Daniel Deidda @@ -33,8 +33,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 @@ -45,17 +47,14 @@ 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 { 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); }; /*-coincidence event*/ @@ -67,11 +66,11 @@ class CListEvent : public ListEvent class CListRecord : public ListRecord { public: - }; 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 000ee7614..1dcd68da5 100644 --- a/src/include/stir/listmode/CListRecordECAT8_32bit.h +++ b/src/include/stir/listmode/CListRecordECAT8_32bit.h @@ -11,7 +11,7 @@ \file \ingroup listmode \brief Classes for listmode events for the ECAT 8 format - + \author Kris Thielemans */ @@ -30,7 +30,8 @@ #include "stir/DetectionPositionPair.h" START_NAMESPACE_STIR -namespace ecat { +namespace ecat +{ //! Class for decoding storing and using a raw coincidence event from a listmode file from the ECAT 966 scanner /*! \ingroup listmode @@ -45,62 +46,67 @@ namespace ecat { */ class CListEventDataECAT8_32bit { - public: - - /* 'delayed' bit: - 0 if event is delayed (it fell in delayed time window) */ +public: + /* 'delayed' bit: + 0 if event is delayed (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: +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 void get_detection_position(DetectionPositionPair<>&) const override; //! This routine sets in a coincidence event from detector "indices" void set_detection_position(const DetectionPositionPair<>&) override; - 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 override { return this->data.delayed == 1; } - inline Succeeded set_prompt(const bool prompt = true) override - { if (prompt) this->data.delayed=1; else this->data.delayed=0; return Succeeded::yes; } + inline Succeeded set_prompt(const bool prompt = true) override + { + if (prompt) + this->data.delayed = 1; + else + this->data.delayed = 0; + return Succeeded::yes; + } - private: - BOOST_STATIC_ASSERT(sizeof(CListEventDataECAT8_32bit)==4); - union +private: + BOOST_STATIC_ASSERT(sizeof(CListEventDataECAT8_32bit) == 4); + union { - CListEventDataECAT8_32bit data; - boost::int32_t raw; + CListEventDataECAT8_32bit data; + boost::int32_t raw; }; std::vector segment_sequence; std::vector timing_poss_sequence; @@ -112,77 +118,68 @@ class CListEventECAT8_32bit : public CListEventCylindricalScannerWithDiscreteDet */ class CListTimeDataECAT8_32bit { - public: - +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 { 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 + Succeeded init_from_data_ptr(const void* const ptr) { - CListTimeDataECAT8_32bit data; - boost::int32_t raw; + 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 override - { return static_cast(this->data.time); } +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 override { return static_cast(this->data.time); } inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) override - { - this->data.time = ((1U<<30)-1) & static_cast(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 +private: + BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT8_32bit) == 4); + union { - CListTimeDataECAT8_32bit data; - boost::int32_t raw; + CListTimeDataECAT8_32bit data; + boost::int32_t raw; }; }; @@ -195,74 +192,68 @@ 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 override - { return this->any_data.is_time(); } + bool is_time() const override { return this->any_data.is_time(); } /* bool is_gating_input() const { return this->is_time(); } */ - bool is_event() const override - { return this->any_data.is_event(); } - CListEventECAT8_32bit& event() override - { return this->event_data; } - const CListEventECAT8_32bit& event() const override - { return this->event_data; } - CListTimeECAT8_32bit& time() override - { return this->time_data; } - const CListTimeECAT8_32bit& time() const override - { return this->time_data; } + bool is_event() const override { return this->any_data.is_event(); } + CListEventECAT8_32bit& event() override { return this->event_data; } + const CListEventECAT8_32bit& event() const override { return this->event_data; } + CListTimeECAT8_32bit& time() override { return this->time_data; } + const CListTimeECAT8_32bit& time() const override { return this->time_data; } bool operator==(const CListRecord& e2) const { - return dynamic_cast(&e2) != 0 && - raw == dynamic_cast(e2).raw; - } + 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) - {} +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, + 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 cfc4af83d..408ea02ad 100644 --- a/src/include/stir/listmode/CListRecordECAT962.h +++ b/src/include/stir/listmode/CListRecordECAT962.h @@ -12,9 +12,9 @@ \file \ingroup listmode \brief Classes for listmode events for the ECAT 962 (aka Exact HR+) - + \author Kris Thielemans - + */ #ifndef __stir_listmode_CListRecordECAT962_H__ @@ -38,7 +38,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 @@ -54,62 +53,68 @@ START_NAMESPACE_ECAT7 \todo use DetectionPosition etc. */ -class CListEventDataECAT962 +class CListEventDataECAT962 { - public: +public: inline bool is_prompt() const { return delayed == 0; } - inline Succeeded set_prompt(const bool prompt = true) - { if (prompt) delayed=0; else delayed=1; return Succeeded::yes; } + inline Succeeded set_prompt(const bool prompt = true) + { + if (prompt) + delayed = 0; + else + delayed = 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... - */ - /* 'delayed' bit: - 1 if event is Delayed (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... + */ + /* 'delayed' bit: + 1 if event is Delayed (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 delayed : 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 delayed : 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 delayed : 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 delayed : 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*/ @@ -148,120 +153,112 @@ class CListEventECAT962 : public CListEventCylindricalScannerWithViewTangRingRin */ class CListTimeDataECAT962 { - public: - inline unsigned long get_time_in_millisecs() const - { return static_cast(time); } +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); + { + 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 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 + { + 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 +class CListRecordECAT962 : public CListRecordWithGatingInput, + public ListTime, + public ListGatingInput, + public CListEventCylindricalScannerWithViewTangRingRingEncoding { - public: +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; } +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; - } + 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(); } + // 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); } + { + 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; + union + { + 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 692b60fe6..dbcd54964 100644 --- a/src/include/stir/listmode/CListRecordECAT966.h +++ b/src/include/stir/listmode/CListRecordECAT966.h @@ -12,9 +12,9 @@ \file \ingroup listmode \brief Classes for listmode events for the ECAT 966 (aka Exact 3d) - + \author Kris Thielemans - + */ #ifndef __stir_listmode_CListRecordECAT966_H__ @@ -53,16 +53,13 @@ START_NAMESPACE_ECAT7 */ class CListEventDataECAT966 { - public: - +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 @@ -71,33 +68,33 @@ class CListEventDataECAT966 This organisation corresponds to physical detector blocks (which have 8 crystal rings). Names are not very good probably... - */ - /* 'delayed' bit: - 1 if event is Delayed (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 ; - */ + */ + /* 'delayed' bit: + 1 if event is Delayed (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 delayed : 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 delayed : 1; + unsigned bin : 9; + unsigned view : 9; #else // Do byteswapping first before using this bit field. - unsigned view : 9; - unsigned bin : 9; - unsigned delayed : 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 delayed : 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*/ @@ -105,32 +102,39 @@ class CListEventDataECAT966 //! Class for storing and using a coincidence event from a listmode file from the ECAT 966 scanner class CListEventECAT966 : public CListEventCylindricalScannerWithViewTangRingRingEncoding { - private: - public: +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.delayed == 0; } - inline Succeeded set_prompt(const bool prompt = true) - { if (prompt) this->data.delayed=0; else this->data.delayed=1; return Succeeded::yes; } + inline Succeeded set_prompt(const bool prompt = true) + { + if (prompt) + this->data.delayed = 0; + else + this->data.delayed = 1; + return Succeeded::yes; + } - private: - BOOST_STATIC_ASSERT(sizeof(CListEventDataECAT966)==4); - union +private: + BOOST_STATIC_ASSERT(sizeof(CListEventDataECAT966) == 4); + union { - CListEventDataECAT966 data; - boost::int32_t raw; + CListEventDataECAT966 data; + boost::int32_t raw; }; }; @@ -141,54 +145,52 @@ class CListEventECAT966 : public CListEventCylindricalScannerWithViewTangRingRin */ class CListTimeDataECAT966 { - public: - +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); } +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); + { + 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 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;} + { + this->data.gating = g & 0xf; + return this->data.gating == g ? Succeeded::yes : Succeeded::no; + } - private: - BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT966)==4); - union +private: + BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT966) == 4); + union { - CListTimeDataECAT966 data; - boost::int32_t raw; + CListTimeDataECAT966 data; + boost::int32_t raw; }; }; @@ -198,43 +200,34 @@ class CListTimeECAT966 : public ListTime, public ListGatingInput 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; } + // 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; - } + return dynamic_cast(&e2) != 0 && raw == dynamic_cast(e2).raw; + } - public: - virtual Succeeded init_from_data_ptr(const char * const data_ptr, +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); @@ -245,18 +238,18 @@ 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 7fe105b54..c0f702a30 100644 --- a/src/include/stir/listmode/CListRecordGEHDF5.h +++ b/src/include/stir/listmode/CListRecordGEHDF5.h @@ -30,155 +30,159 @@ 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 - }; +namespace GE +{ +namespace RDF_HDF5 +{ - /*********************************** - * 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 +}; - //! Class for finding out what the event/size-type is in a GE RDF9 listmode file - /*! \ingroup listmode - \ingroup GE - */ - class CListAnyRecordDataGEHDF5 - { - public: +/*********************************** + * 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: #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 - - inline int get_tof_bin() const - { - return static_cast(-deltaTime); - } +}; /*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 + + 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 +{ +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 - //! 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 +private: + typedef union + { + struct { - 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 @@ -186,29 +190,27 @@ 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& 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 override - { - 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 override { return this->time_data.is_time(); } #if 0 bool is_gating_input() const { @@ -217,15 +219,25 @@ class CListRecordGEHDF5 : public CListRecord, public ListTime, // public CListGa #endif bool is_event() const override - { return this->event_data.is_event(); } - CListEvent& event() override - { return *this; } - const CListEvent& event() const override - { return *this; } - ListTime& time() override - { return *this; } - const ListTime& time() const override - { return *this; } + { + return this->event_data.is_event(); + } + CListEvent& event() override + { + return *this; + } + const CListEvent& event() const override + { + return *this; + } + ListTime& time() override + { + return *this; + } + const ListTime& time() const override + { + return *this; + } #if 0 virtual CListGatingInput& gating_input() { return *this; } @@ -243,12 +255,16 @@ dynamic_cast(&e2) != 0 && #endif } - // time - inline unsigned long get_time_in_millisecs() const override - { return time_data.get_time_in_millisecs() - first_time_stamp; } + // time + inline unsigned long get_time_in_millisecs() const override + { + return time_data.get_time_in_millisecs() - first_time_stamp; + } inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) override - { return time_data.set_time_in_millisecs(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(); } @@ -256,17 +272,26 @@ dynamic_cast(&e2) != 0 && { return gating_data.set_gating(g); } #endif // event - inline bool is_prompt() const override { return event_data.is_prompt(); } + inline bool is_prompt() const override + { + return event_data.is_prompt(); + } inline Succeeded set_prompt(const bool prompt = true) override - { return event_data.set_prompt(prompt); } + { + return event_data.set_prompt(prompt); + } void get_detection_position(DetectionPositionPair<>& det_pos) const override { - det_pos.pos1().tangential_coord() = this->get_uncompressed_proj_data_info_sptr()->get_scanner_sptr()->get_num_detectors_per_ring() - 1 - event_data.loXtalTransAxID; + det_pos.pos1().tangential_coord() + = this->get_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() = this->get_uncompressed_proj_data_info_sptr()->get_scanner_sptr()->get_num_detectors_per_ring() - 1 - event_data.hiXtalTransAxID; + det_pos.pos2().tangential_coord() + = this->get_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; - det_pos.timing_pos() = event_data.get_tof_bin(); + det_pos.timing_pos() = event_data.get_tof_bin(); } //! This routine sets in a coincidence event from detector "indices" @@ -275,9 +300,8 @@ dynamic_cast(&e2) != 0 && 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); @@ -287,30 +311,31 @@ dynamic_cast(&e2) != 0 && detail::CListAnyRecordDataGEHDF5 rec; boost::uint16_t raw[4]; }; - std::copy(data_ptr, data_ptr+2, &raw[0]); - switch(rec.eventLength) + std::copy(data_ptr, data_ptr + 2, &raw[0]); + 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); + 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])); + 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]); + // ByteOrder::swap_order(this->raw[0]); } return Succeeded::yes; @@ -318,22 +343,21 @@ dynamic_cast(&e2) != 0 && private: unsigned long first_time_stamp; - union { - DataType event_data; - TimeType time_data; - //GatingType gating_data; - boost::int32_t raw[16/4]; + union + { + 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/CListRecordPENN.h b/src/include/stir/listmode/CListRecordPENN.h index ef4b838f0..ccd3839a2 100644 --- a/src/include/stir/listmode/CListRecordPENN.h +++ b/src/include/stir/listmode/CListRecordPENN.h @@ -30,44 +30,41 @@ START_NAMESPACE_STIR class CListEventPENN : public CListEventCylindricalScannerWithDiscreteDetectors { public: - CListEventPENN(const shared_ptr& scanner_sptr); - //! 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<>&); - - void init_from_data(bool d, int dt, int xa, int xb, int za, int zb, int ea, int eb); - - inline bool is_prompt() const - { return delay == false; } - - inline Succeeded set_prompt(const bool _prompt = true) - { - if (_prompt) - delay=false; - else - delay=true; - return Succeeded::yes; - } + CListEventPENN(const shared_ptr& scanner_sptr); + //! 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<>&); -private: + void init_from_data(bool d, int dt, int xa, int xb, int za, int zb, int ea, int eb); + + inline bool is_prompt() const { return delay == false; } + + inline Succeeded set_prompt(const bool _prompt = true) + { + if (_prompt) + delay = false; + else + delay = true; + return Succeeded::yes; + } - std::vector segment_sequence; - std::vector sizes; +private: + std::vector segment_sequence; + std::vector sizes; - int delay; + int delay; #ifdef STIR_TOF - short int tof_bin; - short int orig_tof_bin; + short int tof_bin; + short int orig_tof_bin; #endif - int d1, d2; - int z1, z2; + int d1, d2; + int z1, z2; #if 0 // Most likely, most people will not need these. unsigned short int orig_z1, orig_z2; #endif - int quarter_of_detectors; - + int quarter_of_detectors; }; /*! \ingroup listmode @@ -75,21 +72,12 @@ class CListEventPENN : public CListEventCylindricalScannerWithDiscreteDetectors class CListTimePENN : public ListTime { public: - Succeeded init_from_data_ptr(const void * const ptr) - { - return Succeeded::yes; - } - bool is_time() const - { return false; } - inline unsigned long get_time_in_millisecs() const - { return 0; } - inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) - { - return Succeeded::yes; - } + Succeeded init_from_data_ptr(const void* const ptr) { return Succeeded::yes; } + bool is_time() const { return false; } + inline unsigned long get_time_in_millisecs() const { return 0; } + inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) { return Succeeded::yes; } private: - }; /*! \ingroup listmode @@ -98,56 +86,39 @@ class CListRecordPENN : public CListRecord // currently no gating yet { public: - //!Currently, I skip time events. - bool is_time() const - { return false; } - /* - bool is_gating_input() const - { return this->is_time(); } - */ - bool is_event() const - { return true; } - virtual CListEventPENN& event() - { return this->event_data; } - virtual const CListEventPENN& event() const - { return this->event_data; } - virtual CListTimePENN& time() - { return this->time_data; } - virtual const CListTimePENN& time() const - { return this->time_data; } - //! \todo - bool operator==(const CListRecord& e2) const - { - - } + //! Currently, I skip time events. + bool is_time() const { return false; } + /* +bool is_gating_input() const +{ return this->is_time(); } +*/ + bool is_event() const { return true; } + virtual CListEventPENN& event() { return this->event_data; } + virtual const CListEventPENN& event() const { return this->event_data; } + virtual CListTimePENN& time() { return this->time_data; } + virtual const CListTimePENN& time() const { return this->time_data; } + //! \todo + bool operator==(const CListRecord& e2) const {} public: - CListRecordPENN(const shared_ptr& scanner_sptr) : - event_data(scanner_sptr) - {} - - virtual Succeeded init_from_data(int is_delay, - int dt, - int xa, int xb, - int za, int zb, - int ea, int eb) - { - - this->event_data.init_from_data(is_delay, dt, - xa, xb, - za, zb, - ea, eb); - // this->time_data.init_from_data(ta, tb); - - return Succeeded::yes; - } + CListRecordPENN(const shared_ptr& scanner_sptr) + : event_data(scanner_sptr) + {} + + virtual Succeeded init_from_data(int is_delay, int dt, int xa, int xb, int za, int zb, int ea, int eb) + { + + this->event_data.init_from_data(is_delay, dt, xa, xb, za, zb, ea, eb); + // this->time_data.init_from_data(ta, tb); + + return Succeeded::yes; + } private: - CListEventPENN event_data; - CListTimePENN time_data; + CListEventPENN event_data; + CListTimePENN time_data; }; END_NAMESPACE_STIR #endif - diff --git a/src/include/stir/listmode/CListRecordROOT.h b/src/include/stir/listmode/CListRecordROOT.h index 7705de1c7..b0d2ff9dc 100644 --- a/src/include/stir/listmode/CListRecordROOT.h +++ b/src/include/stir/listmode/CListRecordROOT.h @@ -34,40 +34,36 @@ START_NAMESPACE_STIR class CListEventROOT : public CListEventCylindricalScannerWithDiscreteDetectors { public: + CListEventROOT(const shared_ptr& proj_data_info); - CListEventROOT(const shared_ptr& proj_data_info); + //! This routine returns the corresponding detector pair + void get_detection_position(DetectionPositionPair<>&) const override; - //! This routine returns the corresponding detector pair - void get_detection_position(DetectionPositionPair<>&) const override; + //! This routine sets in a coincidence event from detector "indices" + void set_detection_position(const DetectionPositionPair<>&) override; - //! This routine sets in a coincidence event from detector "indices" - void set_detection_position(const DetectionPositionPair<>&) override; + //! \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); - //! \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 override { return true; } - inline bool is_prompt() const override - { return true; } + double get_delta_time() const { return delta_time; } - double get_delta_time() const { return delta_time; } - - 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; - //! The detection time difference, between the two photons. - double delta_time; +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; + //! The detection time difference, between the two photons. + double delta_time; #ifdef STIR_ROOT_ROTATION_AS_V4 - //! This is the number of detector we have to rotate in order to - //! align GATE and STIR. - int quarter_of_detectors; + //! This is the number of detector we have to rotate in order to + //! align GATE and STIR. + int quarter_of_detectors; #endif }; @@ -77,104 +73,82 @@ class CListEventROOT : public CListEventCylindricalScannerWithDiscreteDetectors class CListTimeROOT : public ListTime { public: - 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 override - { return static_cast (timeA * 1e3); } - inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) override - { - 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 override { return static_cast(timeA * 1e3); } + inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) override + { + 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 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 override; - //! Returns always true - bool inline is_event() const override; - - CListEventROOT& event() override - { - return this->event_data; - } - - const CListEventROOT& event() const override - { - return this->event_data; - } - - CListTimeROOT& time() override - { - return this->time_data; - } - - const CListTimeROOT& time() const override - { - 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; - } + //! Returns always true + bool inline is_time() const override; + //! Returns always true + bool inline is_event() const override; -private: - CListEventROOT event_data; - CListTimeROOT time_data; - boost::int32_t raw[2]; // this raw field isn't strictly necessary, get rid of it? + CListEventROOT& event() override { return this->event_data; } + + const CListEventROOT& event() const override { return this->event_data; } + + CListTimeROOT& time() override { return this->time_data; } + + const CListTimeROOT& time() const override { 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 141131337..b78f1576d 100644 --- a/src/include/stir/listmode/CListRecordROOT.inl +++ b/src/include/stir/listmode/CListRecordROOT.inl @@ -19,10 +19,16 @@ START_NAMESPACE_STIR -bool CListRecordROOT::is_time() const -{ return true; } - -bool CListRecordROOT::is_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 cc1afac14..05da4f209 100644 --- a/src/include/stir/listmode/CListRecordSAFIR.h +++ b/src/include/stir/listmode/CListRecordSAFIR.h @@ -2,21 +2,21 @@ Coincidence Event Class for SAFIR: Header File - Copyright 2015 ETH Zurich, Institute of Particle Physics - Copyright 2017 ETH Zurich, Institute of Particle Physics and Astrophysics - Copyright 2020, 2022 Positrigo AG, Zurich + Copyright 2015 ETH Zurich, Institute of Particle Physics + Copyright 2017 ETH Zurich, Institute of Particle Physics and Astrophysics + Copyright 2020, 2022 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. */ @@ -34,7 +34,7 @@ #ifndef __stir_listmode_CListRecordSAFIR_H__ #define __stir_listmode_CListRecordSAFIR_H__ -#include +#include #include "stir/listmode/CListRecord.h" #include "stir/DetectionPositionPair.h" @@ -51,19 +51,20 @@ START_NAMESPACE_STIR /*! -Provides interface of the record class to STIR by implementing get_LOR(). It uses an optional 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 an optional 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 isDelayed : 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 isDelayed : 1; + unsigned type : 1; \endcode \ingroup listmode */ @@ -71,162 +72,152 @@ template class CListEventSAFIR : public CListEvent { public: - /*! Default constructor will not work as it does not initialize a map to relate - detector indices and space coordinates. Always use either set_scanner_sptr or set_map_sptr after default construction. - */ - inline CListEventSAFIR( ) {} - - //! Returns LOR corresponding to the given event. - inline LORAs2Points get_LOR() const override; - + /*! Default constructor will not work as it does not initialize a map to relate + detector indices and space coordinates. Always use either set_scanner_sptr or set_map_sptr after default construction. + */ + inline CListEventSAFIR() {} + + //! Returns LOR corresponding to the given event. + inline LORAs2Points get_LOR() const override; + //! Override the default implementation inline void get_bin(Bin& bin, const ProjDataInfo& proj_data_info) const override; - + //! 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 bool is_valid_template(const ProjDataInfo&) const override {return true;} - - //! Returns 0 if event is prompt and 1 if delayed - inline bool is_prompt() - const override { return !(static_cast(this)->is_prompt()); } - //! Function to set map for detector indices to coordinates. - /*! Use a null pointer to disable the mapping functionality */ - inline void set_map_sptr( shared_ptr new_map_sptr ) { map_sptr = new_map_sptr; } - /*! Set the scanner */ - /*! Currently only used if the map is not set. */ - inline void set_scanner_sptr( shared_ptr new_scanner_sptr ) { scanner_sptr = new_scanner_sptr; } + inline bool is_valid_template(const ProjDataInfo&) const override { return true; } + + //! Returns 0 if event is prompt and 1 if delayed + inline bool is_prompt() const override { return !(static_cast(this)->is_prompt()); } + //! Function to set map for detector indices to coordinates. + /*! Use a null pointer to disable the mapping functionality */ + inline void set_map_sptr(shared_ptr new_map_sptr) { map_sptr = new_map_sptr; } + /*! Set the scanner */ + /*! Currently only used if the map is not set. */ + inline void set_scanner_sptr(shared_ptr new_scanner_sptr) { scanner_sptr = new_scanner_sptr; } private: - shared_ptr map_sptr; - shared_ptr scanner_sptr; + shared_ptr map_sptr; + shared_ptr scanner_sptr; - const DetectorCoordinateMap& map_to_use() const - { return map_sptr ? *map_sptr : *this->scanner_sptr->get_detector_map_sptr(); } + const DetectorCoordinateMap& map_to_use() const { return map_sptr ? *map_sptr : *this->scanner_sptr->get_detector_map_sptr(); } }; - - //! Class for record with coincidence data using SAFIR bitfield definition /*! \ingroup listmode */ class CListEventDataSAFIR { public: - //! Writes detection position pair to reference given as argument. - inline void get_detection_position_pair(DetectionPositionPair<>& det_pos_pair); + //! 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 delayed - inline bool is_prompt() - const { return !isDelayed; } + //! Returns 0 if event is prompt and 1 if delayed + inline bool is_prompt() const { return !isDelayed; } - //! Returns 1 if if event is time and 0 if it is prompt - inline bool is_time() const { return type; } - - //! Can be used to set "promptness" of event. - inline Succeeded set_prompt( const bool prompt = true ) { - isDelayed = !prompt; - return Succeeded::yes; - } + //! Returns 1 if if event is time and 0 if it is prompt + inline bool is_time() const { return type; } + //! Can be used to set "promptness" of event. + inline Succeeded set_prompt(const bool prompt = true) + { + isDelayed = !prompt; + return Succeeded::yes; + } private: - #if STIRIsNativeByteOrderBigEndian - unsigned type : 1; - unsigned isDelayed : 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 isDelayed : 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 isDelayed : 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 isDelayed : 1; + unsigned type : 1; #endif }; - //! Class for record with coincidence data using NeuroLF bitfield definition /*! \ingroup listmode */ class CListEventDataNeuroLF { 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 delayed - inline bool is_prompt() - const { return !isDelayed; } + //! Writes detection position pair to reference given as argument. + inline void get_detection_position_pair(DetectionPositionPair<>& det_pos_pair); - //! Returns 1 if if event is time and 0 if it is prompt - inline bool is_time() const { return type; } + //! Returns 0 if event is prompt and 1 if delayed + inline bool is_prompt() const { return !isDelayed; } - //! Can be used to set "promptness" of event. - inline Succeeded set_prompt( const bool prompt = true ) { - isDelayed = !prompt; - return Succeeded::yes; - } + //! Returns 1 if if event is time and 0 if it is prompt + inline bool is_time() const { return type; } + //! Can be used to set "promptness" of event. + inline Succeeded set_prompt(const bool prompt = true) + { + isDelayed = !prompt; + return Succeeded::yes; + } private: - #if STIRIsNativeByteOrderBigEndian - unsigned type : 1; - unsigned isDelayed : 1; - unsigned reserved : 8; - unsigned layerB : 3; - unsigned layerA : 3; - unsigned detB : 16; - unsigned detA : 16; - unsigned ringB : 8; - unsigned ringA : 8; + unsigned type : 1; + unsigned isDelayed : 1; + unsigned reserved : 8; + unsigned layerB : 3; + unsigned layerA : 3; + 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 : 3; - unsigned layerB : 3; - unsigned reserved : 8; - unsigned isDelayed : 1; - unsigned type : 1; + unsigned ringA : 8; + unsigned ringB : 8; + unsigned detA : 16; + unsigned detB : 16; + unsigned layerA : 3; + unsigned layerB : 3; + unsigned reserved : 8; + unsigned isDelayed : 1; + unsigned type : 1; #endif }; - //! Class for record with time data using SAFIR bitfield definition /*! \ingroup listmode */ 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 bool is_time() const { return type; } + 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 bool is_time() const { return type; } + private: #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 }; @@ -236,86 +227,76 @@ template class CListRecordSAFIR : public CListRecord, public ListTime, public CListEventSAFIR> { public: + //! Returns event_data (without checking if the type is really event and not time). + DataType get_data() const { return this->event_data; } - //! Returns event_data (without checking if the type is really event and not time). - DataType get_data() const - { return this->event_data; } - - CListRecordSAFIR() : CListEventSAFIR>() {} + CListRecordSAFIR() + : CListEventSAFIR>() + {} - ~CListRecordSAFIR() override {} + ~CListRecordSAFIR() override {} - bool is_time() const override - { return time_data.is_time(); } + bool is_time() const override { return time_data.is_time(); } - bool is_event() const override - { return !time_data.is_time(); } + bool is_event() const override { return !time_data.is_time(); } - CListEvent& event() override - { return *this; } + CListEvent& event() override { return *this; } - const CListEvent& event() const override - { return *this; } + const CListEvent& event() const override { return *this; } - virtual CListEventSAFIR>& event_SAFIR() - { return *this; } + virtual CListEventSAFIR>& event_SAFIR() { return *this; } - virtual const CListEventSAFIR>& event_SAFIR() const - { return *this; } + virtual const CListEventSAFIR>& event_SAFIR() const { return *this; } - ListTime& time() override - { return *this; } + ListTime& time() override { return *this; } - const ListTime& time() const override - { return *this; } + const ListTime& time() const override { return *this; } - virtual bool operator==(const CListRecord& e2) const - { - return dynamic_cast const *>(&e2) != 0 && - raw == static_cast const &>(e2).raw; - } + virtual bool operator==(const CListRecord& e2) const + { + return dynamic_cast const*>(&e2) != 0 + && raw == static_cast const&>(e2).raw; + } - inline unsigned long get_time_in_millisecs() const override - { return time_data.get_time_in_millisecs(); } + inline unsigned long get_time_in_millisecs() const override { return time_data.get_time_in_millisecs(); } - inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) override - { return time_data.set_time_in_millisecs(time_in_millisecs); } + inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) override + { + return time_data.set_time_in_millisecs(time_in_millisecs); + } - inline bool is_prompt() const override { return event_data.is_prompt(); } + inline bool is_prompt() const override { return event_data.is_prompt(); } - 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; - } + 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 { - DataType event_data; - CListTimeDataSAFIR time_data; - boost::int64_t raw; - }; - BOOST_STATIC_ASSERT(sizeof(boost::uint64_t)==8); - BOOST_STATIC_ASSERT(sizeof(DataType)==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 + { + DataType event_data; + CListTimeDataSAFIR time_data; + boost::int64_t raw; + }; + BOOST_STATIC_ASSERT(sizeof(boost::uint64_t) == 8); + BOOST_STATIC_ASSERT(sizeof(DataType) == 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 c8974f51b..6f2f5bfcd 100644 --- a/src/include/stir/listmode/CListRecordSAFIR.inl +++ b/src/include/stir/listmode/CListRecordSAFIR.inl @@ -2,22 +2,22 @@ Coincidence Event Class for SAFIR: Inline File - Copyright 2015 ETH Zurich, Institute of Particle Physics - Copyright 2017 ETH Zurich, Institute of Particle Physics and Astrophysics - Copyright 2020, 2022 Positrigo AG, Zurich + Copyright 2015 ETH Zurich, Institute of Particle Physics + Copyright 2017 ETH Zurich, Institute of Particle Physics and Astrophysics + Copyright 2020, 2022 Positrigo AG, Zurich Copyright 2021 University College London - 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. */ /*! @@ -32,7 +32,7 @@ \author Kris Thielemans */ -#include +#include #include "stir/LORCoordinates.h" #include "stir/listmode/CListRecord.h" @@ -53,15 +53,15 @@ template LORAs2Points CListEventSAFIR::get_LOR() const { - LORAs2Points lor; - DetectionPositionPair<> det_pos_pair; + 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); - lor.p1() = map_to_use().get_coordinate_for_index(det_pos_pair.pos1()); - lor.p2() = map_to_use().get_coordinate_for_index(det_pos_pair.pos2()); + lor.p1() = map_to_use().get_coordinate_for_index(det_pos_pair.pos1()); + lor.p2() = map_to_use().get_coordinate_for_index(det_pos_pair.pos2()); - return lor; + return lor; } namespace detail @@ -95,11 +95,12 @@ CListEventSAFIR::get_bin(Bin& bin, const ProjDataInfo& proj_data_info) // transform det_pos_pair into stir conventions det_pos_pair.pos1() = map_to_use().get_det_pos_for_index(det_pos_pair.pos1()); det_pos_pair.pos2() = map_to_use().get_det_pos_for_index(det_pos_pair.pos2()); - - if (det_pos_pair.pos1().tangential_coord() == det_pos_pair.pos2().tangential_coord()) { - bin.set_bin_value(-1); - return; - } + + if (det_pos_pair.pos1().tangential_coord() == det_pos_pair.pos2().tangential_coord()) + { + bin.set_bin_value(-1); + return; + } if (!detail::get_bin_for_det_pos_pair(bin, det_pos_pair, proj_data_info)) { @@ -116,28 +117,30 @@ CListEventSAFIR::get_bin(Bin& bin, const ProjDataInfo& proj_data_info) } } -void CListEventDataSAFIR::get_detection_position_pair(DetectionPositionPair<>& det_pos_pair) +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().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; } -void CListEventDataNeuroLF::get_detection_position_pair(DetectionPositionPair<>& det_pos_pair) +void +CListEventDataNeuroLF::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().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/ListEvent.h b/src/include/stir/listmode/ListEvent.h index 86d4fbb13..5c53a97ef 100644 --- a/src/include/stir/listmode/ListEvent.h +++ b/src/include/stir/listmode/ListEvent.h @@ -46,7 +46,7 @@ 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 @@ -63,8 +63,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 @@ -83,18 +82,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/ListModeData.h b/src/include/stir/listmode/ListModeData.h index 5df50e3be..ab0293bac 100644 --- a/src/include/stir/listmode/ListModeData.h +++ b/src/include/stir/listmode/ListModeData.h @@ -28,8 +28,11 @@ #include "stir/RegisteredParsingObject.h" #include "stir/listmode/ListRecord.h" #include "stir/error.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 @@ -129,8 +132,7 @@ class ListModeData : public ExamData //! Default constructor ListModeData(); - - ~ListModeData() override; + ~ListModeData() override; //! Returns the name of the list mode data /*! This name is not necessarily unique, and might be empty. However, it is expected @@ -141,17 +143,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 @@ -171,17 +172,19 @@ 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 /*! @@ -201,13 +204,11 @@ 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 reference to scanner /*! Returns a reference to a scanner object that is appropriate for the @@ -222,16 +223,16 @@ class ListModeData : public ExamData //! 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; + 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/ListModeData_dummy.h b/src/include/stir/listmode/ListModeData_dummy.h index b4c091c1b..6d9611fc1 100644 --- a/src/include/stir/listmode/ListModeData_dummy.h +++ b/src/include/stir/listmode/ListModeData_dummy.h @@ -44,57 +44,51 @@ listmode file with a third party. class ListModeData_dummy : public ListModeData { public: - ListModeData_dummy(shared_ptr exam_info, - shared_ptr proj_data_info) - { - this->exam_info_sptr = exam_info; - this->proj_data_info_sptr = proj_data_info; - } - - std::string get_name() const override - { - return std::string("ListModeData_dummy"); - } - - Succeeded reset() override - { - error("ListModeData_dummy does not have reset()"); - return Succeeded::no; - } - - SavedPosition save_get_position() override - { - error("ListModeData_dummy does not have save_get_position()"); - return 0; - } - - Succeeded set_get_position(const SavedPosition&) override - { - error("ListModeData_dummy does not have set_get_position()"); - return Succeeded::no; - } - - bool has_delayeds() const override - { - error("ListModeData_dummy does not have has_delayeds()"); - return false; - } + ListModeData_dummy(shared_ptr exam_info, shared_ptr proj_data_info) + { + this->exam_info_sptr = exam_info; + this->proj_data_info_sptr = proj_data_info; + } + + std::string get_name() const override { return std::string("ListModeData_dummy"); } + + Succeeded reset() override + { + error("ListModeData_dummy does not have reset()"); + return Succeeded::no; + } + + SavedPosition save_get_position() override + { + error("ListModeData_dummy does not have save_get_position()"); + return 0; + } + + Succeeded set_get_position(const SavedPosition&) override + { + error("ListModeData_dummy does not have set_get_position()"); + return Succeeded::no; + } + + bool has_delayeds() const override + { + error("ListModeData_dummy does not have has_delayeds()"); + return false; + } protected: - shared_ptr get_empty_record_helper_sptr() const override - { - error("ListModeData_dummy does not have get_empty_record_helper_sptr()"); - return nullptr; - } - Succeeded get_next(ListRecord& event) const override - { - error("ListModeData_dummy does not have get_next()"); - return Succeeded::no; - } - + shared_ptr get_empty_record_helper_sptr() const override + { + error("ListModeData_dummy does not have get_empty_record_helper_sptr()"); + return nullptr; + } + Succeeded get_next(ListRecord& event) const override + { + error("ListModeData_dummy does not have get_next()"); + return Succeeded::no; + } }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir/listmode/ListRecord.h b/src/include/stir/listmode/ListRecord.h index 29ee28109..f275012de 100644 --- a/src/include/stir/listmode/ListRecord.h +++ b/src/include/stir/listmode/ListRecord.h @@ -44,17 +44,16 @@ START_NAMESPACE_STIR 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 00095b152..3731005f3 100644 --- a/src/include/stir/listmode/ListRecordWithGatingInput.h +++ b/src/include/stir/listmode/ListRecordWithGatingInput.h @@ -32,10 +32,10 @@ START_NAMESPACE_STIR class ListRecordWithGatingInput : public virtual ListRecord { - public: +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 151f829c2..7a3cdf7c3 100644 --- a/src/include/stir/listmode/ListTime.h +++ b/src/include/stir/listmode/ListTime.h @@ -29,7 +29,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 @@ -49,17 +49,15 @@ class ListTime 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); - } - + { + 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 8d727244f..db858d7f3 100644 --- a/src/include/stir/listmode/LmToProjData.h +++ b/src/include/stir/listmode/LmToProjData.h @@ -3,16 +3,16 @@ // // /*! - \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 @@ -26,7 +26,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/listmode/LmToProjDataAbstract.h" #include "stir/ProjDataInfo.h" #include "stir/listmode/ListModeData.h" @@ -47,7 +46,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: @@ -61,9 +60,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 @@ -88,7 +87,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 @@ -108,9 +107,9 @@ class ListTime; num_segments_in_memory := -1 ; same for TOF bins num_TOF_bins_in_memory := 1 - End := + 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: @@ -119,22 +118,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, @@ -153,7 +152,7 @@ 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. @@ -163,10 +162,9 @@ class ListTime; 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. */ @@ -230,7 +228,6 @@ class LmToProjData : public LmToProjDataAbstract #endif 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); @@ -240,8 +237,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; @@ -251,10 +248,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; @@ -312,8 +309,7 @@ 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; diff --git a/src/include/stir/listmode/LmToProjDataAbstract.h b/src/include/stir/listmode/LmToProjDataAbstract.h index 47b585598..f9afa4346 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 @@ -32,21 +32,20 @@ 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 { public: + /// Destructor + ~LmToProjDataAbstract() override {} - /// Destructor - ~LmToProjDataAbstract() override {} - - /// 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 da027a4a0..6ad783179 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 @@ -24,20 +24,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 @@ -65,19 +64,19 @@ START_NAMESPACE_STIR bootstrapping mechanism does not depend on how LmToProjData actually works. */ -template< typename 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); Succeeded set_up() override; + protected: //! will be called when a new time frame starts /*! Initialises a vector with the number of times each event has to be replicated */ @@ -85,7 +84,6 @@ class LmToProjDataBootstrap : public LmToProjDataT void get_bin_from_event(Bin& bin, const ListEvent&) const override; - // \name parsing variables //@{ //! used to seed the pseudo-random number generator @@ -97,17 +95,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; void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - - }; END_NAMESPACE_STIR - #endif diff --git a/src/include/stir/listmode/LmToProjDataWithRandomRejection.h b/src/include/stir/listmode/LmToProjDataWithRandomRejection.h index 931c2d2ac..95b70775b 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 @@ -24,7 +24,6 @@ #ifndef __stir_listmode_LmToProjDataWithRandomRejection_H__ #define __stir_listmode_LmToProjDataWithRandomRejection_H__ - #include "stir/listmode/LmToProjData.h" #include #include @@ -32,13 +31,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 @@ -66,22 +65,22 @@ START_NAMESPACE_STIR bootstrapping mechanism does not depend on how LmToProjData actually works. */ -template< typename 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); Succeeded set_up() override; + protected: //! will be called when a new time frame starts /*! Initialises a vector with the number of times each event has to be replicated */ @@ -89,7 +88,6 @@ class LmToProjDataWithRandomRejection : public LmToProjDataT void get_bin_from_event(Bin& bin, const ListEvent&) const override; - // \name parsing variables //@{ //! used to seed the pseudo-random number generator @@ -101,17 +99,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; void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - - }; 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 7fe9e32a3..00d1c312a 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 @@ -46,79 +46,67 @@ class ProjData; 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 efa471603..ab5adc576 100644 --- a/src/include/stir/listmode/SPECTListEvent.h +++ b/src/include/stir/listmode/SPECTListEvent.h @@ -44,12 +44,10 @@ 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 390294a67..bda86a7cc 100644 --- a/src/include/stir/listmode/SPECTListModeData.h +++ b/src/include/stir/listmode/SPECTListModeData.h @@ -22,8 +22,11 @@ #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 @@ -44,31 +47,27 @@ class ExamInfo; 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;} + 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 d77766c76..90f87f269 100644 --- a/src/include/stir/listmode/SPECTListRecord.h +++ b/src/include/stir/listmode/SPECTListRecord.h @@ -23,7 +23,6 @@ #ifndef __stir_listmode_SPECTListRecord_H__ #define __stir_listmode_SPECTListRecord_H__ - #include "stir/listmode/ListTime.h" #include "ListRecord.h" #include "stir/listmode/SPECTListEvent.h" @@ -45,20 +44,19 @@ START_NAMESPACE_STIR 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 2100d2f94..46cad4e12 100644 --- a/src/include/stir/listmode/SPECTListRecordWithGatingInput.h +++ b/src/include/stir/listmode/SPECTListRecordWithGatingInput.h @@ -31,10 +31,10 @@ START_NAMESPACE_STIR class SPECTListRecordWithGatingInput : public virtual SPECTListRecord { - public: +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 73adc0280..f5359a481 100644 --- a/src/include/stir/make_array.h +++ b/src/include/stir/make_array.h @@ -13,9 +13,9 @@ /*! \file \ingroup Array - + \brief Declaration of functions for constructing arrays stir::make_1d_array etc - + \author Kris Thielemans */ @@ -23,178 +23,160 @@ 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 cb47c2520..dbb456809 100644 --- a/src/include/stir/make_array.inl +++ b/src/include/stir/make_array.inl @@ -11,9 +11,9 @@ /*! \file \ingroup Array - + \brief Implementation of functions for constructing arrays stir::make_1d_array etc - + \author Kris Thielemans */ @@ -25,7 +25,7 @@ VectorWithOffset make_vector(const T& a0) { VectorWithOffset a(1); - a[0]=a0; + a[0] = a0; return a; } @@ -34,7 +34,8 @@ VectorWithOffset 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; } @@ -43,7 +44,9 @@ VectorWithOffset 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; } @@ -52,7 +55,10 @@ VectorWithOffset 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; } @@ -61,270 +67,317 @@ VectorWithOffset 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> +Array<1, T> make_1d_array(const T& a0) { - const Array<1,T> a = NumericVectorWithOffset(make_vector(a0)); + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0)); return a; } template -Array<1,T> +Array<1, T> make_1d_array(const T& a0, const T& a1) { - const Array<1,T> a = NumericVectorWithOffset(make_vector(a0, a1)); + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0, a1)); return a; } - template -Array<1,T> +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)); + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0, a1, a2)); return a; } - template -Array<1,T> +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)); + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0, a1, a2, a3)); return a; } template -Array<1,T> +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)); + 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) +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)); + 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) +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)); + 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) +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)); + 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) +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)); + 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) +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)); + 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) +Array +make_array(const Array& a0) { - const Array<1,T> a = NumericVectorWithOffset(make_vector(a0)); + const Array<1, T> a = NumericVectorWithOffset(make_vector(a0)); return a; } template -Array -make_array(const Array& a0, const Array& a1) +Array +make_array(const Array& a0, const Array& a1) { - const Array a = NumericVectorWithOffset,T>(make_vector(a0, 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) +Array +make_array(const Array& a0, const Array& a1, const Array& a2) { - const Array a = NumericVectorWithOffset,T>(make_vector(a0, a1, 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) +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)); + 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) +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)); + 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) +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)); + 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) +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)); + 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) +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)); + 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) +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)); + 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) +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)); + 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 d2030a0b3..64daeb18e 100644 --- a/src/include/stir/min_positive_element.h +++ b/src/include/stir/min_positive_element.h @@ -13,9 +13,9 @@ #define __stir_min_positive_element_h_ /*! - \file + \file \ingroup buildblock - + \brief Declares the stir::min_positive_element() function \author Kris Thielemans @@ -32,27 +32,28 @@ 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 +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 c7b2ee1f6..7a7254825 100644 --- a/src/include/stir/modelling/KineticModel.h +++ b/src/include/stir/modelling/KineticModel.h @@ -15,7 +15,7 @@ \brief Definition of class stir::KineticModel \author Charalampos Tsoumpas - + */ #ifndef __stir_modelling_KineticModel_H__ @@ -26,18 +26,18 @@ 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 @@ -50,7 +50,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 0e378bb74..2961efb21 100644 --- a/src/include/stir/modelling/KineticParameters.h +++ b/src/include/stir/modelling/KineticParameters.h @@ -15,7 +15,7 @@ \brief Declaration of class stir::KineticParameters \author Charalampos Tsoumpas - + */ #ifndef __stir_modelling_KineticParameters_H__ @@ -27,25 +27,23 @@ START_NAMESPACE_STIR template -class KineticParameters:public BasicCoordinate +class KineticParameters : public BasicCoordinate { - typedef BasicCoordinate base_type; - public: - KineticParameters() - {} + 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) +inline void +assign(KineticParameters& v, const T2& y) { - for (typename KineticParameters::iterator iter = v.begin(); - iter != v.end(); ++iter) + 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 f5f629418..77f6a783d 100644 --- a/src/include/stir/modelling/KineticParameters.inl +++ b/src/include/stir/modelling/KineticParameters.inl @@ -19,31 +19,34 @@ 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 6216bb01d..1f721b9cb 100644 --- a/src/include/stir/modelling/ModelMatrix.h +++ b/src/include/stir/modelling/ModelMatrix.h @@ -13,7 +13,7 @@ \ingroup modelling \brief Declaration of class stir::ModelMatrix \author Charalampos Tsoumpas - + */ #ifndef __stir_modelling_ModelMatrix_H__ @@ -34,91 +34,87 @@ START_NAMESPACE_STIR */ template 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 f40dbbfaf..1277a8825 100644 --- a/src/include/stir/modelling/ModelMatrix.inl +++ b/src/include/stir/modelling/ModelMatrix.inl @@ -23,342 +23,345 @@ START_NAMESPACE_STIR //! default constructor -template +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; + // 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 +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"); +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 ; + 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) + + 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; + 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. -} + 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) + 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; + 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 << " " ; + 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) + 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) + 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) + 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] ; + 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; + 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_in_correct_scale(const bool in_correct_scale) +{ + this->_in_correct_scale = in_correct_scale; } -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::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)) + 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; - + 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. "); + 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)) + 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; - } + 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) +template +void +ModelMatrix::convert_to_total_frame_counts(const TimeFrameDefinitions& time_frame_definitions) { - if (ModelMatrix::_is_converted_to_total_counts==true) + 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)) + 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; + 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 +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)) + 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) + 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 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) + 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 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) + 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; + 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 +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)) + 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) + 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 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) + 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 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 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 +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)) + 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) + 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 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) + 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 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) + 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]); + 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 87105f349..6e5b192b2 100644 --- a/src/include/stir/modelling/ParametricDiscretisedDensity.h +++ b/src/include/stir/modelling/ParametricDiscretisedDensity.h @@ -17,12 +17,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 @@ -37,13 +37,13 @@ template struct Parametric2Single; template -struct Parametric2Single > +struct Parametric2Single> { typedef typename Parametric2Single::type type; }; template -struct Parametric2Single > > +struct Parametric2Single>> { typedef VoxelsOnCartesianGrid type; }; @@ -61,13 +61,13 @@ struct Parametric2Single -class ParametricDiscretisedDensity: -public DiscDensT +class ParametricDiscretisedDensity : public DiscDensT { - private: +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). @@ -80,20 +80,18 @@ 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) - {} + : base_type(density) + {} /// Create blank parametric image from a dynamic image /*! Uses only its geometric/exam info and timing */ @@ -109,43 +107,37 @@ 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()); } + { + 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()); } + { + 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. ParametricDiscretisedDensity* get_empty_copy() const override; @@ -153,39 +145,31 @@ public DiscDensT //! Allocate a new object which is a copy of the current one. ParametricDiscretisedDensity* clone() const override; - //! 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 2603bd4af..13ff84aa8 100644 --- a/src/include/stir/modelling/ParseAndCreateParametricDiscretisedDensityFrom.h +++ b/src/include/stir/modelling/ParseAndCreateParametricDiscretisedDensityFrom.h @@ -1,9 +1,9 @@ /* Copyright (C) 2019, University College London - This file is part of STIR. - - SPDX-License-Identifier: Apache-2.0 - + This file is part of STIR. + + SPDX-License-Identifier: Apache-2.0 + See STIR/LICENSE.txt for details */ /*! @@ -31,15 +31,12 @@ class KeyParser; \see ParseAndCreateFrom, ExamDataT> */ template - class ParseAndCreateFrom >, - ExamDataT> - : public ParseDiscretisedDensityParameters +class ParseAndCreateFrom>, ExamDataT> + : public ParseDiscretisedDensityParameters { - public: - typedef ParametricDiscretisedDensity > output_type; - inline - output_type* - create(const ExamDataT&) const; +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 fef65fe91..690f5b094 100644 --- a/src/include/stir/modelling/ParseAndCreateParametricDiscretisedDensityFrom.inl +++ b/src/include/stir/modelling/ParseAndCreateParametricDiscretisedDensityFrom.inl @@ -1,9 +1,9 @@ /* Copyright (C) 2019, University College London - This file is part of STIR. - - SPDX-License-Identifier: Apache-2.0 - + This file is part of STIR. + + SPDX-License-Identifier: Apache-2.0 + See STIR/LICENSE.txt for details */ /*! @@ -12,7 +12,7 @@ \brief implementation of the stir::ParseAndCreateFrom class for stir:ParametricDiscretisedDensity - \author Kris Thielemans + \author Kris Thielemans */ #include "stir/VoxelsOnCartesianGrid.h" @@ -21,28 +21,19 @@ START_NAMESPACE_STIR - template -ParametricDiscretisedDensity >* -ParseAndCreateFrom >, ExamDataT>:: -create(const ExamDataT& exam_data) const +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()) - ) - ); + 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 570d91f44..7e33de305 100644 --- a/src/include/stir/modelling/PatlakPlot.h +++ b/src/include/stir/modelling/PatlakPlot.h @@ -17,7 +17,6 @@ */ - #ifndef __stir_modelling_PatlakPlot_H__ #define __stir_modelling_PatlakPlot_H__ @@ -35,13 +34,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 @@ -60,97 +60,91 @@ 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 +class PatlakPlot : public RegisteredParsingObject { - public: +public: //! Name which will be used when parsing a PatlakPlot object - static const char * const registered_name; - - PatlakPlot(); //!< Default constructor (calls set_defaults()) - ~PatlakPlot() override; //!< 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 number of the last frame available. - unsigned int - get_ending_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() override; - - Succeeded set_up() override; - - 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() override; //!< 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 number of the last frame available. + unsigned int get_ending_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() override; + + Succeeded set_up() override; + + 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() override; bool post_processing() override; 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 a959420e9..db4548b42 100644 --- a/src/include/stir/modelling/PlasmaData.h +++ b/src/include/stir/modelling/PlasmaData.h @@ -13,7 +13,7 @@ \ingroup modelling \brief Declaration of class stir::PlasmaData \author Charalampos Tsoumpas - + */ #ifndef __stir_modelling_PlasmaData_H__ @@ -30,91 +30,94 @@ START_NAMESPACE_STIR \see PlasmaSample */ -class PlasmaData +class PlasmaData { - typedef std::vector plot_type; - - public: + 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 bac054cfd..e72f87330 100644 --- a/src/include/stir/modelling/PlasmaData.inl +++ b/src/include/stir/modelling/PlasmaData.inl @@ -26,250 +26,288 @@ START_NAMESPACE_STIR //! default constructor 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) +//! 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.; + this->_plasma_blood_plot = plasma_blood_plot; + this->set_is_decay_corrected(false); + this->_isotope_halflife = -1.; } //! default destructor 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"); +//! 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::bind(std::not_equal_to(), ' ', std::placeholders::_1)).base(), first_line.end()); - first_line.erase(first_line.begin(), std::find_if(first_line.begin(), first_line.end(), std::bind(std::not_equal_to(), ' ', std::placeholders::_1))); - // 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"); + // 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::bind(std::not_equal_to(), ' ', std::placeholders::_1)) + .base(), + first_line.end()); + first_line.erase(first_line.begin(), + std::find_if(first_line.begin(), + first_line.end(), + std::bind(std::not_equal_to(), ' ', std::placeholders::_1))); + // 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"); + else + _sample_size = converted; + } else - _sample_size=converted; - } - else - { - error("Input function file ("+ input_string + ") is empty"); + { + error("Input function file (" + input_string + ") is empty"); + } } - } - while(true) + 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) + 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); + 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; } +{ + 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() +void +PlasmaData::decay_correct_PlasmaData() { - - if (this->_is_decay_corrected==true) + + 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) + 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()))); - } + 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 PlasmaData::get_sample_data_in_frames(TimeFrameDefinitions time_frame_def) -{ - if (this->_is_decay_corrected==false) +{ + 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 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) + 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]))) ; + 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]) ; + 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) + 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_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) ; + 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() ; } +{ + return this->_plasma_blood_plot.begin(); +} PlasmaData::const_iterator PlasmaData::end() const -{ return this->_plasma_blood_plot.end() ; } +{ + return this->_plasma_blood_plot.end(); +} unsigned int PlasmaData::size() const -{ return static_cast(this->_plasma_blood_plot.size()) ; } +{ + 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 944a0030e..ffacd0c60 100644 --- a/src/include/stir/modelling/PlasmaSample.h +++ b/src/include/stir/modelling/PlasmaSample.h @@ -13,7 +13,7 @@ \ingroup modelling \brief Declaration of class stir::PlasmaData \author Charalampos Tsoumpas - + */ #ifndef __stir_modelling_PlasmaSample_H__ @@ -35,44 +35,42 @@ START_NAMESPACE_STIR currently not be encoded. */ 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 d7fbe9fbb..e4f096ee9 100644 --- a/src/include/stir/modelling/PlasmaSample.inl +++ b/src/include/stir/modelling/PlasmaSample.inl @@ -19,46 +19,61 @@ START_NAMESPACE_STIR - //! default constructor +//! default constructor PlasmaSample::PlasmaSample() -{ } - //! constructor, time in s -PlasmaSample:: -PlasmaSample(const double sample_time, const float plasma_sample_counts, const float blood_sample_counts) +{} +//! 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 ); + 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 +//! default destructor PlasmaSample::~PlasmaSample() -{ } - - //! set the time of the sample -void PlasmaSample::set_time_in_s( const double time ) -{ PlasmaSample::_time=time ; } +{} - //! 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 97707c21d..3f2d38b91 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 @@ -31,14 +31,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. @@ -48,102 +48,96 @@ START_NAMESPACE_STIR give you float which is (a tiny bit) larger than fabs(b). */ -inline -double +inline double modulo(const double a, const double b) { - const double res = fmod(a,b); - return res<0 ? res + fabs(b) : res; + 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 +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); + 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 +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)); + 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 +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 +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) + 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 +inline FloatOrDouble to_0_2pi(const FloatOrDouble phi) { - return modulo(phi, static_cast(2*_PI)); + return modulo(phi, static_cast(2 * _PI)); } //@} diff --git a/src/include/stir/more_algorithms.h b/src/include/stir/more_algorithms.h index de68f2936..3cdb7bd85 100644 --- a/src/include/stir/more_algorithms.h +++ b/src/include/stir/more_algorithms.h @@ -13,9 +13,9 @@ /*! \file \ingroup buildblock - + \brief Declaration of some functions missing from std::algorithm - + \author Kris Thielemans */ @@ -29,54 +29,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 4753005ef..40670e132 100644 --- a/src/include/stir/more_algorithms.inl +++ b/src/include/stir/more_algorithms.inl @@ -11,9 +11,9 @@ /*! \file \ingroup buildblock - + \brief Implementation of some functions missing from std::algorithm - + \author Kris Thielemans */ @@ -23,63 +23,60 @@ 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) + while (iter != end) { - const double n=norm_squared(*iter); - if (n>current_max) - { - current_max=n; current_max_iter=iter; - } + 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 +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 +template +inline typename std::iterator_traits::value_type sum(IterT start, IterT end) { - if (start==end) + if (start == end) { typename std::iterator_traits::value_type tmp; tmp *= 0; return tmp; } - return sum(start+1,end,*start); + return sum(start + 1, end, *start); } -template -inline -typename std::iterator_traits::value_type +template +inline typename std::iterator_traits::value_type average(IterT start, IterT end) { - typename std::iterator_traits::value_type tmp = - sum(start, 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/multiply_crystal_factors.h b/src/include/stir/multiply_crystal_factors.h index e51b53270..ac8951ef1 100644 --- a/src/include/stir/multiply_crystal_factors.h +++ b/src/include/stir/multiply_crystal_factors.h @@ -22,7 +22,8 @@ START_NAMESPACE_STIR class ProjData; -template class Array; +template +class Array; /*! \ingroup projdata @@ -46,6 +47,6 @@ template class Array; the existing data with the efficiencies, but overwrites it. */ -void multiply_crystal_factors(ProjData& proj_data, const Array<2,float>& efficiencies, const float global_factor); +void multiply_crystal_factors(ProjData& proj_data, const Array<2, float>& efficiencies, const float global_factor); END_NAMESPACE_STIR diff --git a/src/include/stir/num_threads.h b/src/include/stir/num_threads.h index 8732178e3..7e65104f7 100644 --- a/src/include/stir/num_threads.h +++ b/src/include/stir/num_threads.h @@ -13,7 +13,7 @@ \brief Implementation of functions related to setting/getting the number of threads - \author Kris Thielemans + \author Kris Thielemans */ #include "stir/common.h" @@ -24,7 +24,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() */ @@ -51,8 +51,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(); @@ -60,7 +60,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 d3c1b4228..cde2aa3ad 100644 --- a/src/include/stir/numerics/BSplines.h +++ b/src/include/stir/numerics/BSplines.h @@ -4,16 +4,16 @@ This file is part of STIR. SPDX-License-Identifier: Apache-2.0 - + 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 @@ -23,52 +23,56 @@ START_NAMESPACE_STIR -namespace BSpline { - - /*! \brief The type used for relative positions between the grid points. - \ingroup BSpline - */ - typedef double pos_type; +namespace BSpline +{ - /*! \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 0e5b4bf35..516822e17 100644 --- a/src/include/stir/numerics/BSplines1DRegularGrid.h +++ b/src/include/stir/numerics/BSplines1DRegularGrid.h @@ -4,16 +4,16 @@ This file is part of STIR. SPDX-License-Identifier: Apache-2.0 - + 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 @@ -24,107 +24,85 @@ START_NAMESPACE_STIR -namespace BSpline +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 { - - /*! \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 +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 ecaa5f0bb..f3f6b4b22 100644 --- a/src/include/stir/numerics/BSplines1DRegularGrid.inl +++ b/src/include/stir/numerics/BSplines1DRegularGrid.inl @@ -8,9 +8,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 @@ -20,42 +20,39 @@ #include "stir/assign.h" 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); - } +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); +} #if 0 // needs to be in .h for VC 6.0 @@ -74,16 +71,16 @@ 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); - } - - 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()); - } - -} // end BSpline namespace + 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 0810d65c2..ec4ec9d80 100644 --- a/src/include/stir/numerics/BSplinesDetail.inl +++ b/src/include/stir/numerics/BSplinesDetail.inl @@ -4,103 +4,98 @@ This file is part of STIR. SPDX-License-Identifier: Apache-2.0 - + 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 */ #include "stir/assign.h" #ifndef __stir_numerics_BSplinesDetail_inl_ -#define __stir_numerics_BSplinesDetail_inl_ +# define __stir_numerics_BSplinesDetail_inl_ 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) +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) { - 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))); + 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; } - - - // 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]); - } + 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)); - } - } - -#if 0 +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 { @@ -120,211 +115,203 @@ namespace BSpline { return BSplines_1st_der_weight(p, type); } }; -#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 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) +# else +template +struct BW +{ + typedef pos_type result_type; + pos_type operator()(const pos_type pos, int piece, const PieceWiseFunction& f) { - 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 -#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 -#else -#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) * -#ifdef NNN - f(current_pos, p, bspline) -#else - f(current_pos, spline_types[current_dimension]) -#endif - ); - } - return value ; + return f.function_piece(pos, piece); } +}; - template - inline - T - spline_convolution(const Array<1, T>& coeffs, - const BasicCoordinate& relative_positions, - const BasicCoordinate& spline_types, - FunctionT f) +template +struct Bder +{ + typedef pos_type result_type; + pos_type operator()(const pos_type pos, int piece, const PieceWiseFunction& 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 -#else -#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] * -#ifdef NNN - f(current_pos, p, bspline) - // bspline.function_piece(current_pos, p) -#else - f(current_pos, spline_types[current_dimension]) -#endif - ); - } - return value ; + return f.derivative_piece(pos, piece); } +}; +# endif - template - struct - compute_BSplines_value - { - typedef T result_type; - T operator()(const Array& coeffs, - const BasicCoordinate& relative_positions, - const BasicCoordinate& spline_types) const +// 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 +# 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 +# else +# define DECR_P +# endif + for (; k <= kmax; ++k, --current_pos DECR_P) { - return - spline_convolution(coeffs, relative_positions, spline_types, - BW(), - //BSplineFunction(), - compute_BSplines_value()); + 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) +# else + f(current_pos, spline_types[current_dimension]) +# endif + ); } - }; + return value; +} - template - 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 +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 +# else +# define DECR_P +# endif + for (; k <= kmax; ++k, --current_pos DECR_P) { - return - spline_convolution(coeffs, relative_positions, spline_types, - BW() - //BSplineFunction() - ); + 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) +# else + f(current_pos, spline_types[current_dimension]) +# endif + ); } - }; + return value; +} - template - struct - compute_BSplines_gradient +template +struct compute_BSplines_value +{ + typedef T result_type; + T operator()(const Array& coeffs, + const BasicCoordinate& relative_positions, + const BasicCoordinate& spline_types) const { - typedef BasicCoordinate result_type; + return spline_convolution(coeffs, + relative_positions, + spline_types, + BW(), + // BSplineFunction(), + compute_BSplines_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); - } - }; +template +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() + ); + } +}; + +template +struct compute_BSplines_gradient +{ + typedef BasicCoordinate result_type; - template - struct - compute_BSplines_gradient<1,num_dimensions2,T> + BasicCoordinate operator()(const Array& coeffs, + const BasicCoordinate& relative_positions, + const BasicCoordinate& spline_types) const { - typedef BasicCoordinate<1,T> result_type; + 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<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; - } - }; +template +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; + } +}; -} // 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 92a0959ee..3bfd64e2f 100644 --- a/src/include/stir/numerics/BSplinesRegularGrid.h +++ b/src/include/stir/numerics/BSplinesRegularGrid.h @@ -4,15 +4,15 @@ This file is part of STIR. SPDX-License-Identifier: Apache-2.0 - + 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 @@ -23,139 +23,116 @@ #include "stir/numerics/BSplines.h" 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 +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); +}; + +} // namespace BSpline END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/BSplinesRegularGrid.inl b/src/include/stir/numerics/BSplinesRegularGrid.inl index ed42401d9..4e9acaec6 100644 --- a/src/include/stir/numerics/BSplinesRegularGrid.inl +++ b/src/include/stir/numerics/BSplinesRegularGrid.inl @@ -4,13 +4,13 @@ This file is part of STIR. SPDX-License-Identifier: Apache-2.0 - + 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 @@ -19,60 +19,60 @@ #include "stir/numerics/BSplinesDetail.inl" START_NAMESPACE_STIR -namespace BSpline { +namespace BSpline +{ - template -BSplinesRegularGrid:: -~BSplinesRegularGrid() +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); - } - 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 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); +} + +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 107678e0e..ad26a6684 100644 --- a/src/include/stir/numerics/BSplines_coef.inl +++ b/src/include/stir/numerics/BSplines_coef.inl @@ -7,9 +7,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 @@ -20,100 +20,109 @@ #include "stir/numerics/IR_filters.h" START_NAMESPACE_STIR -namespace BSpline { +namespace BSpline +{ - namespace detail - { - template - inline - typename std::iterator_traits::value_type - cplus0(const IterT input_begin_iterator, - const IterT input_end_iterator, - const constantsT z1, const constantsT precision, const bool periodicity) +namespace detail +{ +template +inline typename std::iterator_traits::value_type +cplus0(const IterT input_begin_iterator, + const IterT input_end_iterator, + const constantsT z1, + const constantsT precision, + const bool periodicity) +{ + typedef typename std::iterator_traits::value_type out_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) { - typedef typename std::iterator_traits::value_type out_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) - { - - typedef typename std::iterator_traits::value_type out_elemT; - - /* - 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); - } + 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) +{ + + typedef typename std::iterator_traits::value_type out_elemT; + + /* + 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 77e64f293..41d45427a 100644 --- a/src/include/stir/numerics/BSplines_weights.inl +++ b/src/include/stir/numerics/BSplines_weights.inl @@ -10,9 +10,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 @@ -22,201 +22,172 @@ #include "stir/error.h" START_NAMESPACE_STIR -namespace BSpline +namespace BSpline { - template - class PieceWiseFunction - { - public: - typedef posT result_type; +template +class PieceWiseFunction +{ +public: + typedef posT result_type; - virtual ~PieceWiseFunction() {} + 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); - } + 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 +{ +}; - template - class BSplineFunction: public PieceWiseFunction +template +class BSplineFunction : public PieceWiseFunction +{ +public: + BSplineFunction() {} + posT kernel_length_left() const override { return static_cast(.5); } + BOOST_STATIC_CONSTANT(int, kernel_total_length_value = 1); + int kernel_total_length() const override { return kernel_total_length_value; } + posT function_piece(const posT x, int p) const override { - public: - BSplineFunction() {} - posT kernel_length_left() const override { return static_cast(.5); } - BOOST_STATIC_CONSTANT(int, kernel_total_length_value=1); - int kernel_total_length() const override { return kernel_total_length_value; } - posT function_piece(const posT x, int p) const override - { - 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 override - { - return 0; - } - - int find_abs_piece(const posT absx) const - { - return static_cast(absx+.5); - } - int find_piece(const posT x) const override - { - 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 override - { - return 0; - } - }; + 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 override { return 0; } - template - class BSplineFunction: public PieceWiseFunction + int find_abs_piece(const posT absx) const { return static_cast(absx + .5); } + int find_piece(const posT x) const override { - public: - BSplineFunction() {} - posT kernel_length_left() const override { return static_cast(1); } - BOOST_STATIC_CONSTANT(int, kernel_total_length_value=2); - int kernel_total_length() const override { return kernel_total_length_value; } - posT function_piece(const posT x, int p) const override - { - switch (p) - { - case 0: - return 1-x; - case -1: - return 1+x; - default: - return 0; - } - } - posT derivative_piece(const posT x, int p) const override - { - switch (p) - { - case 0: - return -1; - case -1: - return 1; - default: - return 0; - } - } - int find_piece(const posT x) const override - { - return static_cast(floor(x)); - } + 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 override { return 0; } +}; - int find_highest_piece() const override - { - return 0; - } - }; +template +class BSplineFunction : public PieceWiseFunction +{ +public: + BSplineFunction() {} + posT kernel_length_left() const override { return static_cast(1); } + BOOST_STATIC_CONSTANT(int, kernel_total_length_value = 2); + int kernel_total_length() const override { return kernel_total_length_value; } + posT function_piece(const posT x, int p) const override + { + switch (p) + { + case 0: + return 1 - x; + case -1: + return 1 + x; + default: + return 0; + } + } + posT derivative_piece(const posT x, int p) const override + { + switch (p) + { + case 0: + return -1; + case -1: + return 1; + default: + return 0; + } + } + int find_piece(const posT x) const override { return static_cast(floor(x)); } + + int find_highest_piece() const override { return 0; } +}; - template - class BSplineFunction: public PieceWiseFunction +template +class BSplineFunction : public PieceWiseFunction +{ +public: + BSplineFunction() {} + posT kernel_length_left() const override { return static_cast(1.5); } + BOOST_STATIC_CONSTANT(int, kernel_total_length_value = 3); + int kernel_total_length() const override { return kernel_total_length_value; } + posT function_piece(const posT x, int p) const override { - public: - BSplineFunction() {} - posT kernel_length_left() const override { return static_cast(1.5); } - BOOST_STATIC_CONSTANT(int, kernel_total_length_value=3); - int kernel_total_length() const override { return kernel_total_length_value; } - posT function_piece(const posT x, int p) const override - { - 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; + 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 override - { - 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; + default: + return 0; + } + } + posT derivative_piece(const posT x, int p) const override + { + 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); } - } - private: - int find_abs_piece(const posT absx) const - { + default: + return 0; + } + } + +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 override - { - 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 override - { - return 1; - } +public: + int find_piece(const posT x) const override + { + 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 override + { + return 1; + } #if 0 posT function(const posT x) const @@ -233,243 +204,219 @@ namespace BSpline return 0; } #endif - }; - - template - class BSplineFunction: public PieceWiseFunction - { - public: - BSplineFunction() {} - posT kernel_length_left() const override { return static_cast(2); } - BOOST_STATIC_CONSTANT(int, kernel_total_length_value=4); - int kernel_total_length() const override { return kernel_total_length_value; } - posT function_piece(const posT x, int p) const override - { - 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; - } - } - posT derivative_piece(const posT x, int p) const override - { - 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 override - { - return static_cast(floor(x)); - } - int find_highest_piece() const override - { - return 1; - } - }; - +}; - template - class BSplineFunction: public PieceWiseFunction - { - public: - BSplineFunction() {} - posT kernel_length_left() const override { return static_cast(2); } - BOOST_STATIC_CONSTANT(int, kernel_total_length_value=4); - int kernel_total_length() const override { return kernel_total_length_value; } - posT function_piece(const posT x, int p) const override - { - 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 override - { - 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 override - { - return static_cast(floor(x)); - } - int find_highest_piece() const override - { - 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) +template +class BSplineFunction : public PieceWiseFunction +{ +public: + BSplineFunction() {} + posT kernel_length_left() const override { return static_cast(2); } + BOOST_STATIC_CONSTANT(int, kernel_total_length_value = 4); + int kernel_total_length() const override { return kernel_total_length_value; } + posT function_piece(const posT x, int p) const override { - switch (type) + const posT absx = std::fabs(x); + switch (p) { - 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 + 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 - 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) + posT derivative_piece(const posT x, int p) const override { - 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.); + 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 override { return static_cast(floor(x)); } + int find_highest_piece() const override { return 1; } +}; - template - posT - BSplines_1st_der_weight(const posT relative_position, const BSplineType spline_type) +template +class BSplineFunction : public PieceWiseFunction +{ +public: + BSplineFunction() {} + posT kernel_length_left() const override { return static_cast(2); } + BOOST_STATIC_CONSTANT(int, kernel_total_length_value = 4); + int kernel_total_length() const override { return kernel_total_length_value; } + posT function_piece(const posT x, int p) const override { - switch(spline_type) + const posT absx = std::fabs(x); + switch (p) { - case cubic: - return cubic_BSplines_1st_der_weight(relative_position); + 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: - 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) + posT derivative_piece(const posT x, int p) const override { - // double relative_position = rel_position; - switch(spline_type) + const posT absx = std::fabs(x); + const int sign = x > 0 ? 1 : -1; + switch (p) { - 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); + 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: - error("Not implemented b-spline type"); - return -1000000; + return 0; } } + int find_piece(const posT x) const override { return static_cast(floor(x)); } + int find_highest_piece() const override { return 1; } +}; -} // end BSpline namespace +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; -END_NAMESPACE_STIR +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; + } + 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; + } +} + +} // namespace BSpline + +END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/FastErf.h b/src/include/stir/numerics/FastErf.h index 1422fb28e..abc6d13ce 100644 --- a/src/include/stir/numerics/FastErf.h +++ b/src/include/stir/numerics/FastErf.h @@ -18,11 +18,10 @@ #include "stir/numerics/BSplines1DRegularGrid.h" #ifndef __stir_numerics_FastErf__H__ -#define __stir_numerics_FastErf__H__ +# define __stir_numerics_FastErf__H__ START_NAMESPACE_STIR - /*! \ingroup numerics \name FastErf \brief The class acts as a potentially faster way to compute many erf values by precomputing the function at @@ -34,15 +33,14 @@ START_NAMESPACE_STIR class FastErf { private: - //! The number of erf samples to take from -\c_maximum_sample_value to \c_maximum_sample_value int _num_samples; //! The sampling period, computed as \c_maximum_sample_value / \c_num_samples) double _sampling_period; -// //! Used to check if setup has been run before parameter changes -// bool _is_setup = false; + // //! Used to check if setup has been run before parameter changes + // bool _is_setup = false; //! BSplines object using linear interpolation BSpline::BSplines1DRegularGrid _spline; @@ -57,7 +55,8 @@ class FastErf public: explicit FastErf(const int num_samples = 1000, const float maximum_sample_value = 5) - : _num_samples(num_samples), _maximum_sample_value(maximum_sample_value ) + : _num_samples(num_samples), + _maximum_sample_value(maximum_sample_value) {} //! Returns the number of erf samples @@ -73,32 +72,31 @@ class FastErf /*! \brief Computes the erf() values, sets up BSplines and sets up interpolation vectors. */ inline void set_up(); -/*! \brief Uses BSplines to interpolate the value of erf(xp) - * If xp out of range (-\c_maximum_sample_value \c_maximum_sample_value) then outputs -1 or 1 - * @param xp input argument for erf(xp) - * @return interpolated approximation of erf(xp) - */ -inline double get_erf_BSplines_interpolation(double xp) const; - -/*! \brief Uses linear interpolation of precomputed erf(x) values for erf(xp) - * @param xp input argument for erf(xp) - * @return linear interpolated approximation of erf(xp) - */ -inline double get_erf_linear_interpolation(double xp) const; - -/*! \brief Uses nearest neighbour interpolation of precomputed erf(x) values for erf(xp) - * @param xp input argument for erf(xp) - * @return nearest neighbour interpolated approximation of erf(xp) - */ -inline double get_erf_nearest_neighbour_interpolation(double xp) const; + /*! \brief Uses BSplines to interpolate the value of erf(xp) + * If xp out of range (-\c_maximum_sample_value \c_maximum_sample_value) then outputs -1 or 1 + * @param xp input argument for erf(xp) + * @return interpolated approximation of erf(xp) + */ + inline double get_erf_BSplines_interpolation(double xp) const; - //! Wraps get_erf_linear_interpolation as a () operator - inline const double operator() (const double xp) const; + /*! \brief Uses linear interpolation of precomputed erf(x) values for erf(xp) + * @param xp input argument for erf(xp) + * @return linear interpolated approximation of erf(xp) + */ + inline double get_erf_linear_interpolation(double xp) const; + + /*! \brief Uses nearest neighbour interpolation of precomputed erf(x) values for erf(xp) + * @param xp input argument for erf(xp) + * @return nearest neighbour interpolated approximation of erf(xp) + */ + inline double get_erf_nearest_neighbour_interpolation(double xp) const; + //! Wraps get_erf_linear_interpolation as a () operator + inline const double operator()(const double xp) const; }; END_NAMESPACE_STIR -#include "stir/numerics/FastErf.inl" +# include "stir/numerics/FastErf.inl" #endif // __stir_numerics_FastErf__H__ diff --git a/src/include/stir/numerics/FastErf.inl b/src/include/stir/numerics/FastErf.inl index e40fea9d5..7fb19d767 100644 --- a/src/include/stir/numerics/FastErf.inl +++ b/src/include/stir/numerics/FastErf.inl @@ -19,14 +19,13 @@ START_NAMESPACE_STIR inline void -FastErf:: -set_up() +FastErf::set_up() { this->_sampling_period = (2 * this->_maximum_sample_value) / this->get_num_samples(); - + // Add two samples for end cases and compute a vector of erf values std::vector erf_values(this->get_num_samples() + 2); - for (int i=0; iget_num_samples() + 2; ++i) + for (int i = 0; i < this->get_num_samples() + 2; ++i) erf_values[i] = erf(i * this->_sampling_period - this->_maximum_sample_value); // Setup BSplines @@ -34,7 +33,7 @@ set_up() this->_spline = spline; erf_values_vec = erf_values; -// this->_is_setup = true; + // this->_is_setup = true; } inline double @@ -48,10 +47,8 @@ FastErf::get_erf_BSplines_interpolation(double xp) const return this->_spline.BSplines((xp + this->_maximum_sample_value) / this->_sampling_period); } - inline double -FastErf:: -get_erf_linear_interpolation(double xp) const +FastErf::get_erf_linear_interpolation(double xp) const { #if 0 xp = std::clamp(xp,-this->_maximum_sample_value, this->_maximum_sample_value); @@ -77,7 +74,7 @@ FastErf::get_erf_nearest_neighbour_interpolation(double xp) const xp = std::max(std::min(this->_maximum_sample_value, xp), -this->_maximum_sample_value); #endif // Selects index of the nearest neighbour via rounding - return erf_values_vec[static_cast(std::round((xp + this->_maximum_sample_value) / this->_sampling_period))]; + return erf_values_vec[static_cast(std::round((xp + this->_maximum_sample_value) / this->_sampling_period))]; } inline void @@ -86,8 +83,7 @@ FastErf::set_num_samples(const int num_samples) this->_num_samples = num_samples; } -inline -int +inline int FastErf::get_num_samples() const { return this->_num_samples; @@ -106,7 +102,7 @@ FastErf::set_maximum_sample_value(double maximum_sample_value) } const double -FastErf::operator() (const double xp) const +FastErf::operator()(const double xp) const { return get_erf_linear_interpolation(xp); } diff --git a/src/include/stir/numerics/IR_filters.h b/src/include/stir/numerics/IR_filters.h index d3ac5aed0..569bd08bf 100644 --- a/src/include/stir/numerics/IR_filters.h +++ b/src/include/stir/numerics/IR_filters.h @@ -9,7 +9,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics \brief Implementation of the IIR and FIR filters @@ -28,37 +28,28 @@ 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 b560d7a14..4471a6996 100644 --- a/src/include/stir/numerics/IR_filters.inl +++ b/src/include/stir/numerics/IR_filters.inl @@ -8,7 +8,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics \brief implements the IR_filters @@ -18,101 +18,89 @@ 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) + 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 - ) + 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) + if (current_current_input_iterator == input_begin_iterator) break; } 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) -= + 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) -= #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) + 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) +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); + 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 df4104d61..a9f448301 100644 --- a/src/include/stir/numerics/MatrixFunction.h +++ b/src/include/stir/numerics/MatrixFunction.h @@ -13,9 +13,9 @@ /*! \file \ingroup numerics - + \brief Declaration of functions for matrices - + \author Kris Thielemans \author Sanida Mustafovic @@ -25,7 +25,6 @@ START_NAMESPACE_STIR - //---------------------------------------------------------------------- /*! \ingroup numerics \name functions specific for 1D Arrays @@ -33,27 +32,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 @@ -63,33 +59,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 @@ -98,17 +90,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 @@ -117,15 +107,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 2ffd5612d..1ab013a3e 100644 --- a/src/include/stir/numerics/MatrixFunction.inl +++ b/src/include/stir/numerics/MatrixFunction.inl @@ -11,9 +11,9 @@ /*! \file \ingroup numerics - + \brief Implementation of functions for matrices - + \author Kris Thielemans \author Sanida Mustafovic @@ -21,112 +21,116 @@ #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) +angle(const Array<1, elemT>& v1, const Array<1, elemT>& v2) { - return std::acos(inner_product(v1,v2)/norm(v1)/ norm(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 +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]; - } - } +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) +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()); + 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) +template +inline BasicCoordinate +matrix_multiply(const Array<2, elemT>& m, const BasicCoordinate& vec) { - BasicCoordinate ret; + 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(); @@ -137,61 +141,59 @@ 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) + 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]; - } + 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) +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 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) +inline Array<2, elemT> +diagonal_matrix(const BasicCoordinate& values) { - Array<2,elemT> m(IndexRange2D(dimension,dimension)); - for (unsigned int i=0; i 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 47d0a5333..b6d6ba2c8 100644 --- a/src/include/stir/numerics/determinant.h +++ b/src/include/stir/numerics/determinant.h @@ -13,9 +13,9 @@ /*! \file \ingroup numerics - + \brief Declaration of stir::determinant() function for matrices - + \author Kris Thielemans */ @@ -23,18 +23,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 fe2f8c156..e8e59e753 100644 --- a/src/include/stir/numerics/divide.h +++ b/src/include/stir/numerics/divide.h @@ -19,34 +19,30 @@ \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 c65054f94..90a9dd534 100644 --- a/src/include/stir/numerics/divide.inl +++ b/src/include/stir/numerics/divide.inl @@ -17,35 +17,30 @@ \author Matthew Jacobson \author Kris Thielemans \author PARAPET project - + */ #include START_NAMESPACE_STIR -template -void -divide( - const NumeratorIterT& numerator_begin, +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; + 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); + 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; } diff --git a/src/include/stir/numerics/erf.h b/src/include/stir/numerics/erf.h index 646a6672d..ac5681d30 100644 --- a/src/include/stir/numerics/erf.h +++ b/src/include/stir/numerics/erf.h @@ -11,7 +11,7 @@ /*! \file \ingroup numerics - + \author Charalampos Tsoumpas \author Kris Thielemans @@ -20,27 +20,25 @@ #include "stir/common.h" #ifndef __stir_numerics_erf__H__ -#define __stir_numerics_erf__H__ +# define __stir_numerics_erf__H__ 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" +# include "stir/numerics/erf.inl" #endif // __stir_numerics_erf__H__ diff --git a/src/include/stir/numerics/erf.inl b/src/include/stir/numerics/erf.inl index 4a84e2338..3c5329955 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,275 @@ 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 +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); + 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 +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; + 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 91f1466c5..21ad9df28 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 @@ -18,13 +18,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. @@ -39,10 +37,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. @@ -52,17 +48,18 @@ fourier(T& c, const int sign = 1); \see fourier */ template -inline void inverse_fourier(T& c, const int sign=1) +inline void +inverse_fourier(T& c, const int sign = 1) { - fourier(c,-sign); + 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 } @@ -78,16 +75,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\), @@ -106,16 +103,17 @@ void fourier_1d(T& c, const int sign); \see fourier_1d() */ template -inline void inverse_fourier_1d(T& c, const int sign=1) +inline void +inverse_fourier_1d(T& c, const int sign = 1) { - fourier_1d(c,-sign); + 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 } @@ -123,11 +121,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 @@ -142,20 +140,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 @@ -165,8 +161,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 @@ -176,14 +171,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, @@ -192,11 +186,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. @@ -204,8 +198,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 @@ -215,9 +208,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 @@ -227,8 +218,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. @@ -236,9 +227,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 75e42c22b..42853b762 100644 --- a/src/include/stir/numerics/ieeefp.h +++ b/src/include/stir/numerics/ieeefp.h @@ -13,8 +13,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, @@ -25,20 +25,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 @@ -52,30 +51,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) @@ -89,5 +88,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 f68d68970..7b96d646a 100644 --- a/src/include/stir/numerics/integrate_discrete_function.h +++ b/src/include/stir/numerics/integrate_discrete_function.h @@ -14,7 +14,7 @@ \brief Declaration of stir::integrate_discrete_function function \author Charalampos Tsoumpas - + */ #ifndef __stir_integrate_discrete_function_H__ @@ -22,9 +22,9 @@ #include "stir/common.h" #include -#include +#include #include -#include +#include #include START_NAMESPACE_STIR @@ -41,8 +41,9 @@ 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 f3857aa33..7bdab6ab8 100644 --- a/src/include/stir/numerics/integrate_discrete_function.inl +++ b/src/include/stir/numerics/integrate_discrete_function.inl @@ -22,34 +22,34 @@ START_NAMESPACE_STIR template -elemT -integrate_discrete_function(const std::vector& t , const std::vector& f , const int interpolation_order ) +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()) + 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) { 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 @@ -66,22 +66,25 @@ START_NAMESPACE_STIR (e.g. with opposite sign). */ -template -inline -Succeeded +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) + 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; @@ -94,26 +97,23 @@ absolute_max_eigenvector_using_power_method(elemT& max_eigenvalue, change = norm_squared(max_eigenvector - current); current = max_eigenvector; --remaining_num_iterations; - } - while (change > tolerance_squared && remaining_num_iterations!=0); - + } 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(). @@ -121,41 +121,39 @@ 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 + */ +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) + 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) + 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"); - - 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); + " 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); 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. @@ -167,53 +165,41 @@ 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 +*/ +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) + 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); + Succeeded success + = 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 528088248..46f07346b 100644 --- a/src/include/stir/numerics/norm.h +++ b/src/include/stir/numerics/norm.h @@ -12,26 +12,29 @@ #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 @@ -41,52 +44,55 @@ 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. -*/ +*/ // specialisations for complex numbers are in .inl file for clarity of this file. template struct NormSquared { - double operator()(T x) const - { - return static_cast(x)*x; - } + 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 @@ -95,26 +101,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 317856ae7..187daa589 100644 --- a/src/include/stir/numerics/norm.inl +++ b/src/include/stir/numerics/norm.inl @@ -10,61 +10,61 @@ */ /*! - \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 - template -struct NormSquared > +struct NormSquared> { - double operator()(const std::complex& x) const - { return square(x.real())+ square(x.imag()); } + double operator()(const std::complex& x) const { return square(x.real()) + square(x.imag()); } }; 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 518305796..8cbb34edf 100644 --- a/src/include/stir/numerics/overlap_interpolate.h +++ b/src/include/stir/numerics/overlap_interpolate.h @@ -21,32 +21,31 @@ */ #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. @@ -56,13 +55,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). @@ -70,9 +69,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: @@ -96,12 +95,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 @@ -109,7 +108,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).
          @@ -120,15 +119,17 @@ 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 dbf9cc14e..409dcc83b 100644 --- a/src/include/stir/numerics/overlap_interpolate.inl +++ b/src/include/stir/numerics/overlap_interpolate.inl @@ -19,15 +19,18 @@ #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) @@ -38,8 +41,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; @@ -48,40 +51,40 @@ 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) + 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; + ++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) + 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; + *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. @@ -90,67 +93,66 @@ void 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); + 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); #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); + 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; - } + { + 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; - } + { + 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; - } + { + ++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; - } + { + ++in_coord_iter; + ++in_iter; + if (in_iter == in_end) + break; + } } // end of while - assert(in_coord_iter+1 == in_coord_end); + 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; + { + ++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); } } diff --git a/src/include/stir/numerics/sampling_functions.h b/src/include/stir/numerics/sampling_functions.h index 05b78588e..6b619a023 100644 --- a/src/include/stir/numerics/sampling_functions.h +++ b/src/include/stir/numerics/sampling_functions.h @@ -10,7 +10,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics \brief Sampling functions (currently only stir::sample_function_on_regular_grid) @@ -29,11 +29,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 @@ -44,11 +44,10 @@ 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); /*! \brief Generic function to get the values of a 3D function on a grid @@ -56,7 +55,8 @@ void sample_function_on_regular_grid(Array<3,elemT>& out, \param[in,out] out array that will be filled with the function values. Its dimensions are used to find the coordinates where to sample the function (see below). \param[in] func function to sample - \param[in] index_converter a lambda function converting indices in the out array to coordinates where the function shall be sampled + \param[in] index_converter a lambda function converting indices in the out array to coordinates where the function shall be + sampled \par requirement for type FunctionType Due to the calling sequence above, the following has to be defined @@ -67,8 +67,7 @@ void sample_function_on_regular_grid(Array<3,elemT>& out, \todo At the moment, only the 3D version is implemented, but this could be templated. */ template -inline -void sample_function_using_index_converter(Array<3,elemT>& out, FunctionType func, Lambda&& index_converter); +inline void sample_function_using_index_converter(Array<3, elemT>& out, FunctionType func, Lambda&& index_converter); END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index adc586a35..62712d997 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -6,7 +6,7 @@ Copyright 2023, Positrigo AG, Zurich This file is part of STIR. SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details */ /*! @@ -21,62 +21,61 @@ 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) +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)) + 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]) + 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[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) ; - } - } + 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); + } + } } template -void sample_function_using_index_converter(Array<3,elemT>& out, FunctionType func, Lambda&& index_converter) +void +sample_function_using_index_converter(Array<3, elemT>& out, FunctionType func, Lambda&& index_converter) { - BasicCoordinate<3,int> min_out, max_out; + 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)) + if (!out_range.get_regular_range(min_out, max_out)) warning("Output must be regular range!"); BasicCoordinate<3, int> index_out; for (index_out[1] = min_out[1]; index_out[1] <= max_out[1]; ++index_out[1]) - { - for (index_out[2] = min_out[2]; index_out[2] <= max_out[2]; ++index_out[2]) { - for (index_out[3] = min_out[3]; index_out[3] <= max_out[3]; ++index_out[3]) - { - auto index_in = index_converter(index_out); - out[index_out] = func(index_in); - } + for (index_out[2] = min_out[2]; index_out[2] <= max_out[2]; ++index_out[2]) + { + for (index_out[3] = min_out[3]; index_out[3] <= max_out[3]; ++index_out[3]) + { + auto index_in = index_converter(index_out); + out[index_out] = func(index_in); + } + } } - } } END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/stir_NumericalRecipes.h b/src/include/stir/numerics/stir_NumericalRecipes.h index b243be4c6..044b91d87 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. @@ -32,26 +32,25 @@ START_NAMESPACE_STIR */ //@{ -inline void stir_to_nr(const VectorWithOffset< std::complex >& c, - VectorWithOffset& nr_data) +inline void +stir_to_nr(const VectorWithOffset>& c, VectorWithOffset& nr_data) { - for (int i=0; i >& 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()) + Array<2, std::complex>::const_full_iterator iter = c2d.begin_all(); + + while (iter != c2d.end_all()) { *nr_iter++ = iter->real(); *nr_iter++ = iter->imag(); @@ -59,19 +58,17 @@ inline void stir_to_nr(const Array<2,std::complex >& c2d, } } - -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()) + 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()) + 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(); @@ -81,42 +78,40 @@ inline void stir_to_nr(const VectorWithOffset > >& c } } -void nr_to_stir(const VectorWithOffset& nr_data, - VectorWithOffset< std::complex >& c) +void +nr_to_stir(const VectorWithOffset& nr_data, VectorWithOffset>& c) { - for (int i=0; i(nr_data[2*i+1], nr_data[2*i+2]); - } + 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()) + 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 = 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()) + VectorWithOffset>>::iterator iter = c2d.begin(); + while (iter != c2d.end()) { - Array<1,std::complex >::iterator row_iter = iter->begin(); - while(row_iter != iter->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 = std::complex(*nr_iter, *(nr_iter + 1)); + nr_iter += 2; ++row_iter; } ++iter; diff --git a/src/include/stir/recon_array_functions.h b/src/include/stir/recon_array_functions.h index 98105a0ad..1fda9be24 100644 --- a/src/include/stir/recon_array_functions.h +++ b/src/include/stir/recon_array_functions.h @@ -14,9 +14,9 @@ #define __stir_recon_array_functions_h_ /*! - \file + \file \ingroup buildblock - + \brief a variety of useful functions \author Matthew Jacobson @@ -29,15 +29,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 @@ -47,9 +50,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 -// gives 1 if negative, 0 otherwise -//float neg_indicate(float x){return (x<=0.0)?1.0:0.0;} +// MJ 17/05/2000 disabled +// gives 1 if negative, 0 otherwise +// 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 @@ -66,21 +69,25 @@ 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); +void divide_and_truncate(RelatedViewgrams& numerator, + const RelatedViewgrams& denominator, + 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); @@ -89,23 +96,21 @@ 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 dd9122fcf..38ad4ba1c 100644 --- a/src/include/stir/recon_buildblock/AnalyticReconstruction.h +++ b/src/include/stir/recon_buildblock/AnalyticReconstruction.h @@ -2,20 +2,20 @@ // /* 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 part of STIR. + SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license - + 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 @@ -35,7 +35,6 @@ START_NAMESPACE_STIR - class Succeeded; /*! @@ -48,28 +47,26 @@ 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. */ - Succeeded - reconstruct() override; + Succeeded reconstruct() override; //! executes the reconstruction storing result in \c target_image_sptr /*! @@ -79,11 +76,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. - */ - Succeeded - reconstruct(shared_ptr const& target_image_sptr) override; + */ + Succeeded reconstruct(shared_ptr const& target_image_sptr) override; void set_input_data(const shared_ptr&) override; const ProjData& get_input_data() const override; @@ -101,8 +97,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 @@ -117,28 +112,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... - bool post_processing() override; + bool post_processing() override; void set_defaults() override; void initialise_keymap() override; - - }; END_NAMESPACE_STIR - #endif - diff --git a/src/include/stir/recon_buildblock/BackProjectorByBin.h b/src/include/stir/recon_buildblock/BackProjectorByBin.h index 25dd7d0db..650f626a5 100644 --- a/src/include/stir/recon_buildblock/BackProjectorByBin.h +++ b/src/include/stir/recon_buildblock/BackProjectorByBin.h @@ -33,115 +33,116 @@ 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(); ~BackProjectorByBin() override; //! 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 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. */ + virtual void back_project(const ProjData&, int subset_num = 0, int num_subsets = 1); - /*! \brief projects the specified range of the viewgrams, axial positions and tangential positions into the volume + /*! \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&, - 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 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(); + void back_project(const RelatedViewgrams&); - /*! \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 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 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 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); virtual BackProjectorByBin* clone() const = 0; protected: - /*! \brief This actually does the back projection. There are two versions of this code to enable backwards compatibility. @@ -151,10 +152,12 @@ 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>&, + 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); + 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. @@ -165,9 +168,11 @@ 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. @@ -182,30 +187,28 @@ void back_project(const RelatedViewgrams&, Calls check(const ProjDataInfo&) */ - 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; void set_defaults() override; void initialise_keymap() override; - protected: +protected: //! ProjDataInfo set by set_up() shared_ptr _proj_data_info_sptr; - private: - +private: #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 bc43a1bf9..8e943bedb 100644 --- a/src/include/stir/recon_buildblock/BackProjectorByBinUsingInterpolation.h +++ b/src/include/stir/recon_buildblock/BackProjectorByBinUsingInterpolation.h @@ -23,26 +23,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 @@ -51,8 +55,7 @@ class DataSymmetriesForBins_PET_CartesianGrid; \endcode */ - -class JacobianForIntBP +class JacobianForIntBP { private: // store some scanner related data to avoid recomputation @@ -69,19 +72,18 @@ 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 @@ -95,13 +97,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 @@ -110,7 +112,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 @@ -121,51 +123,46 @@ 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. - */ - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; + */ + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; /*! \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 override; - /*! - \brief Use this to switch between the exact Jacobian and + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const override; + /*! + \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. @@ -175,11 +172,10 @@ class BackProjectorByBinUsingInterpolation : BackProjectorByBinUsingInterpolation* clone() const override; 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; @@ -217,44 +213,46 @@ 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) override; - - 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); + 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) override; + + 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); @@ -262,47 +260,61 @@ 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 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 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 backproj2D_Cho_view_viewplus90( PETPlane & image, @@ -316,11 +328,8 @@ static void backproj2D_Cho_view_viewplus90( PETPlane & image, */ void set_defaults() override; void initialise_keymap() override; - }; 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 1457f1ca5..976147f4f 100644 --- a/src/include/stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h +++ b/src/include/stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h @@ -31,59 +31,53 @@ //#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. - */ - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; - - const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const override; + */ + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const override; - 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) override; + 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) override; - - shared_ptr & - get_proj_matrix_sptr(){ return proj_matrix_ptr ;} + shared_ptr& get_proj_matrix_sptr() { return proj_matrix_ptr; } BackProjectorByBinUsingProjMatrixByBin* clone() const override; - -protected: +protected: shared_ptr proj_matrix_ptr; // currently not exposed, but leaving this ine for the future - void actual_back_project(DiscretisedDensity<3,float>& image, - const Bin& bin); + void actual_back_project(DiscretisedDensity<3, float>& image, const Bin& bin); private: void set_defaults() override; @@ -91,13 +85,8 @@ class BackProjectorByBinUsingProjMatrixByBin: bool post_processing() override; }; - - - 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 718170c62..23c067646 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,7 +9,7 @@ \file - \brief + \brief \author Kris Thielemans */ @@ -28,66 +27,54 @@ //#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 override; - - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; + BackProjectorByBinUsingSquareProjMatrixByBin(const shared_ptr& proj_matrix_ptr); + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const override; - 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) override; + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; + 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) override; - shared_ptr & - get_proj_matrix_sptr(){ return proj_matrix_ptr ;} - - protected: + shared_ptr& get_proj_matrix_sptr() { return proj_matrix_ptr; } +protected: shared_ptr proj_matrix_ptr; - void actual_back_project(DiscretisedDensity<3,float>& image, - const Bin& bin); + void actual_back_project(DiscretisedDensity<3, float>& image, const Bin& bin); private: void set_defaults() override; void initialise_keymap() override; }; - - - 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 efb4a14c2..cb8458ed9 100644 --- a/src/include/stir/recon_buildblock/BinNormalisation.h +++ b/src/include/stir/recon_buildblock/BinNormalisation.h @@ -21,7 +21,6 @@ #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" @@ -29,7 +28,8 @@ START_NAMESPACE_STIR -template class RelatedViewgrams; +template +class RelatedViewgrams; class Succeeded; class ProjDataInfo; class ProjData; @@ -39,49 +39,48 @@ 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 { public: - BinNormalisation(); ~BinNormalisation() override; /*! sets \c _already_setup to \c false */ void set_defaults() override; - 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 sets _already_set_up and stores the shared pointers. */ - 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 =0; + virtual float get_bin_efficiency(const Bin& bin) 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() @@ -90,58 +89,58 @@ class BinNormalisation : public RegisteredObject virtual void apply(RelatedViewgrams&) 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; + virtual void undo(RelatedViewgrams&) 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&, - shared_ptr = shared_ptr()) const; - + void undo(ProjData&, 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; shared_ptr proj_data_info_sptr; + private: shared_ptr exam_info_sptr; }; diff --git a/src/include/stir/recon_buildblock/BinNormalisationFromAttenuationImage.h b/src/include/stir/recon_buildblock/BinNormalisationFromAttenuationImage.h index d3a172cb3..22ea0ac35 100644 --- a/src/include/stir/recon_buildblock/BinNormalisationFromAttenuationImage.h +++ b/src/include/stir/recon_buildblock/BinNormalisationFromAttenuationImage.h @@ -35,14 +35,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 @@ -53,18 +53,19 @@ START_NAMESPACE_STIR End Bin Normalisation From Attenuation Image := \endverbatim */ -class BinNormalisationFromAttenuationImage : - public RegisteredParsingObject +class BinNormalisationFromAttenuationImage + : public RegisteredParsingObject { private: using base_type = BinNormalisation; + 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. */ @@ -72,41 +73,42 @@ 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(). */ - Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr& ) override; + Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&) override; using base_type::apply; //! 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. */ void apply(RelatedViewgrams& viewgrams) const override; //! 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. */ - + void undo(RelatedViewgrams& viewgrams) const override; - float get_bin_efficiency(const Bin& bin) const override; + float get_bin_efficiency(const Bin& bin) const override; private: - shared_ptr > attenuation_image_ptr; + shared_ptr> attenuation_image_ptr; shared_ptr forward_projector_ptr; // parsing stuff @@ -117,7 +119,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 385c20228..5be9d310c 100644 --- a/src/include/stir/recon_buildblock/BinNormalisationFromECAT7.h +++ b/src/include/stir/recon_buildblock/BinNormalisationFromECAT7.h @@ -33,7 +33,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 @@ -67,23 +67,24 @@ START_NAMESPACE_ECAT7 ; use_crystal_interference_factors:=1 End Bin Normalisation From ECAT7:= \endverbatim - + \par Warning dead-time code might currently give wrong results due to uncertainty in units for singles rates */ -class BinNormalisationFromECAT7 : - public RegisteredParsingObject +class BinNormalisationFromECAT7 + : public RegisteredParsingObject { private: using base_type = BinNormalisationWithCalibration; + 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. */ @@ -92,7 +93,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&) override; + virtual Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&) override; float get_uncalibrated_bin_efficiency(const Bin& bin) const override; bool use_detector_efficiencies() const; @@ -101,19 +102,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; @@ -125,8 +126,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() override; diff --git a/src/include/stir/recon_buildblock/BinNormalisationFromECAT8.h b/src/include/stir/recon_buildblock/BinNormalisationFromECAT8.h index c2445c905..0a9715f2e 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, 2020, 2023 University College London - Largely a copy of the ECAT7 version. + Largely a copy of the ECAT7 version. SPDX-License-Identifier: Apache-2.0 @@ -17,7 +17,6 @@ \author Kris Thielemans */ - #ifndef __stir_recon_buildblock_BinNormalisationFromECAT8_H__ #define __stir_recon_buildblock_BinNormalisationFromECAT8_H__ @@ -83,20 +82,21 @@ START_NAMESPACE_ECAT \todo dead-time is not yet implemented - + */ -class BinNormalisationFromECAT8 : - public RegisteredParsingObject +class BinNormalisationFromECAT8 + : public RegisteredParsingObject { private: using base_type = BinNormalisationWithCalibration; + 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. */ @@ -105,7 +105,7 @@ class BinNormalisationFromECAT8 : //! Constructor that reads the projdata from a file BinNormalisationFromECAT8(const string& filename); - Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr& ) override; + Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&) override; float get_uncalibrated_bin_efficiency(const Bin& bin) const override; bool use_detector_efficiencies() const; @@ -114,17 +114,17 @@ class BinNormalisationFromECAT8 : bool use_crystal_interference_factors() const; bool use_axial_effects_factors() const; - private: - Array<1,float> axial_t1_array; - Array<1,float> axial_t2_array; - Array<1,float> trans_t1_array; +private: + 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<1,float> axial_effects; + Array<2, float> geometric_factors; + Array<2, float> efficiency_factors; + Array<2, float> crystal_interference_factors; + Array<1, float> axial_effects; //! lookup table from STIR ring-pair to a Siemens sinogram-index - Array<2,int> sino_index; + Array<2, int> sino_index; //! number of sinograms in Siemens sinogram (span=11?) int num_Siemens_sinograms; @@ -134,7 +134,7 @@ class BinNormalisationFromECAT8 : int num_axial_blocks_per_singles_unit; shared_ptr proj_data_info_ptr; shared_ptr norm_proj_data_info_sptr; - ProjDataInfoCylindricalNoArcCorr const * proj_data_info_cyl_ptr; + ProjDataInfoCylindricalNoArcCorr const* proj_data_info_cyl_ptr; shared_ptr proj_data_info_cyl_uncompressed_ptr; int mash; int num_blocks_per_singles_unit; @@ -149,8 +149,7 @@ class BinNormalisationFromECAT8 : bool _write_components_to_file; 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; //! initialise sino_index and num_Siemens_sinograms void construct_sino_lookup_table(); diff --git a/src/include/stir/recon_buildblock/BinNormalisationFromGEHDF5.h b/src/include/stir/recon_buildblock/BinNormalisationFromGEHDF5.h index 365079fce..5b6a2f180 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. SPDX-License-Identifier: Apache-2.0 @@ -19,7 +19,6 @@ \author Palak Wadhwa */ - #ifndef __stir_recon_buildblock_BinNormalisationFromGEHDF5_H__ #define __stir_recon_buildblock_BinNormalisationFromGEHDF5_H__ @@ -41,8 +40,10 @@ START_NAMESPACE_STIR class ProjDataInMemory; -namespace GE { -namespace RDF_HDF5 { +namespace GE +{ +namespace RDF_HDF5 +{ /*! \ingroup recon_buildblock @@ -67,20 +68,21 @@ namespace RDF_HDF5 { \todo dead-time is not yet implemented - + */ -class BinNormalisationFromGEHDF5 : - public RegisteredParsingObject +class BinNormalisationFromGEHDF5 + : public RegisteredParsingObject { private: using base_type = BinNormalisationWithCalibration; + 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. */ @@ -89,8 +91,7 @@ class BinNormalisationFromGEHDF5 : //! Constructor that reads the projdata from a file BinNormalisationFromGEHDF5(const string& filename); - - Succeeded set_up(const shared_ptr &exam_info_sptr, const shared_ptr&) override; + Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&) override; float get_uncalibrated_bin_efficiency(const Bin& bin) const override; bool use_detector_efficiencies() const; @@ -99,18 +100,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; @@ -121,11 +122,12 @@ 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 void set_defaults() override; void initialise_keymap() override; @@ -136,8 +138,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 42444f6d6..f8844258f 100644 --- a/src/include/stir/recon_buildblock/BinNormalisationFromProjData.h +++ b/src/include/stir/recon_buildblock/BinNormalisationFromProjData.h @@ -34,7 +34,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 @@ -44,18 +44,18 @@ START_NAMESPACE_STIR End Bin Normalisation From ProjData:= \endverbatim */ -class BinNormalisationFromProjData : - public RegisteredParsingObject +class BinNormalisationFromProjData : public RegisteredParsingObject { private: using base_type = BinNormalisation; + 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. */ @@ -69,7 +69,7 @@ class BinNormalisationFromProjData : BinNormalisationFromProjData(const shared_ptr& norm_proj_data_ptr); //! check if we could be multiplying with 1 (i.e. do nothing) - /*! + /*! always return \c false, as the case where the whole ProjData is set to 1 will never occur in "real life", so we save ourselves some time/complications by returning \c false @@ -77,30 +77,30 @@ class BinNormalisationFromProjData : bool is_trivial() const override; //! 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. */ - Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr& ) override; + Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&) override; //! 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. */ - + void apply(RelatedViewgrams& viewgrams) const override; //! 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. */ void undo(RelatedViewgrams& viewgrams) const override; float get_bin_efficiency(const Bin& bin) const override; - - //! Get a shared_ptr to the normalisation proj_data. + + //! 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; void set_defaults() override; @@ -110,7 +110,6 @@ class BinNormalisationFromProjData : std::string normalisation_projdata_filename; }; - END_NAMESPACE_STIR #endif diff --git a/src/include/stir/recon_buildblock/BinNormalisationPETFromComponents.h b/src/include/stir/recon_buildblock/BinNormalisationPETFromComponents.h index 70ffb200a..329a1ef05 100644 --- a/src/include/stir/recon_buildblock/BinNormalisationPETFromComponents.h +++ b/src/include/stir/recon_buildblock/BinNormalisationPETFromComponents.h @@ -49,10 +49,10 @@ START_NAMESPACE_STIR
      Niknejad, T., Tavernier, S., Varela, J. and Thielemans, K. Validation of 3D model-based maximum-likelihood estimation of normalisation factors for partial ring positron emission - tomography. + tomography
      . in 2016 IEEE Nuclear Science Symposium, Medical Imaging Conference and Room-Temperature Semiconductor Detector Workshop (NSS/MIC/RTSD) 1-5 (2016). doi:10.1109/NSSMIC.2016.8069577. -
      +
      Note however that this describes rotational/translational symmetry per block, while the default is now to use symmetries per bucket ( see the \c do_symmetry_per_block argument of allocate()). (The block factors still work per block, not bucket). @@ -121,12 +121,21 @@ class BinNormalisationPETFromComponents : public BinNormalisation //! Allocate the relevant factors /*! They are currently probably set to 0, but do not rely on this. */ - void allocate(shared_ptr, bool do_eff, bool do_geo, bool do_block = false, - bool do_symmetry_per_block = false); - - DetectorEfficiencies& crystal_efficiencies() { return efficiencies; } - GeoData3D& geometric_factors() { return geo_data; } - BlockData3D& block_factors() { return block_data; } + void + allocate(shared_ptr, bool do_eff, bool do_geo, bool do_block = false, bool do_symmetry_per_block = false); + + DetectorEfficiencies& crystal_efficiencies() + { + return efficiencies; + } + GeoData3D& geometric_factors() + { + return geo_data; + } + BlockData3D& block_factors() + { + return block_data; + } //! Sets all factors to empty and flags that allocations need to be done /*! Also calls base_type::set_defaults() */ diff --git a/src/include/stir/recon_buildblock/BinNormalisationSPECT.h b/src/include/stir/recon_buildblock/BinNormalisationSPECT.h index 0a368bd50..8c89af475 100644 --- a/src/include/stir/recon_buildblock/BinNormalisationSPECT.h +++ b/src/include/stir/recon_buildblock/BinNormalisationSPECT.h @@ -29,41 +29,34 @@ START_NAMESPACE_STIR -class BinNormalisationSPECT : - public RegisteredParsingObject +class BinNormalisationSPECT + : public RegisteredParsingObject { private: using base_type = BinNormalisationWithCalibration; -public: - +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); - Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr& ) override; - 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; - } - + Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&) override; + void set_num_views(int num_views) const { this->num_views = num_views; } - 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; + void set_uniformity(Array<3, float>& uniformity) { this->down_sampled_uniformity = uniformity; } - float get_dead_time_efficiency (const DetectionPosition<>& det_pos, - const double start_time, - const double end_time) 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; void apply(RelatedViewgrams& viewgrams) const override; @@ -71,14 +64,14 @@ class BinNormalisationSPECT : float get_uncalibrated_bin_efficiency(const Bin& bin) const override; - 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 @@ -88,11 +81,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; @@ -112,4 +105,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 9e9e65243..737e938d3 100644 --- a/src/include/stir/recon_buildblock/BinNormalisationWithCalibration.h +++ b/src/include/stir/recon_buildblock/BinNormalisationWithCalibration.h @@ -22,7 +22,6 @@ #ifndef __stir_recon_buildblock_BinNormalisationWithCalibration_H__ #define __stir_recon_buildblock_BinNormalisationWithCalibration_H__ - #include "stir/RegisteredParsingObject.h" #include "stir/Bin.h" #include "stir/Radionuclide.h" @@ -36,50 +35,49 @@ START_NAMESPACE_STIR \ingroup normalisation This class provides the facility to use a calibration factor and (isotope) 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 the calibration factor. The branching ratio is obtained from the radionuclide set in \c ExamInfo (passed by set_up()). */ -class BinNormalisationWithCalibration : - public BinNormalisation +class BinNormalisationWithCalibration : public BinNormalisation { private: using base_type = BinNormalisation; + public: - - BinNormalisationWithCalibration(); //! initialises the object and checks if it can handle such projection data /*! Computes internal numbers related to calibration etc. */ - Succeeded set_up(const shared_ptr& exam_info_sptr,const shared_ptr&) override; + Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&) override; //! product of calibration factor etc float get_calib_decay_branching_ratio_factor(const Bin&) const; // TODO find a better name float get_calibration_factor() const override; float get_branching_ratio() const; - + void set_calibration_factor(const float); void set_radionuclide(const Radionuclide&); - + // needs to be implemented by derived class - virtual float get_uncalibrated_bin_efficiency(const Bin&) const = 0; + virtual float get_uncalibrated_bin_efficiency(const Bin&) const = 0; //! return efficiency for 1 bin /*! returns get_uncalibrated_bin_efficiency(bin)/get_calib_decay_branching_ratio_factor(bin) */ float get_bin_efficiency(const Bin& bin) const final - { return this->get_uncalibrated_bin_efficiency(bin)/this->_calib_decay_branching_ratio; } - - protected: + { + return this->get_uncalibrated_bin_efficiency(bin) / this->_calib_decay_branching_ratio; + } + +protected: // parsing stuff void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - private: // provide facility to switch off things? // need to be added to the parsing keywords -// bool use_calibration_factor; // default to true + // bool use_calibration_factor; // default to true float calibration_factor; Radionuclide radionuclide; //! product of various factors diff --git a/src/include/stir/recon_buildblock/ChainedBinNormalisation.h b/src/include/stir/recon_buildblock/ChainedBinNormalisation.h index e2584ec76..0ecf59cce 100644 --- a/src/include/stir/recon_buildblock/ChainedBinNormalisation.h +++ b/src/include/stir/recon_buildblock/ChainedBinNormalisation.h @@ -30,7 +30,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. @@ -46,7 +46,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. @@ -56,7 +56,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 @@ -67,32 +67,31 @@ START_NAMESPACE_STIR END Chained Bin Normalisation Parameters := \endverbatim */ -class ChainedBinNormalisation : - public RegisteredParsingObject +class ChainedBinNormalisation : public RegisteredParsingObject { private: using base_type = BinNormalisation; + 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. */ - Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr& ) override; + Succeeded set_up(const shared_ptr& exam_info_sptr, const shared_ptr&) override; //! Normalise some data - /*! + /*! This calls apply() of the 2 BinNormalisation members */ @@ -103,41 +102,42 @@ ChainedBinNormalisation(shared_ptr const& apply_first, virtual void apply_only_first(RelatedViewgrams& viewgrams) const; -virtual void apply_only_first(ProjData&) const; + virtual void apply_only_first(ProjData&) const; -virtual void apply_only_second(RelatedViewgrams& viewgrams) const; + virtual void apply_only_second(RelatedViewgrams& viewgrams) const; -virtual void apply_only_second(ProjData&) const; + virtual void apply_only_second(ProjData&) const; //! Undo the normalisation of some data - /*! - This calls undo() of the 2 BinNormalisation members. + /*! + This calls undo() of the 2 BinNormalisation members. */ void undo(RelatedViewgrams& viewgrams) const override; #if 0 virtual void undo(ProjData&) const override; - #endif +#endif -virtual void undo_only_first(RelatedViewgrams& viewgrams) const; + virtual void undo_only_first(RelatedViewgrams& viewgrams) const; -virtual void undo_only_first(ProjData&) const; + virtual void undo_only_first(ProjData&) const; -virtual void undo_only_second(RelatedViewgrams& viewgrams) const; + virtual void undo_only_second(RelatedViewgrams& viewgrams) const; -virtual void undo_only_second(ProjData&) const; + virtual void undo_only_second(ProjData&) const; float get_bin_efficiency(const Bin& bin) const override; - - //! Returns the is_trivial() status of the first normalisation object. - //! \warning Currently, if the object has not been set the function throws an error. + + //! 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 85c49a40d..a9691f0e0 100644 --- a/src/include/stir/recon_buildblock/DataSymmetriesForBins.h +++ b/src/include/stir/recon_buildblock/DataSymmetriesForBins.h @@ -39,12 +39,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. @@ -52,18 +51,17 @@ 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 @@ -77,8 +75,7 @@ class DataSymmetriesForBins : public DataSymmetriesForViewSegmentNumbers ~DataSymmetriesForBins() override; - - DataSymmetriesForBins * clone() const override = 0; + DataSymmetriesForBins* clone() const override = 0; #if 0 TODO! @@ -88,94 +85,89 @@ 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 int min_timing_pos_num, const int max_timing_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, + const int max_timing_pos_num) 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 - bool blindly_equals(const root_type * const) const override = 0; + bool blindly_equals(const root_type* const) const override = 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 b90bb877a..212819367 100644 --- a/src/include/stir/recon_buildblock/DataSymmetriesForBins.inl +++ b/src/include/stir/recon_buildblock/DataSymmetriesForBins.inl @@ -26,28 +26,27 @@ START_NAMESPACE_STIR void -DataSymmetriesForBins:: -get_related_bins(std::vector& rel_b, const Bin& b) const +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()), + 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_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()); + proj_data_info_ptr->get_max_tof_pos_num()); } - void -DataSymmetriesForBins:: -get_related_bins_factorised(std::vector& ax_tang_poss, const Bin& b) const +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()); + 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 8298d7c67..8738b16b9 100644 --- a/src/include/stir/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.h +++ b/src/include/stir/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.h @@ -23,7 +23,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" @@ -33,13 +32,15 @@ START_NAMESPACE_STIR -template class DiscretisedDensity; -template class DiscretisedDensityOnCartesianGrid; +template +class DiscretisedDensity; +template +class DiscretisedDensityOnCartesianGrid; class ProjDataInfoCylindrical; /*! \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 @@ -52,7 +53,6 @@ class DataSymmetriesForBins_PET_CartesianGrid : public DataSymmetriesForBins 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}. @@ -63,10 +63,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
  • @@ -80,23 +80,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); - - #ifndef STIR_NO_COVARIANT_RETURN_TYPES - DataSymmetriesForBins_PET_CartesianGrid + DataSymmetriesForBins_PET_CartesianGrid #else - DataSymmetriesForViewSegmentNumbers + DataSymmetriesForViewSegmentNumbers #endif - * clone() const override; + * + clone() const override; //! Check equality virtual bool operator==(const DataSymmetriesForBins_PET_CartesianGrid&) const; @@ -108,38 +107,33 @@ 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 override; + 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 override; - inline int - num_related_bins(const Bin& b) const override; + inline int num_related_bins(const Bin& b) const override; - inline unique_ptr - find_symmetry_operation_from_basic_bin(Bin&) const override; + inline unique_ptr find_symmetry_operation_from_basic_bin(Bin&) const override; - inline bool - find_basic_bin(Bin& b) const override; - - inline int - num_related_view_segment_numbers(const ViewSegmentNumbers& vs) const override; - - inline void - get_related_view_segment_numbers(std::vector& rel_vs, const ViewSegmentNumbers& vs) const override; - - inline bool - find_basic_view_segment_numbers(ViewSegmentNumbers& v_s) const override; + inline bool find_basic_bin(Bin& b) const override; - //! 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_view_segment_numbers(const ViewSegmentNumbers& vs) const override; + inline void get_related_view_segment_numbers(std::vector& rel_vs, + const ViewSegmentNumbers& vs) const override; + inline bool find_basic_view_segment_numbers(ViewSegmentNumbers& v_s) const override; + + //! 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; @@ -148,15 +142,25 @@ 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; } + { + return do_symmetry_90degrees_min_phi; + } inline bool using_symmetry_180degrees_min_phi() const - { return do_symmetry_180degrees_min_phi; } + { + return do_symmetry_180degrees_min_phi; + } inline bool using_symmetry_swap_segment() const - { return do_symmetry_swap_segment; } + { + return do_symmetry_swap_segment; + } inline bool using_symmetry_swap_s() const - { return do_symmetry_swap_s; } + { + return do_symmetry_swap_s; + } inline bool using_symmetry_shift_z() const - { return do_symmetry_shift_z; } + { + return do_symmetry_shift_z; + } //@} private: @@ -165,7 +169,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 @@ -188,30 +192,16 @@ class DataSymmetriesForBins_PET_CartesianGrid : public DataSymmetriesForBins cartesian_grid_info_ptr() const; #endif - bool blindly_equals(const root_type * const) const override; - + bool blindly_equals(const root_type* const) const override; inline bool - find_basic_bin(int &segment_num, int &view_num, int &axial_pos_num, int &tangential_pos_num, int &timing_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; - + find_basic_bin(int& segment_num, int& view_num, int& axial_pos_num, int& tangential_pos_num, int& timing_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 13550a5df..16f92a2e7 100644 --- a/src/include/stir/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.inl +++ b/src/include/stir/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.inl @@ -46,837 +46,803 @@ 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 +DataSymmetriesForBins_PET_CartesianGrid::find_transform_z(const int segment_num, const int axial_pos_num) const { const float delta = this->deltas[segment_num]; int transform_z; - //cylindrical implementaion - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="Cylindrical") - { - - - // 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]); - // now use rounding to be safe - transform_z = (int)floor(transform_z_float + 0.5); - assert(fabs(transform_z-transform_z_float) < 10E-4); + // cylindrical implementaion + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "Cylindrical") + { - } - } - //block implementaion - else if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="BlocksOnCylindrical") + // 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 { - - // 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]); + // now use rounding to be safe + transform_z = (int)floor(transform_z_float + 0.5); + assert(fabs(transform_z - transform_z_float) < 10E-4); + } + } + // block implementaion + else if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "BlocksOnCylindrical") { - // 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]); - // now use rounding to be safe - transform_z = (int)floor(transform_z_float + 0.5); - assert(fabs(transform_z-transform_z_float) < 10E-4); - } + // 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]); + // now use rounding to be safe + transform_z = (int)floor(transform_z_float + 0.5); + assert(fabs(transform_z - transform_z_float) < 10E-4); } - // generic implementation - else + } + // generic implementation + else { - // 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]); - // 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); - - return transform_z; - } + // 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]); + // 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); + + return transform_z; + } } - return transform_z; + 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 { - //cylindrical implementaion - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="Cylindrical") + // cylindrical implementaion + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "Cylindrical") { - // 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); + // 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); - // If doing z shifts, set the axial_pos_shift to axial_pos_num, else, set to 0 - const int axial_pos_shift = do_symmetry_shift_z ? axial_pos_num : 0; + // If doing z shifts, set the axial_pos_shift to axial_pos_num, else, set to 0 + const int axial_pos_shift = do_symmetry_shift_z ? axial_pos_num : 0; - const int z_shift = - do_symmetry_shift_z ? - num_planes_per_axial_pos[segment_num]*axial_pos_num - : 0; - - const int view180 = num_views; + 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); #ifndef NDEBUG - // 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; + // 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; #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_shift, z_shift); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq(view180, axial_pos_shift, 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_shift, z_shift, transform_z); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xy_yx(view180, axial_pos_shift, 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_shift, z_shift, transform_z); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xmx(view180, axial_pos_shift, 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_shift, z_shift, transform_z); - else - { - if (z_shift==0) - return new TrivialSymmetryOperation(); + 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_shift, z_shift); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq( + view180, axial_pos_shift, 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_shift, z_shift, transform_z); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xy_yx( + view180, axial_pos_shift, 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_shift, z_shift, transform_z); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xmx(view180, axial_pos_shift, z_shift); // seg < 0 + } else - return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_shift, z_shift); - } - } + { + 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_shift, z_shift, transform_z); + else + { + if (z_shift == 0) + return new TrivialSymmetryOperation(); + else + return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_shift, z_shift); + } + } } - //block implementaion - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="BlocksOnCylindrical") + // block implementaion + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "BlocksOnCylindrical") { - if (do_symmetry_90degrees_min_phi - || do_symmetry_swap_segment - || do_symmetry_swap_s - || do_symmetry_180degrees_min_phi) - { - warning("Currently, no symmetry is implemented for block geometry.\n"); - return new TrivialSymmetryOperation(); - } + if (do_symmetry_90degrees_min_phi || do_symmetry_swap_segment || do_symmetry_swap_s || do_symmetry_180degrees_min_phi) + { + warning("Currently, no symmetry is implemented for block geometry.\n"); + return new TrivialSymmetryOperation(); + } - if (do_symmetry_shift_z) - { - Bin basic_bin(segment_num, view_num, axial_pos_num, 0); - find_basic_bin(basic_bin); - const int z_shift = - num_planes_per_axial_pos[segment_num] - *(axial_pos_num - basic_bin.axial_pos_num()); - - if (z_shift==0) - return new TrivialSymmetryOperation(); - else - return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_num, z_shift); - } + if (do_symmetry_shift_z) + { + Bin basic_bin(segment_num, view_num, axial_pos_num, 0); + find_basic_bin(basic_bin); + const int z_shift = num_planes_per_axial_pos[segment_num] * (axial_pos_num - basic_bin.axial_pos_num()); - if (!do_symmetry_90degrees_min_phi - && !do_symmetry_swap_segment - && !do_symmetry_swap_s - && !do_symmetry_180degrees_min_phi - && !do_symmetry_shift_z) - { - return new TrivialSymmetryOperation(); - } + if (z_shift == 0) + return new TrivialSymmetryOperation(); + else + return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_num, z_shift); + } + if (!do_symmetry_90degrees_min_phi && !do_symmetry_swap_segment && !do_symmetry_swap_s && !do_symmetry_180degrees_min_phi + && !do_symmetry_shift_z) + { + return new TrivialSymmetryOperation(); + } } - if(proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="Generic") + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "Generic") { - // No symmetry is implemented for generic scanner - return new TrivialSymmetryOperation(); + // No symmetry is implemented for generic scanner + return new TrivialSymmetryOperation(); } } // 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 { - //cylindrical implementaion - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="Cylindrical") - { - // 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); - - // If doing z shifts, set the axial_pos_shift to axial_pos_num, else, set to 0 - const int axial_pos_shift = do_symmetry_shift_z ? axial_pos_num : 0; - - 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_numget_scanner_ptr()->get_scanner_geometry() == "Cylindrical") + { + // 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); + + // If doing z shifts, set the axial_pos_shift to axial_pos_num, else, set to 0 + const int axial_pos_shift = do_symmetry_shift_z ? axial_pos_num : 0; + + 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 < num_views); + + const int view180 = num_views; #ifndef NDEBUG - // 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; + // 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; #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_shift, z_shift); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq(view180, axial_pos_shift, 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_shift, z_shift, transform_z); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xy_ymx(view180, axial_pos_shift, z_shift); - } - else { // segment_num == 0 - if ( !do_symmetry_swap_s || s > 0 ) - return new SymmetryOperation_PET_CartesianGrid_swap_xmy_yx(view180, axial_pos_shift, z_shift); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xy_ymx(view180, axial_pos_shift, 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_shift, z_shift, transform_z); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx(view180, axial_pos_shift, 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_shift, z_shift); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq( + view180, axial_pos_shift, 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_shift, z_shift, transform_z); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xy_ymx(view180, axial_pos_shift, z_shift); + } + else + { // segment_num == 0 + if (!do_symmetry_swap_s || s > 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xmy_yx(view180, axial_pos_shift, z_shift); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xy_ymx(view180, axial_pos_shift, 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_shift, z_shift, transform_z); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx(view180, axial_pos_shift, 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_shift, z_shift); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq(view180, axial_pos_shift, 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_shift, z_shift); + else + return new SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx(view180, axial_pos_shift, z_shift); + } + } + 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_shift, z_shift, transform_z); + else + return new SymmetryOperation_PET_CartesianGrid_swap_ymy(view180, axial_pos_shift, 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_shift, z_shift); + else + return new SymmetryOperation_PET_CartesianGrid_swap_ymy_zq(view180, axial_pos_shift, 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_shift, 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_shift, z_shift, transform_z); + else + { + if (z_shift == 0) + return new TrivialSymmetryOperation(); + else + return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_shift, z_shift); + } + } + else if (segment_num < 0) + { + /*KT if ( s == 0) + return new SymmetryOperation_PET_CartesianGrid_swap_zq(view180, axial_pos_shift, z_shift, transform_z); + else*/ + if (do_symmetry_swap_s && s < 0) + return new SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy(view180, axial_pos_shift, z_shift); + else + return new SymmetryOperation_PET_CartesianGrid_swap_zq(view180, axial_pos_shift, 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_shift, z_shift); + else + { + if (z_shift == 0) + return new TrivialSymmetryOperation(); + else + return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_shift, 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_shift, z_shift); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq(view180, axial_pos_shift, z_shift, transform_z); - - } - else // segment_num == 0 + // block implementaion + // the implementation is as the above function for the current status of block symmetry. + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "BlocksOnCylindrical") { - if ( !do_symmetry_swap_s || s > 0 ) - return new SymmetryOperation_PET_CartesianGrid_swap_xy_yx(view180, axial_pos_shift, z_shift); - else - return new SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx(view180, axial_pos_shift, z_shift); - } - } - 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_shift, z_shift, transform_z); - else - return new SymmetryOperation_PET_CartesianGrid_swap_ymy(view180, axial_pos_shift, 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_shift, z_shift); - else - return new SymmetryOperation_PET_CartesianGrid_swap_ymy_zq(view180, axial_pos_shift, 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_shift, 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_shift, z_shift, transform_z); - else - { - if (z_shift==0) + if (do_symmetry_90degrees_min_phi || do_symmetry_swap_segment || do_symmetry_swap_s || do_symmetry_180degrees_min_phi) + { + warning("Currently, only symmetry along z is implemented for block geometry.\n"); return new TrivialSymmetryOperation(); - else - return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_shift, z_shift); - } - } - else - if ( segment_num < 0 ) - { - /*KT if ( s == 0) - return new SymmetryOperation_PET_CartesianGrid_swap_zq(view180, axial_pos_shift, z_shift, transform_z); - else*/ - if ( do_symmetry_swap_s && s < 0) - return new SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy(view180, axial_pos_shift, z_shift); - else - return new SymmetryOperation_PET_CartesianGrid_swap_zq(view180, axial_pos_shift, 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_shift, z_shift); - else + } + if (do_symmetry_shift_z) { - if (z_shift==0) + Bin basic_bin(segment_num, view_num, axial_pos_num, s); + find_basic_bin(basic_bin); + const int z_shift = num_planes_per_axial_pos[segment_num] * (axial_pos_num - basic_bin.axial_pos_num()); + + if (z_shift == 0) return new TrivialSymmetryOperation(); else - return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_shift, z_shift); + return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_num, z_shift); + } + if (!do_symmetry_90degrees_min_phi && !do_symmetry_swap_segment && !do_symmetry_swap_s && !do_symmetry_180degrees_min_phi + && !do_symmetry_shift_z) + { + return new TrivialSymmetryOperation(); } - } - } } - //block implementaion - //the implementation is as the above function for the current status of block symmetry. - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="BlocksOnCylindrical") - { - if (do_symmetry_90degrees_min_phi - || do_symmetry_swap_segment - || do_symmetry_swap_s - || do_symmetry_180degrees_min_phi) + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "Generic") { - warning("Currently, only symmetry along z is implemented for block geometry.\n"); + // No symmetry is implemented for generic scanner return new TrivialSymmetryOperation(); } - if (do_symmetry_shift_z) +} + +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) { - Bin basic_bin(segment_num, view_num, axial_pos_num, s); - find_basic_bin(basic_bin); - const int z_shift = - num_planes_per_axial_pos[segment_num] - *(axial_pos_num - basic_bin.axial_pos_num()); - - if (z_shift==0) - return new TrivialSymmetryOperation(); - else - return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_num, z_shift); + v_s.segment_num() = -v_s.segment_num(); + change = true; } - if (!do_symmetry_90degrees_min_phi - && !do_symmetry_swap_segment - && !do_symmetry_swap_s - && !do_symmetry_180degrees_min_phi - && !do_symmetry_shift_z) + + if (do_symmetry_90degrees_min_phi) { - return new TrivialSymmetryOperation(); + // 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; + } } - } - if(proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="Generic") - { - // No symmetry is implemented for generic scanner - return new TrivialSymmetryOperation(); - } - -} - -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, int &timing_pos_num) const +bool +DataSymmetriesForBins_PET_CartesianGrid::find_basic_bin( + int& segment_num, int& view_num, int& axial_pos_num, int& tangential_pos_num, int& timing_pos_num) const { - bool change=false; - //cylindrical implementaion - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="Cylindrical") + bool change = false; + // cylindrical implementaion + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "Cylindrical") { - ViewSegmentNumbers v_s(view_num, segment_num); + ViewSegmentNumbers v_s(view_num, segment_num); - change=find_basic_view_segment_numbers(v_s); + change = find_basic_view_segment_numbers(v_s); - view_num = v_s.view_num(); - segment_num = v_s.segment_num(); + view_num = v_s.view_num(); + segment_num = v_s.segment_num(); - if ( do_symmetry_swap_s && tangential_pos_num < 0) - { - //when swap_s, must invert timing pos for lor probs. Symmetry operation should correct bin - tangential_pos_num *= -1; - timing_pos_num *= -1; - change=true; - } - if ( do_symmetry_shift_z && axial_pos_num != 0 ) { axial_pos_num = 0; change = true; } - - return change; - } - - //block implementaion - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="BlocksOnCylindrical") - { - /* - ax_pos_num = (ring1 + ring2 - ax_pos_num_offset[seg_num])*num_ax_pos_per_ring_inc(seg_num)/2 - ax_pos_num_offset = num_rings - 1 - (max_ax_pos_num + min_ax_pos_num)/num_ax_pos_per_ring_inc(seg_num) - Then - ax_pos_num = (ring1 + ring2 - num_rings + 1)*ax_pos_inc/2 - (max_ax_pos_num + min_ax_pos_num)/2 - and - max_ax_pos_num + min_ax_pos_num = (num_ax_pos_per_seg -1) + 0 = num_rings - seg_num - 1 - Then - ax_pos_num = (ring1 + ring2 - num_rings + 1)*ax_pos_inc/2 - (num_rings - seg_num - 1)/2 - if ax_pos_inc == 1 - ax_pos_num = (ring1 + ring2 - seg_num)/2 - */ - const ProjDataInfoBlocksOnCylindrical* proj_data_info_blk_ptr = - static_cast(proj_data_info_ptr.get()); - if (do_symmetry_shift_z) - { - int ring1, ring2; - proj_data_info_blk_ptr->get_ring_pair_for_segment_axial_pos_num (ring1, ring2, segment_num, axial_pos_num); - //to check - //std::cout<<"before seg, ax, r1, r2 = "<get_scanner_ptr()->get_num_axial_crystals_per_block(); - int axial_blk_diff = ring2/num_axial_crys_per_block - ring1/num_axial_crys_per_block; - - if (axial_crys_diff >=0) - { // seg_num > =0 - if (axial_crys_diff%num_axial_crys_per_block == 0) - { // In this case, axial block difference can be only equal to axial_crys_diff/num_axial_crys_per_block. So we only have one type of related bins - // basic bin will be the first lor from the corresponding group - ring1= (ring1/num_axial_crys_per_block)*num_axial_crys_per_block; - ring2= ring1 + axial_crys_diff; - } - else - { /* In this case, axial block difference can be equal to axial_crys_diff/num_axial_crys_per_block - or one less. - So we can have two types of of related bins*/ - if (axial_blk_diff == axial_crys_diff/num_axial_crys_per_block) - {// basic bin will be the first lor from the corresponding group - ring1= (ring1/num_axial_crys_per_block)*num_axial_crys_per_block; - ring2= ring1 + axial_crys_diff; - } - else if (axial_blk_diff > axial_crys_diff/num_axial_crys_per_block) - {// basic bin will be the last lor from the corresponding group - ring1= (ring1/num_axial_crys_per_block)*num_axial_crys_per_block + num_axial_crys_per_block-1; - ring2= ring1 + axial_crys_diff; - } + if (do_symmetry_swap_s && tangential_pos_num < 0) + { + // when swap_s, must invert timing pos for lor probs. Symmetry operation should correct bin + tangential_pos_num *= -1; + timing_pos_num *= -1; + change = true; } - } - else if (axial_crys_diff <0) - { // seg_num < 0 - if (abs(axial_crys_diff)%num_axial_crys_per_block == 0) - { // In this case, axial block difference can be only equal to axial_crys_diff/num_axial_crys_per_block. So we only have one type of related bins - // basic bin will be the first lor from the corresponding group - ring2= (ring2/num_axial_crys_per_block)*num_axial_crys_per_block; - ring1= ring2 - axial_crys_diff; + if (do_symmetry_shift_z && axial_pos_num != 0) + { + axial_pos_num = 0; + change = true; } - else - { /* In this case, axial block difference can be equal to axial_crys_diff/num_axial_crys_per_block - or one less. - So we can have two types of of related bins*/ - if (abs(axial_blk_diff) == abs(axial_crys_diff)/num_axial_crys_per_block) - {// basic bin will be the first lor from the corresponding group - ring2= (ring2/num_axial_crys_per_block)*num_axial_crys_per_block; - ring1= ring2 - axial_crys_diff; - } - else if (abs(axial_blk_diff) > abs(axial_crys_diff)/num_axial_crys_per_block) - {// basic bin will be the last lor from the corresponding group - ring2= (ring2/num_axial_crys_per_block)*num_axial_crys_per_block + num_axial_crys_per_block-1; - ring1= ring2 - axial_crys_diff; - } + + return change; + } + + // block implementaion + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "BlocksOnCylindrical") + { + /* + ax_pos_num = (ring1 + ring2 - ax_pos_num_offset[seg_num])*num_ax_pos_per_ring_inc(seg_num)/2 + ax_pos_num_offset = num_rings - 1 - (max_ax_pos_num + min_ax_pos_num)/num_ax_pos_per_ring_inc(seg_num) + Then + ax_pos_num = (ring1 + ring2 - num_rings + 1)*ax_pos_inc/2 - (max_ax_pos_num + min_ax_pos_num)/2 + and + max_ax_pos_num + min_ax_pos_num = (num_ax_pos_per_seg -1) + 0 = num_rings - seg_num - 1 + Then + ax_pos_num = (ring1 + ring2 - num_rings + 1)*ax_pos_inc/2 - (num_rings - seg_num - 1)/2 + if ax_pos_inc == 1 + ax_pos_num = (ring1 + ring2 - seg_num)/2 + */ + const ProjDataInfoBlocksOnCylindrical* proj_data_info_blk_ptr + = static_cast(proj_data_info_ptr.get()); + if (do_symmetry_shift_z) + { + int ring1, ring2; + proj_data_info_blk_ptr->get_ring_pair_for_segment_axial_pos_num(ring1, ring2, segment_num, axial_pos_num); + // to check + // std::cout<<"before seg, ax, r1, r2 = "<get_scanner_ptr()->get_num_axial_crystals_per_block(); + int axial_blk_diff = ring2 / num_axial_crys_per_block - ring1 / num_axial_crys_per_block; + + if (axial_crys_diff >= 0) + { // seg_num > =0 + if (axial_crys_diff % num_axial_crys_per_block == 0) + { // In this case, axial block difference can be only equal to axial_crys_diff/num_axial_crys_per_block. So we + // only have one type of related bins + // basic bin will be the first lor from the corresponding group + ring1 = (ring1 / num_axial_crys_per_block) * num_axial_crys_per_block; + ring2 = ring1 + axial_crys_diff; + } + else + { /* In this case, axial block difference can be equal to axial_crys_diff/num_axial_crys_per_block + or one less. + So we can have two types of of related bins*/ + if (axial_blk_diff == axial_crys_diff / num_axial_crys_per_block) + { // basic bin will be the first lor from the corresponding group + ring1 = (ring1 / num_axial_crys_per_block) * num_axial_crys_per_block; + ring2 = ring1 + axial_crys_diff; + } + else if (axial_blk_diff > axial_crys_diff / num_axial_crys_per_block) + { // basic bin will be the last lor from the corresponding group + ring1 = (ring1 / num_axial_crys_per_block) * num_axial_crys_per_block + num_axial_crys_per_block - 1; + ring2 = ring1 + axial_crys_diff; + } + } + } + else if (axial_crys_diff < 0) + { // seg_num < 0 + if (abs(axial_crys_diff) % num_axial_crys_per_block == 0) + { // In this case, axial block difference can be only equal to axial_crys_diff/num_axial_crys_per_block. So we + // only have one type of related bins + // basic bin will be the first lor from the corresponding group + ring2 = (ring2 / num_axial_crys_per_block) * num_axial_crys_per_block; + ring1 = ring2 - axial_crys_diff; + } + else + { /* In this case, axial block difference can be equal to axial_crys_diff/num_axial_crys_per_block + or one less. + So we can have two types of of related bins*/ + if (abs(axial_blk_diff) == abs(axial_crys_diff) / num_axial_crys_per_block) + { // basic bin will be the first lor from the corresponding group + ring2 = (ring2 / num_axial_crys_per_block) * num_axial_crys_per_block; + ring1 = ring2 - axial_crys_diff; + } + else if (abs(axial_blk_diff) > abs(axial_crys_diff) / num_axial_crys_per_block) + { // basic bin will be the last lor from the corresponding group + ring2 = (ring2 / num_axial_crys_per_block) * num_axial_crys_per_block + num_axial_crys_per_block - 1; + ring1 = ring2 - axial_crys_diff; + } + } + } + + int segment_num_temp, axial_pos_num_temp; + proj_data_info_blk_ptr->get_segment_axial_pos_num_for_ring_pair(segment_num_temp, axial_pos_num_temp, ring1, ring2); + + // to check + // std::cout<<"after seg, ax, r1, r2 = "< - get_segment_axial_pos_num_for_ring_pair(segment_num_temp, axial_pos_num_temp, ring1, ring2); - - //to check - //std::cout<<"after seg, ax, r1, r2 = "<get_scanner_ptr()->get_scanner_geometry()=="Generic") - { //same procedure as for the block implementation above - const ProjDataInfoGeneric* proj_data_info_gen_ptr = - static_cast(proj_data_info_ptr.get()); - if (do_symmetry_shift_z) + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "Generic") + { // same procedure as for the block implementation above + const ProjDataInfoGeneric* proj_data_info_gen_ptr = static_cast(proj_data_info_ptr.get()); + if (do_symmetry_shift_z) { - int ring1, ring2; - proj_data_info_gen_ptr->get_ring_pair_for_segment_axial_pos_num (ring1, ring2, segment_num, axial_pos_num); + int ring1, ring2; + proj_data_info_gen_ptr->get_ring_pair_for_segment_axial_pos_num(ring1, ring2, segment_num, axial_pos_num); - int axial_crys_diff = ring2 - ring1; - int num_axial_crys_per_block = proj_data_info_ptr->get_scanner_ptr()->get_num_axial_crystals_per_block(); - int axial_blk_diff = ring2/num_axial_crys_per_block - ring1/num_axial_crys_per_block; + int axial_crys_diff = ring2 - ring1; + int num_axial_crys_per_block = proj_data_info_ptr->get_scanner_ptr()->get_num_axial_crystals_per_block(); + int axial_blk_diff = ring2 / num_axial_crys_per_block - ring1 / num_axial_crys_per_block; - if (axial_crys_diff >=0) + if (axial_crys_diff >= 0) { // seg_num > 0 - if (axial_crys_diff%num_axial_crys_per_block == 0) - { // axial block difference can be only axial_crys_diff/num_axial_crys_per_block. So we only have one type of related bins - // basic bin will be the first lor from the corresponding group - ring1= (ring1/num_axial_crys_per_block)*num_axial_crys_per_block; - ring2= ring1 + axial_crys_diff; + if (axial_crys_diff % num_axial_crys_per_block == 0) + { // axial block difference can be only axial_crys_diff/num_axial_crys_per_block. So we only have one type of + // related bins + // basic bin will be the first lor from the corresponding group + ring1 = (ring1 / num_axial_crys_per_block) * num_axial_crys_per_block; + ring2 = ring1 + axial_crys_diff; } - else - { /* axial block difference can be axial_crys_diff/num_axial_crys_per_block - or one less. - So we can have two types of of related bins*/ - if (axial_blk_diff == axial_crys_diff/num_axial_crys_per_block) - {// basic bin will be the first lor from the corresponding group - ring1= (ring1/num_axial_crys_per_block)*num_axial_crys_per_block; - ring2= ring1 + axial_crys_diff; + else + { /* axial block difference can be axial_crys_diff/num_axial_crys_per_block + or one less. + So we can have two types of of related bins*/ + if (axial_blk_diff == axial_crys_diff / num_axial_crys_per_block) + { // basic bin will be the first lor from the corresponding group + ring1 = (ring1 / num_axial_crys_per_block) * num_axial_crys_per_block; + ring2 = ring1 + axial_crys_diff; } - else if (axial_blk_diff > axial_crys_diff/num_axial_crys_per_block) - {// basic bin will be the last lor from the corresponding group - ring1= (ring1/num_axial_crys_per_block)*num_axial_crys_per_block + num_axial_crys_per_block-1; - ring2= ring1 + axial_crys_diff; + else if (axial_blk_diff > axial_crys_diff / num_axial_crys_per_block) + { // basic bin will be the last lor from the corresponding group + ring1 = (ring1 / num_axial_crys_per_block) * num_axial_crys_per_block + num_axial_crys_per_block - 1; + ring2 = ring1 + axial_crys_diff; } } } - else if (axial_crys_diff <0) + else if (axial_crys_diff < 0) { // seg_num < 0 - if (abs(axial_crys_diff)%num_axial_crys_per_block == 0) - { // axial block difference can be only axial_crys_diff/num_axial_crys_per_block. So we only have one type of related bins - // basic bin will be the first lor from the corresponding group - ring2= (ring2/num_axial_crys_per_block)*num_axial_crys_per_block; - ring1= ring2 - axial_crys_diff; + if (abs(axial_crys_diff) % num_axial_crys_per_block == 0) + { // axial block difference can be only axial_crys_diff/num_axial_crys_per_block. So we only have one type of + // related bins + // basic bin will be the first lor from the corresponding group + ring2 = (ring2 / num_axial_crys_per_block) * num_axial_crys_per_block; + ring1 = ring2 - axial_crys_diff; } - else - { /* axial block difference can be axial_crys_diff/num_axial_crys_per_block - or one less. - So we can have two types of of related bins*/ - if (abs(axial_blk_diff) == abs(axial_crys_diff)/num_axial_crys_per_block) - {// basic bin will be the first lor from the corresponding group - ring2= (ring2/num_axial_crys_per_block)*num_axial_crys_per_block; - ring1= ring2 - axial_crys_diff; + else + { /* axial block difference can be axial_crys_diff/num_axial_crys_per_block + or one less. + So we can have two types of of related bins*/ + if (abs(axial_blk_diff) == abs(axial_crys_diff) / num_axial_crys_per_block) + { // basic bin will be the first lor from the corresponding group + ring2 = (ring2 / num_axial_crys_per_block) * num_axial_crys_per_block; + ring1 = ring2 - axial_crys_diff; } - else if (abs(axial_blk_diff) > abs(axial_crys_diff)/num_axial_crys_per_block) - {// basic bin will be the last lor from the corresponding group - ring2= (ring2/num_axial_crys_per_block)*num_axial_crys_per_block + num_axial_crys_per_block-1; - ring1= ring2 - axial_crys_diff; + else if (abs(axial_blk_diff) > abs(axial_crys_diff) / num_axial_crys_per_block) + { // basic bin will be the last lor from the corresponding group + ring2 = (ring2 / num_axial_crys_per_block) * num_axial_crys_per_block + num_axial_crys_per_block - 1; + ring1 = ring2 - axial_crys_diff; } } } - int segment_num_temp, axial_pos_num_temp; - proj_data_info_gen_ptr-> - get_segment_axial_pos_num_for_ring_pair(segment_num_temp, axial_pos_num_temp, ring1, ring2); - - if (segment_num_temp != segment_num) - error("segment number shouldn't change in basic bin when implementing only symmetry in z.\n" - "segment_num = %d while segment_num_temp = %d \n", segment_num, segment_num_temp); - else if (axial_pos_num_temp != axial_pos_num) + int segment_num_temp, axial_pos_num_temp; + proj_data_info_gen_ptr->get_segment_axial_pos_num_for_ring_pair(segment_num_temp, axial_pos_num_temp, ring1, ring2); + + if (segment_num_temp != segment_num) + error("segment number shouldn't change in basic bin when implementing only symmetry in z.\n" + "segment_num = %d while segment_num_temp = %d \n", + segment_num, + segment_num_temp); + else if (axial_pos_num_temp != axial_pos_num) { - axial_pos_num = axial_pos_num_temp; - change = true; + axial_pos_num = axial_pos_num_temp; + change = true; } } } - return change; + return change; } -bool -DataSymmetriesForBins_PET_CartesianGrid:: -find_basic_bin(Bin& b) const +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(), b.timing_pos_num()); } - // TODO, optimise unique_ptr -DataSymmetriesForBins_PET_CartesianGrid:: - find_symmetry_operation_from_basic_bin(Bin& b) const +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()) - ); + 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 +DataSymmetriesForBins_PET_CartesianGrid::num_related_bins(const Bin& b) const { - int num; - //cylindrical implementaion - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="Cylindrical") + int num; + // cylindrical implementaion + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "Cylindrical") { - 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; + 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()); + 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()); } - - //block implementaion - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="BlocksOnCylindrical") -{ - const ProjDataInfoBlocksOnCylindrical* proj_data_info_blk_ptr = - static_cast(proj_data_info_ptr.get()); - if (do_symmetry_shift_z) + + // block implementaion + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "BlocksOnCylindrical") { - int ring1, ring2; - proj_data_info_blk_ptr->get_ring_pair_for_segment_axial_pos_num - (ring1, ring2, b.segment_num(), b.axial_pos_num()); - int axial_crys_diff = ring1 - ring2; - int num_axial_crys_per_block = proj_data_info_ptr->get_scanner_ptr()->get_num_axial_crystals_per_block(); - int axial_blk_diff = ring1/num_axial_crys_per_block - ring2/num_axial_crys_per_block; - - if (axial_blk_diff == axial_crys_diff/num_axial_crys_per_block) - { - num = num_axial_crys_per_block - - abs(axial_crys_diff)%num_axial_crys_per_block; - } - else if (axial_blk_diff > axial_crys_diff/num_axial_crys_per_block) - { - num = abs(axial_crys_diff)%num_axial_crys_per_block; - } + const ProjDataInfoBlocksOnCylindrical* proj_data_info_blk_ptr + = static_cast(proj_data_info_ptr.get()); + if (do_symmetry_shift_z) + { + int ring1, ring2; + proj_data_info_blk_ptr->get_ring_pair_for_segment_axial_pos_num(ring1, ring2, b.segment_num(), b.axial_pos_num()); + int axial_crys_diff = ring1 - ring2; + int num_axial_crys_per_block = proj_data_info_ptr->get_scanner_ptr()->get_num_axial_crystals_per_block(); + int axial_blk_diff = ring1 / num_axial_crys_per_block - ring2 / num_axial_crys_per_block; + + if (axial_blk_diff == axial_crys_diff / num_axial_crys_per_block) + { + num = num_axial_crys_per_block - abs(axial_crys_diff) % num_axial_crys_per_block; + } + else if (axial_blk_diff > axial_crys_diff / num_axial_crys_per_block) + { + num = abs(axial_crys_diff) % num_axial_crys_per_block; + } + } } - } - //generic implementation - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="Generic") - { + // generic implementation + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "Generic") + { num = 1; - } + } 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 +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 { - //cylindrical implementaion - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="Cylindrical") + // cylindrical implementaion + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "Cylindrical") { - 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())); - } + 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())); + } } - - //block implementaion - //currently it only saves related bins according to z-symmetry - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="BlocksOnCylindrical") - { - 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) + + // block implementaion + // currently it only saves related bins according to z-symmetry + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "BlocksOnCylindrical") { - if (b.tangential_pos_num() >= min_tangential_pos_num && - b.tangential_pos_num() <= max_tangential_pos_num) - { - Bin basic_bin(b); - find_basic_bin(basic_bin); - Bin bin_temp(b.segment_num(), b.view_num(), axial_pos_num, b.tangential_pos_num()); - find_basic_bin(bin_temp); - if (basic_bin == bin_temp) - ax_tang_poss.push_back(AxTangPosNumbers(axial_pos_num, b.tangential_pos_num())); - } - } - } - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="Generic") - { - 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) + 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) { - Bin basic_bin(b); - find_basic_bin(basic_bin); - Bin bin_temp(b.segment_num(), b.view_num(), axial_pos_num, b.tangential_pos_num()); - find_basic_bin(bin_temp); - if (basic_bin == bin_temp) - ax_tang_poss.push_back(AxTangPosNumbers(axial_pos_num, b.tangential_pos_num())); + if (b.tangential_pos_num() >= min_tangential_pos_num && b.tangential_pos_num() <= max_tangential_pos_num) + { + Bin basic_bin(b); + find_basic_bin(basic_bin); + Bin bin_temp(b.segment_num(), b.view_num(), axial_pos_num, b.tangential_pos_num()); + find_basic_bin(bin_temp); + if (basic_bin == bin_temp) + ax_tang_poss.push_back(AxTangPosNumbers(axial_pos_num, b.tangential_pos_num())); + } } - } - } - + } + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "Generic") + { + 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) + { + Bin basic_bin(b); + find_basic_bin(basic_bin); + Bin bin_temp(b.segment_num(), b.view_num(), axial_pos_num, b.tangential_pos_num()); + find_basic_bin(bin_temp); + if (basic_bin == bin_temp) + 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)); - - 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(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)); - } - 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)); - if (symz) - 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)); + } + 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)); + } + 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)); + if (symz) + 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 c35e0f464..140cc16e8 100644 --- a/src/include/stir/recon_buildblock/DataSymmetriesForDensels.h +++ b/src/include/stir/recon_buildblock/DataSymmetriesForDensels.h @@ -15,7 +15,7 @@ \brief Declaration of class stir::DataSymmetriesForDensels \author Kris Thielemans - + */ #ifndef __stir_recon_buildblock_DataSymmetriesForDensels_H__ #define __stir_recon_buildblock_DataSymmetriesForDensels_H__ @@ -29,41 +29,36 @@ 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! @@ -73,12 +68,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' @@ -90,36 +84,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 dd829388c..2e811599b 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 @@ -23,16 +23,14 @@ START_NAMESPACE_STIR void -DataSymmetriesForDensels:: - get_related_densels(vector& rel_b, const Densel& b) const +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()); + 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 b1b130db7..4b92bb66f 100644 --- a/src/include/stir/recon_buildblock/DistributedCachingInformation.h +++ b/src/include/stir/recon_buildblock/DistributedCachingInformation.h @@ -14,7 +14,7 @@ /*! \ingroup distributable - + \brief Declaration of class stir::DistributedCachingInformation \author Tobias Beisel @@ -32,39 +32,39 @@ 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: +public: //! constructor, calls initialise() explicit DistributedCachingInformation(const int num_processors); - + //! destructor to clean up data structures virtual ~DistributedCachingInformation(); @@ -75,31 +75,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; @@ -109,7 +108,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; @@ -128,33 +127,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 3a1be7237..a5fca375f 100644 --- a/src/include/stir/recon_buildblock/DistributedWorker.h +++ b/src/include/stir/recon_buildblock/DistributedWorker.h @@ -9,27 +9,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 @@ -41,16 +40,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. @@ -59,73 +58,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 b7ab04cdc..78b6ca5ba 100644 --- a/src/include/stir/recon_buildblock/FilterRootPrior.h +++ b/src/include/stir/recon_buildblock/FilterRootPrior.h @@ -21,29 +21,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$ @@ -57,66 +57,49 @@ 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 - > +class FilterRootPrior : public RegisteredParsingObject, GeneralisedPrior, GeneralisedPrior> { - private: - typedef - RegisteredParsingObject< - FilterRootPrior, - GeneralisedPrior, - GeneralisedPrior - > - base_type; +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); bool is_convex() const override; - //! 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. */ - double - compute_value(const DataT ¤t_estimate) override; - + double compute_value(const DataT& current_estimate) override; + //! compute gradient by applying the filter - void compute_gradient(DataT& prior_gradient, - const DataT ¤t_estimate) override; + void compute_gradient(DataT& prior_gradient, const DataT& current_estimate) override; //! Has to be called before using this object Succeeded set_up(shared_ptr const& target_sptr) override; - -protected: +protected: //! Check that the prior is ready to be used void check(DataT const& current_image_estimate) const override; - -private: - shared_ptr > filter_ptr; - void set_defaults() override; - void initialise_keymap() override; +private: + shared_ptr> filter_ptr; + void set_defaults() override; + void initialise_keymap() override; }; - END_NAMESPACE_STIR #endif - diff --git a/src/include/stir/recon_buildblock/ForwardProjectorByBin.h b/src/include/stir/recon_buildblock/ForwardProjectorByBin.h index b8990c669..85a685a0d 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 @@ -35,89 +36,88 @@ 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); #if 0 // disabled as currently not used. needs to be written in the new style anyway //! function mainly used in ListMode reconstruction. @@ -125,24 +125,28 @@ virtual void set_up( void forward_project(Bin&, const DiscretisedDensity<3,float>&); #endif - ~ForwardProjectorByBin() override; + ~ForwardProjectorByBin() override; - /// 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&, + 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); + 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. @@ -164,18 +168,18 @@ virtual void set_up( Calls check(const ProjDataInfo&) */ - 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; void set_defaults() override; void initialise_keymap() override; - protected: +protected: //! ProjDataInfo set by set_up() shared_ptr _proj_data_info_sptr; }; diff --git a/src/include/stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h b/src/include/stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h index 2a6fce003..5343da849 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 @@ -26,59 +26,53 @@ 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. - */ - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; + */ + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; - - const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const override; + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const override; 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) override; + 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) override; #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>&); @@ -87,13 +81,8 @@ class ForwardProjectorByBinUsingProjMatrixByBin: void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - }; - END_NAMESPACE_STIR - #endif - - diff --git a/src/include/stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h b/src/include/stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h index afc89113f..f7be6c597 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 @@ -31,14 +31,17 @@ #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 @@ -50,10 +53,10 @@ class ProjDataInfoCylindrical; 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. @@ -63,47 +66,44 @@ 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. - */ - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; + */ + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; - const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const override; + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const override; - 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) override; + 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) override; #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>&); @@ -116,106 +116,114 @@ 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; - //! 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); + 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; + //! 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); void set_defaults() override; void initialise_keymap() override; diff --git a/src/include/stir/recon_buildblock/FourierRebinning.h b/src/include/stir/recon_buildblock/FourierRebinning.h index 588e0c1f9..0f06b362d 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 @@ -30,48 +30,51 @@ #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; + +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){} + + ; }; /*! @@ -84,140 +87,147 @@ 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> +class FourierRebinning : public RegisteredParsingObject { - private: +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; void set_defaults() override; - 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 override - { 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() override; - -//! 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: - bool post_processing() override; +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 override { 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() override; + + //! 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: + bool post_processing() override; void initialise_keymap() override; - }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/GeneralisedObjectiveFunction.h b/src/include/stir/recon_buildblock/GeneralisedObjectiveFunction.h index f4682bfe1..0a4d73222 100644 --- a/src/include/stir/recon_buildblock/GeneralisedObjectiveFunction.h +++ b/src/include/stir/recon_buildblock/GeneralisedObjectiveFunction.h @@ -23,7 +23,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" @@ -36,20 +35,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. @@ -62,7 +60,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. @@ -81,104 +79,83 @@ class Succeeded; \endverbatim */ template -class GeneralisedObjectiveFunction: - public RegisteredObject > +class GeneralisedObjectiveFunction : public RegisteredObject> { public: - GeneralisedObjectiveFunction() - : already_set_up(false) + : already_set_up(false) {} - - ~GeneralisedObjectiveFunction() override; - + ~GeneralisedObjectiveFunction() override; //! Creates a suitable target as determined by the parameters /*! \warning This should not check \c already_set_up (unfortunately), as it is currently called in Reconstruction::reconstruct() before calling set_up(). */ - 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 @@ -194,85 +171,66 @@ 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 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; + { + auto exam_info_uptr = unique_ptr(new ExamInfo(*(this->get_input_data().get_exam_info_sptr()))); + return exam_info_uptr; } - //! 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 +241,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 +259,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 +284,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 @@ -340,7 +296,7 @@ class GeneralisedObjectiveFunction: int num_subsets; bool already_set_up; - shared_ptr > prior_sptr; + shared_ptr> prior_sptr; //! sets any default values /*! Has to be called by set_defaults in the leaf-class */ @@ -349,7 +305,7 @@ class GeneralisedObjectiveFunction: /*! Has to be called by initialise_keymap in the leaf-class */ void initialise_keymap() override; - //virtual bool post_processing(); + // virtual bool post_processing(); //! Implementation of function that checks subset balancing /*! @@ -357,7 +313,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(). */ @@ -369,13 +325,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. /*! @@ -386,33 +340,31 @@ 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 1f6b804cc..18e125e4e 100644 --- a/src/include/stir/recon_buildblock/GeneralisedPrior.h +++ b/src/include/stir/recon_buildblock/GeneralisedPrior.h @@ -21,7 +21,6 @@ #ifndef __stir_recon_buildblock_GeneralisedPrior_H__ #define __stir_recon_buildblock_GeneralisedPrior_H__ - #include "stir/RegisteredObject.h" #include "stir/ParsingObject.h" @@ -33,45 +32,40 @@ 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 computes a single row of the Hessian /*! Default implementation just call error(). This function needs to be overridden by the derived class. - - The method computes a row (i.e. at a densel/voxel, indicated by \c coords) of the Hessian at \c current_estimate. + + The method computes a row (i.e. at a densel/voxel, indicated by \c coords) of the Hessian at \c current_estimate. Note that a row corresponds to an object of `DataT`. The method (as implemented in derived classes) should store the result in \c prior_Hessian_for_single_densel. */ - virtual void - compute_Hessian(DataT& prior_Hessian_for_single_densel, - const BasicCoordinate<3,int>& coords, - const DataT& current_image_estimate) const; + virtual void compute_Hessian(DataT& prior_Hessian_for_single_densel, + const BasicCoordinate<3, int>& coords, + const DataT& current_image_estimate) 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 @@ -80,27 +74,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 void - 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 void - accumulate_Hessian_times_input(DataT& output, - const DataT& current_estimate, - const DataT& input) const; + virtual void 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 void 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); //! Indicates if the prior is a smooth convex function /*! If true, the prior is expected to have 0th, 1st and 2nd order behaviour implemented.*/ diff --git a/src/include/stir/recon_buildblock/GeneralisedPrior.inl b/src/include/stir/recon_buildblock/GeneralisedPrior.inl index 2cdb5b72d..435f80ff8 100644 --- a/src/include/stir/recon_buildblock/GeneralisedPrior.inl +++ b/src/include/stir/recon_buildblock/GeneralisedPrior.inl @@ -20,25 +20,24 @@ 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 7b4a2176b..5039b4445 100644 --- a/src/include/stir/recon_buildblock/IterativeReconstruction.h +++ b/src/include/stir/recon_buildblock/IterativeReconstruction.h @@ -11,12 +11,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 @@ -31,42 +31,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. @@ -79,16 +79,13 @@ START_NAMESPACE_STIR template class IterativeReconstruction : public Reconstruction -{ - private: - typedef - Reconstruction - base_type; -public: +{ +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. @@ -104,16 +101,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 /*! @@ -122,9 +118,8 @@ class IterativeReconstruction : public Reconstruction See end_of_iteration_processing() for info on saving to file. \return Succeeded::yes if everything was alright. - */ - Succeeded - reconstruct() override; + */ + Succeeded reconstruct() override; //! executes the reconstruction with \a target_data_sptr as initial value /*! After calling set_up(), repeatedly calls update_estimate(); end_of_iteration_processing(); @@ -132,31 +127,26 @@ class IterativeReconstruction : public Reconstruction Final reconstruction is saved in \a target_data_sptr */ - Succeeded - reconstruct(shared_ptr const& target_data_sptr) override; + Succeeded reconstruct(shared_ptr const& target_data_sptr) override; //! 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; @@ -164,7 +154,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 @@ -173,7 +163,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; @@ -183,9 +173,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 @@ -194,12 +184,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); @@ -207,7 +197,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 @@ -216,7 +206,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); @@ -224,9 +214,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 @@ -239,34 +229,32 @@ class IterativeReconstruction : public Reconstruction const ExamData& get_input_data() const override; //@} - Succeeded set_up(shared_ptr const& target_data_ptr) override; + Succeeded set_up(shared_ptr const& target_data_ptr) override; //! 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; @@ -274,16 +262,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 @@ -295,7 +282,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; @@ -303,16 +290,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. */ @@ -326,19 +309,15 @@ class IterativeReconstruction : public Reconstruction //! used to check acceptable parameter ranges, etc... bool post_processing() override; - 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 cacf2526b..0b2dfb45d 100644 --- a/src/include/stir/recon_buildblock/LogcoshPrior.h +++ b/src/include/stir/recon_buildblock/LogcoshPrior.h @@ -21,11 +21,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" @@ -35,7 +33,6 @@ START_NAMESPACE_STIR - /*! \ingroup priors \brief @@ -81,166 +78,164 @@ 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); - bool - parabolic_surrogate_curvature_depends_on_argument() const override - { return false; } + bool parabolic_surrogate_curvature_depends_on_argument() const override { return false; } - bool is_convex() const override; + bool is_convex() const override; - //! compute the value of the function - double - compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate) override; + //! compute the value of the function + double compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate) override; - //! compute gradient - void compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) override; + //! compute gradient + void compute_gradient(DiscretisedDensity<3, elemT>& prior_gradient, + const DiscretisedDensity<3, elemT>& current_image_estimate) override; - //! compute the parabolic surrogate for the prior - void parabolic_surrogate_curvature(DiscretisedDensity<3,elemT>& parabolic_surrogate_curvature, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) override; + //! compute the parabolic surrogate for the prior + void parabolic_surrogate_curvature(DiscretisedDensity<3, elemT>& parabolic_surrogate_curvature, + const DiscretisedDensity<3, elemT>& current_image_estimate) override; - void - compute_Hessian(DiscretisedDensity<3,elemT>& prior_Hessian_for_single_densel, - const BasicCoordinate<3,int>& coords, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) const override; + void compute_Hessian(DiscretisedDensity<3, elemT>& prior_Hessian_for_single_densel, + const BasicCoordinate<3, int>& coords, + const DiscretisedDensity<3, elemT>& current_image_estimate) const override; - //! Compute the multiplication of the hessian of the prior (at \c current_estimate) and the \c input. - void accumulate_Hessian_times_input(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& current_estimate, - const DiscretisedDensity<3,elemT>& input) const override; + //! Compute the multiplication of the hessian of the prior (at \c current_estimate) and the \c input. + void accumulate_Hessian_times_input(DiscretisedDensity<3, elemT>& output, + const DiscretisedDensity<3, elemT>& current_estimate, + const DiscretisedDensity<3, elemT>& input) const override; - //! 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; - void set_defaults() override; - void initialise_keymap() override; - bool post_processing() override; + void set_defaults() override; + void initialise_keymap() override; + bool post_processing() override; 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 ){ + //! 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 { + } + 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(); @@ -65,23 +63,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.*/ @@ -95,12 +91,13 @@ 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; @@ -111,5 +108,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 0a0fbdc78..5ae47854e 100644 --- a/src/include/stir/recon_buildblock/NiftyPET_projector/ForwardProjectorByBinNiftyPET.h +++ b/src/include/stir/recon_buildblock/NiftyPET_projector/ForwardProjectorByBinNiftyPET.h @@ -50,70 +50,71 @@ 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); + 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 b2f47c1a0..2981c6e0c 100644 --- a/src/include/stir/recon_buildblock/NiftyPET_projector/NiftyPETHelper.h +++ b/src/include/stir/recon_buildblock/NiftyPET_projector/NiftyPETHelper.h @@ -45,10 +45,13 @@ 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 @@ -57,114 +60,123 @@ template class VoxelsOnCartesianGrid; 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 ff7dbe214..9a068fac3 100644 --- a/src/include/stir/recon_buildblock/NiftyPET_projector/ProjectorByBinPairUsingNiftyPET.h +++ b/src/include/stir/recon_buildblock/NiftyPET_projector/ProjectorByBinPairUsingNiftyPET.h @@ -31,22 +31,17 @@ 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 @@ -57,7 +52,6 @@ class ProjectorByBinPairUsingNiftyPET : void set_use_truncation(const bool use_truncation); private: - void set_defaults(); void initialise_keymap(); bool post_processing(); @@ -67,5 +61,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 2c33d1a12..59dc09bf7 100644 --- a/src/include/stir/recon_buildblock/PLSPrior.h +++ b/src/include/stir/recon_buildblock/PLSPrior.h @@ -18,11 +18,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" @@ -32,7 +30,6 @@ START_NAMESPACE_STIR - /*! \ingroup priors \brief @@ -95,22 +92,19 @@ START_NAMESPACE_STIR */ template -class PLSPrior: public - RegisteredParsingObject< PLSPrior, - GeneralisedPrior >, - GeneralisedPrior > - > +class PLSPrior : public RegisteredParsingObject, + GeneralisedPrior>, + GeneralisedPrior>> { - private: - typedef - RegisteredParsingObject< PLSPrior, - GeneralisedPrior >, - GeneralisedPrior > > - base_type; - - public: +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(); @@ -120,49 +114,47 @@ class PLSPrior: public //! Has to be called before using this object /*! \todo set the anatomical image to zero if not defined */ - Succeeded set_up(shared_ptr > const& target_sptr) override; + Succeeded set_up(shared_ptr> const& target_sptr) override; bool is_convex() const override; //! compute the value of the function - double - compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate) override; + double compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate) override; //! compute gradient - void compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) override; + void compute_gradient(DiscretisedDensity<3, elemT>& prior_gradient, + const DiscretisedDensity<3, elemT>& current_image_estimate) override; //! 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 @@ -191,40 +183,37 @@ class PLSPrior: public bool post_processing() override; //! Check that the prior is ready to be used - void check(DiscretisedDensity<3,elemT> const& current_image_estimate) const override; - - private: + void check(DiscretisedDensity<3, elemT> const& current_image_estimate) const override; +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/Parallelproj_projector/BackProjectorByBinParallelproj.h b/src/include/stir/recon_buildblock/Parallelproj_projector/BackProjectorByBinParallelproj.h index 610edf1d2..e7338c4eb 100644 --- a/src/include/stir/recon_buildblock/Parallelproj_projector/BackProjectorByBinParallelproj.h +++ b/src/include/stir/recon_buildblock/Parallelproj_projector/BackProjectorByBinParallelproj.h @@ -29,19 +29,20 @@ START_NAMESPACE_STIR class DataSymmetriesForViewSegmentNumbers; class ProjDataInMemory; -namespace detail { class ParallelprojHelper; } +namespace detail +{ +class ParallelprojHelper; +} /*! \ingroup Parallelproj \brief Class for Parallelproj's back projector */ -class BackProjectorByBinParallelproj : - public RegisteredParsingObject -{ +class BackProjectorByBinParallelproj : 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() BackProjectorByBinParallelproj(); @@ -52,24 +53,22 @@ class BackProjectorByBinParallelproj : void initialise_keymap() override; //! Stores all necessary geometric info - /*! - If necessary, set_up() can be called more than once. - */ - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_sptr // TODO should be Info only - ) override; + /*! + If necessary, set_up() can be called more than once. + */ + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_sptr // TODO should be Info only + ) override; //! Symmetries not used, so returns TrivialDataSymmetriesForBins. - const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const override; + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const override; #if 0 /// Back project void back_project(const ProjData&, int subset_num = 0, int num_subsets = 1); #endif - /// Get output - void get_output(DiscretisedDensity<3,float> &) const override; - + /// Get output + void get_output(DiscretisedDensity<3, float>&) const override; /*! \brief tell the back projector to start accumulating into a new target. This function has to be called before any back-projection is initiated.*/ @@ -79,21 +78,31 @@ class BackProjectorByBinParallelproj : void set_defaults() override; /// Set verbosity - void set_verbosity(const bool verbosity) { _cuda_verbosity = verbosity; } - - // set/get number of gpu chunks to use - void set_num_gpu_chunks(int num_gpu_chunks) {_num_gpu_chunks = num_gpu_chunks; } - int get_num_gpu_chunks() { return _num_gpu_chunks; } + void set_verbosity(const bool verbosity) + { + _cuda_verbosity = verbosity; + } + + // set/get number of gpu chunks to use + void set_num_gpu_chunks(int num_gpu_chunks) + { + _num_gpu_chunks = num_gpu_chunks; + } + int get_num_gpu_chunks() + { + return _num_gpu_chunks; + } BackProjectorByBinParallelproj* clone() const override; protected: + 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) override; - 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) override; - - private: +private: shared_ptr _symmetries_sptr; shared_ptr _proj_data_to_backproject_sptr; shared_ptr _helper; @@ -106,5 +115,4 @@ class BackProjectorByBinParallelproj : END_NAMESPACE_STIR - #endif // __stir_gpu_BackProjectorByBinParallelproj_h__ diff --git a/src/include/stir/recon_buildblock/Parallelproj_projector/ForwardProjectorByBinParallelproj.h b/src/include/stir/recon_buildblock/Parallelproj_projector/ForwardProjectorByBinParallelproj.h index 722f89471..42566853a 100644 --- a/src/include/stir/recon_buildblock/Parallelproj_projector/ForwardProjectorByBinParallelproj.h +++ b/src/include/stir/recon_buildblock/Parallelproj_projector/ForwardProjectorByBinParallelproj.h @@ -29,81 +29,82 @@ START_NAMESPACE_STIR class ProjDataInMemory; class DataSymmetriesForViewSegmentNumbers; -namespace detail { class ParallelprojHelper; } +namespace detail +{ +class ParallelprojHelper; +} /*! \ingroup Parallelproj \brief Class for Parallelproj's forward projector. */ -class ForwardProjectorByBinParallelproj: - public RegisteredParsingObject -{ +class ForwardProjectorByBinParallelproj : 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 - ForwardProjectorByBinParallelproj(); + // inline + ForwardProjectorByBinParallelproj(); - /// Constructor - ~ForwardProjectorByBinParallelproj() override; + /// Constructor + ~ForwardProjectorByBinParallelproj() override; - /// Keymap - void initialise_keymap() override; + /// Keymap + void initialise_keymap() override; //! 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. - */ -void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_sptr // TODO should be Info only - ) override; + \warning there is currently no check on this. + \warning Derived classes have to call set_up from the base class. + */ + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_sptr // TODO should be Info only + ) override; //! Symmetries not used, so returns TrivialDataSymmetriesForBins. - const DataSymmetriesForViewSegmentNumbers * get_symmetries_used() const override; + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const override; - /// Set input - void set_input(const DiscretisedDensity<3,float>&) override; + /// Set input + void set_input(const DiscretisedDensity<3, float>&) override; - /// set defaults - void set_defaults() override; + /// set defaults + void set_defaults() override; - /// 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; } - // set/get number of gpu chunks to use - void set_num_gpu_chunks(int num_gpu_chunks) {_num_gpu_chunks = num_gpu_chunks; } - int get_num_gpu_chunks() { return _num_gpu_chunks; } + // set/get number of gpu chunks to use + void set_num_gpu_chunks(int num_gpu_chunks) { _num_gpu_chunks = num_gpu_chunks; } + int get_num_gpu_chunks() { return _num_gpu_chunks; } protected: - 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) override; + const int min_axial_pos_num, + const int max_axial_pos_num, + const int min_tangential_pos_num, + const int max_tangential_pos_num) override; private: - shared_ptr _symmetries_sptr; - shared_ptr _projected_data_sptr; - shared_ptr _helper; - bool _do_not_setup_helper; - friend class ProjectorByBinPairUsingParallelproj; - void set_helper(shared_ptr); - bool _cuda_verbosity; - bool _use_truncation; - int _num_gpu_chunks; + shared_ptr _symmetries_sptr; + shared_ptr _projected_data_sptr; + shared_ptr _helper; + bool _do_not_setup_helper; + friend class ProjectorByBinPairUsingParallelproj; + void set_helper(shared_ptr); + bool _cuda_verbosity; + bool _use_truncation; + int _num_gpu_chunks; }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/Parallelproj_projector/ParallelprojHelper.h b/src/include/stir/recon_buildblock/Parallelproj_projector/ParallelprojHelper.h index e6aa5bd84..c494fb1c6 100644 --- a/src/include/stir/recon_buildblock/Parallelproj_projector/ParallelprojHelper.h +++ b/src/include/stir/recon_buildblock/Parallelproj_projector/ParallelprojHelper.h @@ -26,34 +26,33 @@ START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; class ProjDataInfo; namespace detail { - /*! - \ingroup projection - \ingroup Parallelproj - \brief Helper class for Parallelproj's projectors - */ - class ParallelprojHelper - { - public: - - ~ParallelprojHelper(); - ParallelprojHelper(const ProjDataInfo& p_info, const DiscretisedDensity<3,float> &density); - - // parallelproj arrays - std::array voxsize; - std::array imgdim; - std::array origin; - std::vector xstart; - std::vector xend; - }; - -} +/*! + \ingroup projection + \ingroup Parallelproj + \brief Helper class for Parallelproj's projectors +*/ +class ParallelprojHelper +{ +public: + ~ParallelprojHelper(); + ParallelprojHelper(const ProjDataInfo& p_info, const DiscretisedDensity<3, float>& density); -END_NAMESPACE_STIR + // parallelproj arrays + std::array voxsize; + std::array imgdim; + std::array origin; + std::vector xstart; + std::vector xend; +}; + +} // namespace detail +END_NAMESPACE_STIR #endif // __stir_recon_buildblock_ParallelprojHelper_h__ diff --git a/src/include/stir/recon_buildblock/Parallelproj_projector/ProjectorByBinPairUsingParallelproj.h b/src/include/stir/recon_buildblock/Parallelproj_projector/ProjectorByBinPairUsingParallelproj.h index b08a2e058..bd83489c0 100644 --- a/src/include/stir/recon_buildblock/Parallelproj_projector/ProjectorByBinPairUsingParallelproj.h +++ b/src/include/stir/recon_buildblock/Parallelproj_projector/ProjectorByBinPairUsingParallelproj.h @@ -27,32 +27,28 @@ START_NAMESPACE_STIR class Succeeded; -namespace detail { class ParallelprojHelper; } +namespace detail +{ +class ParallelprojHelper; +} /*! \ingroup Parallelproj \brief A projector pair based on Parallelproj projectors */ -class ProjectorByBinPairUsingParallelproj : - public RegisteredParsingObject -{ - private: - typedef - RegisteredParsingObject - base_type; +class ProjectorByBinPairUsingParallelproj + : 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 ProjectorByBinPairUsingParallelproj(); - Succeeded - set_up(const shared_ptr&, - const shared_ptr >&) override; + Succeeded set_up(const shared_ptr&, const shared_ptr>&) override; /// Set verbosity void set_verbosity(const bool verbosity); @@ -68,5 +64,4 @@ class ProjectorByBinPairUsingParallelproj : END_NAMESPACE_STIR - #endif // __stir_recon_buildblock_ProjectorByBinPairUsingParallelproj_h_ diff --git a/src/include/stir/recon_buildblock/PinholeSPECTUB_Tools.h b/src/include/stir/recon_buildblock/PinholeSPECTUB_Tools.h index c135a3c4f..676d02fe2 100644 --- a/src/include/stir/recon_buildblock/PinholeSPECTUB_Tools.h +++ b/src/include/stir/recon_buildblock/PinholeSPECTUB_Tools.h @@ -22,413 +22,402 @@ namespace SPECTUB_mph { - //::: structures :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +//::: structures :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - //.....structure for distribution function information +//.....structure for distribution function information - typedef struct - { - int max_dimx; // maximum size in bins (for allocation purpose) - int max_dimz; // maximum size in bins (for allocation purpose) +typedef struct +{ + int max_dimx; // maximum size in bins (for allocation purpose) + int max_dimz; // maximum size in bins (for allocation purpose) + + int dimx; // actual number of bins forming the PSF (dimx) + int dimz; // actual number of bins forming the PSF (dimz) - int dimx; // actual number of bins forming the PSF (dimx) - int dimz; // actual number of bins forming the PSF (dimz) + int ib0; // first i index for the bins of the PSF + int jb0; // first j index for the bins of the PSF - int ib0; // first i index for the bins of the PSF - int jb0; // first j index for the bins of the PSF + float lngxcmd2; // half of the lenght in cm, dimx + float lngzcmd2; // half of the lenght in cm, dimz - float lngxcmd2; // half of the lenght in cm, dimx - float lngzcmd2; // half of the lenght in cm, dimz + float xc; + float zc; - float xc; - float zc; + float sum; // sum of values (for intensity normalization) - float sum; // sum of values (for intensity normalization) + float** val; // array of values + // float res1; // resolution dimx + // float res2; // resolution dimz - float ** val; // array of values - //float res1; // resolution dimx - //float res2; // resolution dimz - - } psf2d_type; +} psf2d_type; - //... collimator's holes parametre structure................................ +//... collimator's holes parametre structure................................ - typedef struct - { - //int idet; // index of the detel the hole projects to +typedef struct +{ + // int idet; // index of the detel the hole projects to - //... coordinates ...................... + //... coordinates ...................... - float acy; // angular coordinate of the hole in volume framework: angle (deg) (cyl) - float acyR; // angular coordinate of the hole in rotated framework: ang (deg) (cyl) + float acy; // angular coordinate of the hole in volume framework: angle (deg) (cyl) + float acyR; // angular coordinate of the hole in rotated framework: ang (deg) (cyl) - float x1; // x coordinate of the center of the hole (cm): rotated framework - float y1; // y coordinate of the center of the hole (cm): rotated framework - float z1; // z coordinate of the center of the hole (cm): rotated framework + float x1; // x coordinate of the center of the hole (cm): rotated framework + float y1; // y coordinate of the center of the hole (cm): rotated framework + float z1; // z coordinate of the center of the hole (cm): rotated framework - //... axial, edge and acceptance angles ............................... + //... axial, edge and acceptance angles ............................... - float ahx; // x angle of the hole axis (deg) - float ahz; // z angle of the hole axis (deg) + float ahx; // x angle of the hole axis (deg) + float ahz; // z angle of the hole axis (deg) - float aa_x; // acceptance angle x (aperture with respect to hole axis: half of the total acceptance angle) - float aa_z; // acceptance angle z (aperture with respect to hole axis: half of the total acceptance angle) + float aa_x; // acceptance angle x (aperture with respect to hole axis: half of the total acceptance angle) + float aa_z; // acceptance angle z (aperture with respect to hole axis: half of the total acceptance angle) - float egx; // absolute angle of the hole edge (x, minor) in rotated framework - float Egx; // absolute angle of the hole edge (x, major) in rotated framework - float egz; // absolute angle of the hole edge (z, minor) in rotated framework - float Egz; // absolute angle of the hole edge (z, major) in rotated framework + float egx; // absolute angle of the hole edge (x, minor) in rotated framework + float Egx; // absolute angle of the hole edge (x, major) in rotated framework + float egz; // absolute angle of the hole edge (z, minor) in rotated framework + float Egz; // absolute angle of the hole edge (z, major) in rotated framework - float ax_M; // maximum angle of acceptance x - float ax_m; // minimum angle of acceptance x - float az_M; // maximum angle of acceptance z - float az_m; // minimum angle of acceptance z + float ax_M; // maximum angle of acceptance x + float ax_m; // minimum angle of acceptance x + float az_M; // maximum angle of acceptance z + float az_m; // minimum angle of acceptance z + //... others .................... - //... others .................... + std::string shape; // hole shape { rect, round } + bool do_round; // true: round shape || false: rectangular shape + float dxcm; // horizontal size of the hole (cm): horizontal axis, diameter + float dzcm; // vertical size of the hole (cm): vertical axis, diameter - std::string shape; // hole shape { rect, round } - bool do_round; // true: round shape || false: rectangular shape - float dxcm; // horizontal size of the hole (cm): horizontal axis, diameter - float dzcm; // vertical size of the hole (cm): vertical axis, diameter - - } hole_type; +} hole_type; - //... structure for collimator information +//... structure for collimator information - typedef struct - { - std::string model; // cylindrical (cyl) or polygonal prism (pol) +typedef struct +{ + std::string model; // cylindrical (cyl) or polygonal prism (pol) - float rad; // radius of cylinder containig holes (cyl) or apothem (pol) - float L; // collimator thickness - float Ld2; // half of the collimator thickness + float rad; // radius of cylinder containig holes (cyl) or apothem (pol) + float L; // collimator thickness + float Ld2; // half of the collimator thickness - int Nht; // total number of holes - std::vector holes; //array hole_type structure + int Nht; // total number of holes + std::vector holes; // array hole_type structure - } mphcoll_type; +} mphcoll_type; +//.....structure for ring elements information - //.....structure for ring elements information +typedef struct +{ + int nh; // number of holes that project to this detel + std::vector who; // array of indices of holes projecting to this detel - typedef struct - { - int nh ; // number of holes that project to this detel - std::vector who; // array of indices of holes projecting to this detel + float x0; // cartesian coordinates of the center (unrotated system of reference): x + float y0; // cartesian coordinates of the center (unrotated system of reference): y + float z0; // cartesian coordinates of the center (unrotated system of reference): z - float x0 ; // cartesian coordinates of the center (unrotated system of reference): x - float y0 ; // cartesian coordinates of the center (unrotated system of reference): y - float z0 ; // cartesian coordinates of the center (unrotated system of reference): z + float xbin0; // x coordinate for the first bin of the detection row corresponding to this angle + float ybin0; // y coordinate for the first bin of the detection row corresponding to this angle + float zbin0; // z coordinate for the first bin of the detection row corresponding to this angle - float xbin0 ; // x coordinate for the first bin of the detection row corresponding to this angle - float ybin0 ; // y coordinate for the first bin of the detection row corresponding to this angle - float zbin0 ; // z coordinate for the first bin of the detection row corresponding to this angle + float incx; // increment in x to the following bin in detector row + float incy; // increment in y to the following bin in detector row + float incz; // increment in z to the following detector row - float incx ; // increment in x to the following bin in detector row - float incy ; // increment in y to the following bin in detector row - float incz ; // increment in z to the following detector row + float theta; // theta: in-plane angle radius vs x-axis. longitude (deg) + float costh; // cosinus of theta + float sinth; // sinus of theta - float theta ; // theta: in-plane angle radius vs x-axis. longitude (deg) - float costh ; // cosinus of theta - float sinth ; // sinus of theta +} detel_type; - } detel_type; +//.....structure for distribution function information - //.....structure for distribution function information +typedef struct +{ + int dim; // length (in discretization intervals) (odd number) + int i_max; // last i-index = dim -1 + float res; // spatial resolution of distfunc (discretization interval) + float* val; // double array of values - typedef struct - { - int dim; // length (in discretization intervals) (odd number) - int i_max; // last i-index = dim -1 - float res; // spatial resolution of distfunc (discretization interval) - float *val; // double array of values +} discrf1d_type; - } discrf1d_type; +//.....structure for distribution function information - //.....structure for distribution function information +typedef struct +{ + int dim; // length (in discretization intervals) (odd number) + int i_max; // last i-index = dim -1 + int j_max; // last j-index = dim -1 + float res; // spatial resolution of distfunc (discretization interval) + float** val; // double array of values - typedef struct - { - int dim; // length (in discretization intervals) (odd number) - int i_max; // last i-index = dim -1 - int j_max; // last j-index = dim -1 - float res; // spatial resolution of distfunc (discretization interval) - float **val; // double array of values - - } discrf2d_type; +} discrf2d_type; - //.....structure for projection information +//.....structure for projection information - typedef struct - { - int Nbin; // number of bins per row - int Nsli; // number of slices +typedef struct +{ + int Nbin; // number of bins per row + int Nsli; // number of slices - int Ndt; // number of detels (detector elements) - int Nbd; // number of bins per detel - int Nbt; // total number of bins - - float szcm; // bin size in cm - float szcmd2; // bin size in cm divided by 2 - float thcm; // slice thickness (cm) - float thcmd2; // slice thickness in cm divided by 2 + int Ndt; // number of detels (detector elements) + int Nbd; // number of bins per detel + int Nbt; // total number of bins - float crth; // crystal thickness (cm) to correction for depth - float crth_2; // power 2 of the above value - float crattcoef; // attenuation coefficient of crystal - float max_dcr; //maximum distance of a ray inside the crystal + float szcm; // bin size in cm + float szcmd2; // bin size in cm divided by 2 + float thcm; // slice thickness (cm) + float thcmd2; // slice thickness in cm divided by 2 - float FOVxcmd2; // FOVcmx divided by 2 - float FOVzcmd2; // FOVcmz divided by 2 + float crth; // crystal thickness (cm) to correction for depth + float crth_2; // power 2 of the above value + float crattcoef; // attenuation coefficient of crystal + float max_dcr; // maximum distance of a ray inside the crystal - float rad; // ring radius - float radc; // extended ring radius = radius + crystal thickness + float FOVxcmd2; // FOVcmx divided by 2 + float FOVzcmd2; // FOVcmz divided by 2 - int NOS; // number of subsets - int NdOS; // Number of detels per subset = Ndt/NOS - int NbOS; // total number of bins per subset = Nbt/NOS + float rad; // ring radius + float radc; // extended ring radius = radius + crystal thickness - int *order; // order of the angles of projection (array formed by indexs of angles belonging to consecutive subsets) - float sgm_i; // sigma of intrinsic PSF (cm) + int NOS; // number of subsets + int NdOS; // Number of detels per subset = Ndt/NOS + int NbOS; // total number of bins per subset = Nbt/NOS - float *val; - - } prj_mph_type; + int* order; // order of the angles of projection (array formed by indexs of angles belonging to consecutive subsets) + float sgm_i; // sigma of intrinsic PSF (cm) - //... structure for bin information.................................. + float* val; - typedef struct - { +} prj_mph_type; - int Dimx; // number of columns - int Dimy; // number of rows - int Dimz; // number of slices +//... structure for bin information.................................. - int Npix; // number of pixels (voxels) per axial slice - int Nvox; // number of voxels (the whole volume) +typedef struct +{ - 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) + int Dimx; // number of columns + int Dimy; // number of rows + int Dimz; // number of slices - float FOVxcmd2; // half of the size of the volume, dimension x (cm); - float FOVcmyd2; // half of the size of the volume, dimension y (cm); - float FOVzcmd2; // half of the size of the volume, dimension z (cm); + int Npix; // number of pixels (voxels) per axial slice + int Nvox; // number of voxels (the whole volume) - float szcm; // voxel size (side length in cm) - float thcm; // voxel thickness (cm) + 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 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 FOVxcmd2; // half of the size of the volume, dimension x (cm); + float FOVcmyd2; // half of the size of the volume, dimension y (cm); + float FOVzcmd2; // half of the size of the volume, dimension z (cm); - float *val; // array of values - - } volume_type; + float szcm; // voxel size (side length in cm) + float thcm; // voxel thickness (cm) - //... matrix header information ............................ + 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 - typedef struct - { - int subsamp; // bin subsampling factor for accurate PSF and convolution calculations (typically 2 to 5) - float mn_w; // minimum weight to be taken into account - float highres; // high spatial resolution of continous distributions in PSF calculation + float* val; // array of values - float Nsigm; // number of sigmas in PSF calculation - float mndvh2; // squared minimum distance voxel-hole (cm). Reference for efficiency - float ro; // radius of the object +} volume_type; - float max_hsxcm; // maximum hole size dimx (for allocation purposes) - float max_hszcm; // maximum hole size dimz (for allocation purposes) - float max_amp; // maximum amplification - float tmax_aix; // tangent of the maximum incidence angle x (for allocation purposes) - float tmax_aiz; // tangent of the maximum incidence angle z (for allocation purposes) +//... matrix header information ............................ - bool do_psfi; // true: correct for intrinsic PSF - bool do_depth; // true: correct for impact depth - bool do_att; // true: correct for attenuation - bool do_full_att; // true: coef att for each bin of PSF || false: same att factor for all bins of PSF (central line) - bool do_msk_att; // true: to use att map as a mask - bool do_msk_file; // true: explicit mask - - // internal booleans variables +typedef struct +{ + int subsamp; // bin subsampling factor for accurate PSF and convolution calculations (typically 2 to 5) + float mn_w; // minimum weight to be taken into account + float highres; // high spatial resolution of continous distributions in PSF calculation - bool do_subsamp; - bool do_round_cumsum; - bool do_square_cumsum; + float Nsigm; // number of sigmas in PSF calculation + float mndvh2; // squared minimum distance voxel-hole (cm). Reference for efficiency + float ro; // radius of the object - std::string att_fn; // attenuation map filename - std::string msk_fn; // explicit mask filename - std::string detector_fn; // ring parameter filename - std::string collim_fn; // collimator parameter filename + float max_hsxcm; // maximum hole size dimx (for allocation purposes) + float max_hszcm; // maximum hole size dimz (for allocation purposes) + float max_amp; // maximum amplification + float tmax_aix; // tangent of the maximum incidence angle x (for allocation purposes) + float tmax_aiz; // tangent of the maximum incidence angle z (for allocation purposes) - volume_type vol; // structure with information of volume - std::vector detel; // structure with detection elements information - prj_mph_type prj; // structure with detection rings information - mphcoll_type collim; // structure with the collimator information - - } wmh_mph_type; + bool do_psfi; // true: correct for intrinsic PSF + bool do_depth; // true: correct for impact depth + bool do_att; // true: correct for attenuation + bool do_full_att; // true: coef att for each bin of PSF || false: same att factor for all bins of PSF (central line) + bool do_msk_att; // true: to use att map as a mask + bool do_msk_file; // true: explicit mask - //.......weight_mat structure definition. Structure for reading weight matrix + // internal booleans variables - typedef struct - { - //... weight matrix dimensions ..................... + bool do_subsamp; + bool do_round_cumsum; + bool do_square_cumsum; - int ne; //nonzero elements - int Nbt; //dimension 2 (rows) of the weight matrix (NbOS or Nbt) - int Nvox; //dimension 1 (columns) of the weight matrix (Nvox) + std::string att_fn; // attenuation map filename + std::string msk_fn; // explicit mask filename + std::string detector_fn; // ring parameter filename + std::string collim_fn; // collimator parameter filename - //... weight matrix values ......................... + volume_type vol; // structure with information of volume + std::vector detel; // structure with detection elements information + prj_mph_type prj; // structure with detection rings information + mphcoll_type collim; // structure with the collimator information - 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 +} wmh_mph_type; - } wm_type; +//.......weight_mat structure definition. Structure for reading weight matrix - //.......weight_mat_da structure definition. Structure for generating weight matrix +typedef struct +{ + //... weight matrix dimensions ..................... - typedef struct - { - int Nbt; // dimension 2 (rows) of the weight matrix (NbOS or Nbt) - int Nvox; // dimension 1 (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 + int ne; // nonzero elements + int Nbt; // dimension 2 (rows) of the weight matrix (NbOS or Nbt) + int Nvox; // dimension 1 (columns) of the weight matrix (Nvox) - //... filename ............................................. + //... weight matrix values ......................... - std::string fn; // matrix name - std::string fn_hdr; // matrix header file name + 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 - //... format ............................................... +} wm_type; - bool do_save_STIR; // to save weight matrix with STIR format +//.......weight_mat_da structure definition. Structure for generating weight matrix - //... indexs for STIR format ............................... +typedef struct +{ + int Nbt; // dimension 2 (rows) of the weight matrix (NbOS or Nbt) + int Nvox; // dimension 1 (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 - int *na, *nb, *ns; //indexs for projection elements (angle, bin, slice respec.) - short int *nx, *ny, *nz; //indexs for image elements (x,y,z) - - } wm_da_type; + //... filename ............................................. - //.....structure for distribution function information + std::string fn; // matrix name + std::string fn_hdr; // matrix header file name - typedef struct - { - discrf2d_type square; // distribution for square shape hole - discrf2d_type round; // distribution for round shape hole - discrf1d_type cr_att; // exponential to correct for crystal attenuation when do_depth - - } pcf_type; + //... format ............................................... - //.....structure for voxel information + bool do_save_STIR; // to save weight matrix with STIR format - typedef struct - { - int ix; // column index - int iy; // row index - int iz; // slice index - int ip; // inplane index (slice as an array) - int iv; // volume index (considering the volume as an array) of the voxel + //... indexs for 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) + int *na, *nb, *ns; // indexs for projection elements (angle, bin, slice respec.) + short int *nx, *ny, *nz; // indexs for image elements (x,y,z) - float x1; // x coordinate in rotated framework (cm) - float y1; // y coordinate in rotated framework (cm) - - } voxel_type; +} wm_da_type; - //.....structure for bin information +//.....structure for distribution function information - typedef struct - { - 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) - - } bin_type; +typedef struct +{ + discrf2d_type square; // distribution for square shape hole + discrf2d_type round; // distribution for round shape hole + discrf1d_type cr_att; // exponential to correct for crystal attenuation when do_depth - //...... structure for LOR information +} pcf_type; - typedef struct - { - //... all the following distances in cm ..................... +//.....structure for voxel information - float x1d_l; // x coordiante of intersection lor-detection plane in rotated reference system - float z1d_l; // z coordiante of intersection lor-detection plane in rotated reference system - float x1dc_l; // x coordiante of intersection lor-detection plane + crystal in rotated reference system - float z1dc_l; // z coordiante of intersection lor-detection plane + crystal in rotated reference system +typedef struct +{ + int ix; // column index + int iy; // row index + int iz; // slice index + int ip; // inplane index (slice as an array) + int iv; // volume index (considering the volume as an array) of the voxel - float hsxcm_d; // size (cm) of the shadow of the hole at detector plane (x-azis) - float hszcm_d; // size (cm) of the shadow of the hole at detector plane (z-axis) - float hsxcm_d_d2; // half of the size (cm) of the shadow of the hole at detector plane (x-azis) - float hszcm_d_d2; // half of the size (cm) of the shadow of the hole at detector plane (z-axis) + 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 hsxcm_dc; // size (cm) of the shadow of the hole at detector + crystal plane (x-axis) - float hszcm_dc; // size (cm) of the shadow of the hole at detector + crystal plane (z-axis) - float hsxcm_dc_d2; // half of the size (cm) of the shadow of the hole at detector plane (x-azis) - float hszcm_dc_d2; // half of the size (cm) of the shadow of the hole at detector plane (z-axis) + float x1; // x coordinate in rotated framework (cm) + float y1; // y coordinate in rotated framework (cm) - //... others ....................................................... +} voxel_type; - float eff; // effectiveness - - } lor_type; //voxel-hole link +//.....structure for bin information +typedef struct +{ + 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) - //::: functions ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +} bin_type; - //... functions from wmtools_SPECT.cpp ......................................... +//...... structure for LOR information - void wm_alloc ( int * Nitems, wm_da_type &wm, wmh_mph_type &wmh ); // allocate wm +typedef struct +{ + //... all the following distances in cm ..................... - // void free_wm () ; // delete wm + float x1d_l; // x coordiante of intersection lor-detection plane in rotated reference system + float z1d_l; // z coordiante of intersection lor-detection plane in rotated reference system + float x1dc_l; // x coordiante of intersection lor-detection plane + crystal in rotated reference system + float z1dc_l; // z coordiante of intersection lor-detection plane + crystal in rotated reference system + float hsxcm_d; // size (cm) of the shadow of the hole at detector plane (x-azis) + float hszcm_d; // size (cm) of the shadow of the hole at detector plane (z-axis) + float hsxcm_d_d2; // half of the size (cm) of the shadow of the hole at detector plane (x-azis) + float hszcm_d_d2; // half of the size (cm) of the shadow of the hole at detector plane (z-axis) - // void write_wm_FC_mph (); // write double array weight matrix + float hsxcm_dc; // size (cm) of the shadow of the hole at detector + crystal plane (x-axis) + float hszcm_dc; // size (cm) of the shadow of the hole at detector + crystal plane (z-axis) + float hsxcm_dc_d2; // half of the size (cm) of the shadow of the hole at detector plane (x-azis) + float hszcm_dc_d2; // half of the size (cm) of the shadow of the hole at detector plane (z-axis) - // void write_wm_hdr_mph (); // write header of a matrix + //... others ....................................................... - // void write_wm_STIR_mph (); // write matrix in STIR format + float eff; // effectiveness +} lor_type; // voxel-hole link - void read_prj_params_mph ( wmh_mph_type &wmh ); // read ring parameters from a file +//::: functions ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - void read_coll_params_mph ( wmh_mph_type &wmh ); // read collimator parameters from a file +//... functions from wmtools_SPECT.cpp ......................................... - // void which_hole(); +void wm_alloc(int* Nitems, wm_da_type& wm, wmh_mph_type& wmh); // allocate wm +// void free_wm () ; // delete wm - void fill_pcf ( wmh_mph_type &wmh, pcf_type &pcf ); // fill precalculated functions +// void write_wm_FC_mph (); // write double array weight matrix - // void free_pcf (); // fill precalculated functions +// void write_wm_hdr_mph (); // write header of a matrix +// void write_wm_STIR_mph (); // write matrix in STIR format +void read_prj_params_mph(wmh_mph_type& wmh); // read ring parameters from a file - void calc_cumsum ( discrf2d_type *f ); +void read_coll_params_mph(wmh_mph_type& wmh); // read collimator parameters from a file - void generate_msk_mph ( bool *msk_3d, float *att, wmh_mph_type &wmh ); // create a boolean mask for wm (no weights outside the msk) +// void which_hole(); - // void read_msk_file_mph ( bool * msk ); // read mask from a file +void fill_pcf(wmh_mph_type& wmh, pcf_type& pcf); // fill precalculated functions +// void free_pcf (); // fill precalculated functions - std::string wm_SPECT_read_value_1d ( std::ifstream * stream1, char DELIMITER ); +void calc_cumsum(discrf2d_type* f); - void wm_SPECT_read_hvalues_mph ( std::ifstream * stream1, char DELIMITER, int * nh, bool do_cyl, wmh_mph_type &wmh ); +void generate_msk_mph(bool* msk_3d, float* att, wmh_mph_type& wmh); // create a boolean mask for wm (no weights outside the msk) - // void read_att_map_mph ( float *attmap ); // read attenuation map from a file +// void read_msk_file_mph ( bool * msk ); // read mask from a file +std::string wm_SPECT_read_value_1d(std::ifstream* stream1, char DELIMITER); +void wm_SPECT_read_hvalues_mph(std::ifstream* stream1, char DELIMITER, int* nh, bool do_cyl, wmh_mph_type& wmh); - // char *itoa ( int n, char *s); // to convert integer to ascii +// void read_att_map_mph ( float *attmap ); // read attenuation map from a file +// char *itoa ( int n, char *s); // to convert integer to ascii - void error_wmtools_SPECT_mph( int nerr, int ip, std::string txt ); // error messages in wm_SPECT +void error_wmtools_SPECT_mph(int nerr, int ip, std::string txt); // error messages in wm_SPECT -} +} // namespace SPECTUB_mph #endif //_WM_SPECT_H diff --git a/src/include/stir/recon_buildblock/PinholeSPECTUB_Weight3d.h b/src/include/stir/recon_buildblock/PinholeSPECTUB_Weight3d.h index 2e1b08e5a..d8fb7691b 100644 --- a/src/include/stir/recon_buildblock/PinholeSPECTUB_Weight3d.h +++ b/src/include/stir/recon_buildblock/PinholeSPECTUB_Weight3d.h @@ -19,58 +19,55 @@ namespace SPECTUB_mph { - void wm_calculation_mph ( bool do_estim, - const int kOS, - psf2d_type *psf2d_bin, - psf2d_type *psf_subs, - psf2d_type *psf2d_aux, - psf2d_type *kern, - float *attmap, - bool *msk_3d, - int *Nitems, - wmh_mph_type &wmh, - wm_da_type &wm, - pcf_type &pcf ); +void wm_calculation_mph(bool do_estim, + const int kOS, + psf2d_type* psf2d_bin, + psf2d_type* psf_subs, + psf2d_type* psf2d_aux, + psf2d_type* kern, + float* attmap, + bool* msk_3d, + int* Nitems, + wmh_mph_type& wmh, + wm_da_type& wm, + pcf_type& pcf); - //... geometric component ............................................ +//... geometric component ............................................ - bool check_xang_par( voxel_type * vox, hole_type * h); +bool check_xang_par(voxel_type* vox, hole_type* h); - bool check_zang_par( voxel_type * vox, hole_type * h); +bool check_zang_par(voxel_type* vox, hole_type* h); - //bool check_xang_obl( lor_type * l, voxel_type * vox, hole_type * h); +// bool check_xang_obl( lor_type * l, voxel_type * vox, hole_type * h); - //bool check_zang_obl( lor_type * l, voxel_type * vox, hole_type * h); +// bool check_zang_obl( lor_type * l, voxel_type * vox, hole_type * h); - void voxel_projection_mph ( lor_type * l, voxel_type * v, hole_type * h, wmh_mph_type &wmh ); +void voxel_projection_mph(lor_type* l, voxel_type* v, hole_type* h, wmh_mph_type& wmh); +void fill_psfi(psf2d_type* kern, wmh_mph_type& wmh); - void fill_psfi ( psf2d_type * kern, wmh_mph_type &wmh ); +void downsample_psf(psf2d_type* psf_in, psf2d_type* psf_out, int factor, bool do_calc); - void downsample_psf ( psf2d_type * psf_in, psf2d_type * psf_out, int factor, bool do_calc ); +void psf_convol(psf2d_type* psf1, psf2d_type* psf_aux, psf2d_type* psf2, bool do_calc); - void psf_convol( psf2d_type * psf1, psf2d_type * psf_aux, psf2d_type * psf2, bool do_calc ); +float bresenh_f(int i1, int j1, int i2, int j2, float** f, int imax, int jmax, float dcr, wmh_mph_type& wmh, pcf_type& pcf); - float bresenh_f( int i1, int j1, int i2, int j2, float ** f, int imax, int jmax, float dcr, wmh_mph_type &wmh, pcf_type &pcf ); +void fill_psf_geo(psf2d_type* psf2d, lor_type* l, discrf2d_type* f, int factor, bool do_calc, wmh_mph_type& wmh); +void fill_psf_depth(psf2d_type* psf2d, lor_type* l, discrf2d_type* f, int factor, bool do_calc, wmh_mph_type& wmh, pcf_type& pcf); - void fill_psf_geo ( psf2d_type *psf2d, lor_type *l, discrf2d_type *f, int factor, bool do_calc, wmh_mph_type &wmh ); +void psf_convol(psf2d_type* psf2d, psf2d_type* psf_aux, psf2d_type* kern); - void fill_psf_depth ( psf2d_type *psf2d, lor_type *l, discrf2d_type *f, int factor, bool do_calc, wmh_mph_type &wmh, pcf_type &pcf ); +void downsample_psf(psf2d_type* psf_subs, psf2d_type* psf_bin); - void psf_convol ( psf2d_type * psf2d, psf2d_type * psf_aux, psf2d_type * kern ); +//... attenuation................................................... - void downsample_psf ( psf2d_type * psf_subs, psf2d_type * psf_bin ); +float calc_att_mph(bin_type bin, voxel_type vox, float* attmap, wmh_mph_type& wmh); - //... attenuation................................................... +int comp_dist(float dx, float dy, float dz, float dlast); - float calc_att_mph ( bin_type bin, voxel_type vox, float *attmap, wmh_mph_type &wmh ); +void error_weight3d(int nerr, std::string txt); // error messages in weight3d_SPECT - int comp_dist ( float dx, float dy, float dz, float dlast ); - - - void error_weight3d ( int nerr, std::string txt); // error messages in weight3d_SPECT - -} +} // namespace SPECTUB_mph #endif diff --git a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.h b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.h index f2fd54f7b..3c9f65af8 100644 --- a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.h +++ b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.h @@ -38,7 +38,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 @@ -46,21 +46,22 @@ START_NAMESPACE_STIR */ template -class PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData: -public RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMean > +class PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData + : public RegisteredParsingObject, + GeneralisedObjectiveFunction, + PoissonLogLikelihoodWithLinearModelForMean> { - private: - typedef RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMean > base_type; - typedef PoissonLogLikelihoodWithLinearModelForMeanAndProjData > SingleFrameObjFunc ; +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(); @@ -68,38 +69,32 @@ public RegisteredParsingObject get_exam_info_uptr_for_target() const override; - std::unique_ptr - get_exam_info_uptr_for_target() const override; - protected: - double - actual_compute_objective_function_without_penalty(const TargetT& current_estimate, - const int subset_num) override; +protected: + double actual_compute_objective_function_without_penalty(const TargetT& current_estimate, const int subset_num) override; - Succeeded set_up_before_sensitivity(shared_ptr const& target_sptr) override; + Succeeded set_up_before_sensitivity(shared_ptr const& target_sptr) override; //! Add subset sensitivity to existing data /*! \todo Current implementation does NOT add to the subset sensitivity, but overwrites */ - void - add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const override; + void add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const override; - Succeeded - actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, - const TargetT& input, - const int subset_num) const override; + Succeeded actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, + const TargetT& input, + const int subset_num) const override; - Succeeded - actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT &output, - const TargetT ¤t_image_estimate, - const TargetT &input, - const int subset_num) const override; + Succeeded actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, + const TargetT& current_image_estimate, + const TargetT& input, + const int subset_num) const override; - 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. */ //@{ @@ -118,7 +113,7 @@ public RegisteredParsingObject&) override; void set_additive_proj_data_sptr(const shared_ptr&) override; - void set_input_data(const shared_ptr &) override; + void set_input_data(const shared_ptr&) override; const DynamicProjData& get_input_data() const override; //@} - protected: +protected: //! Filename with input projection data std::string _input_filename; @@ -149,7 +144,7 @@ public RegisteredParsingObject _additive_dyn_proj_data_sptr; /*! the normalisation or/and attenuation data */ @@ -166,21 +161,18 @@ 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; @@ -81,13 +78,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(); @@ -96,15 +92,14 @@ 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); @@ -114,7 +109,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); @@ -126,24 +121,29 @@ 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; } - + { + 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; } + { + 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") @@ -151,187 +151,195 @@ post_processing() 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; } - + { + 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 +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; + 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) + 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_ending_frame();++frame_num) + bool frames_are_balanced = true; + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_ending_frame(); + ++frame_num) frames_are_balanced &= this->_single_frame_obj_funcs[frame_num].subsets_are_approximately_balanced(warning_message); return frames_are_balanced; } - else + 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) +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_ending_frame();++frame_num) + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_ending_frame(); + ++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) + 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; + this->num_subsets = num_subsets; return this->num_subsets; } /*************************************************************** set_up() ***************************************************************/ -template -Succeeded -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -set_up_before_sensitivity(shared_ptr const& target_sptr) +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); + 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); - + (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; } + { + 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); + warning("Number of subsets %d should be larger than 0.", this->num_subsets); return Succeeded::no; } @@ -347,185 +355,178 @@ 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_ending_frame()) + if (this->_patlak_plot_sptr->get_starting_frame() <= 0 + || this->_patlak_plot_sptr->get_starting_frame() > this->_patlak_plot_sptr->get_ending_frame()) { - 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_ending_frame()); + 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_ending_frame()); 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_ending_frame()); - - for(unsigned int frame_num=this->_patlak_plot_sptr->get_starting_frame();frame_num<=this->_patlak_plot_sptr->get_ending_frame();++frame_num) + this->_single_frame_obj_funcs.resize(this->_patlak_plot_sptr->get_starting_frame(), + this->_patlak_plot_sptr->get_ending_frame()); + + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_ending_frame(); + ++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_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) + 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] + } //_single_frame_obj_funcs[frame_num] return Succeeded::yes; } -template +template void -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -set_input_data(const shared_ptr & arg) +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::set_input_data(const shared_ptr& arg) { - this->_dyn_proj_data_sptr = dynamic_pointer_cast(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) +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::set_additive_proj_data_sptr( + const shared_ptr& arg) { - this->_additive_dyn_proj_data_sptr = dynamic_pointer_cast(arg); + this->_additive_dyn_proj_data_sptr = dynamic_pointer_cast(arg); } -template +template void -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -set_normalisation_sptr(const shared_ptr& arg) +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::set_normalisation_sptr( + const shared_ptr& arg) { -// this->normalisation_sptr = arg; - error("Not implemeted yet"); + // this->normalisation_sptr = arg; + error("Not implemeted yet"); } - /************************************************************************* functions that compute the value/gradient of the objective function etc *************************************************************************/ -template +template void -PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:: -actual_compute_subset_gradient_without_penalty(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num, - const bool add_sensitivity) +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::actual_compute_subset_gradient_without_penalty( + TargetT& gradient, const TargetT& current_estimate, const int subset_num, const bool add_sensitivity) { - if (subset_num<0 || subset_num>=this->get_num_subsets()) + 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_ending_frame(); + ++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_ending_frame();++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); - 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_ending_frame();++frame_num) + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_ending_frame(); + ++frame_num) { - std::fill(dyn_gradient[frame_num].begin_all(), - dyn_gradient[frame_num].end_all(), - 1.F); + std::fill(dyn_gradient[frame_num].begin_all(), dyn_gradient[frame_num].end_all(), 1.F); - - this->_single_frame_obj_funcs[frame_num]. - actual_compute_subset_gradient_without_penalty(dyn_gradient[frame_num], - dyn_image_estimate[frame_num], - subset_num, - add_sensitivity); + this->_single_frame_obj_funcs[frame_num].actual_compute_subset_gradient_without_penalty( + dyn_gradient[frame_num], dyn_image_estimate[frame_num], subset_num, add_sensitivity); } - 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) +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::actual_compute_objective_function_without_penalty( + const TargetT& current_estimate, const int subset_num) { - assert(subset_num>=0); - assert(subset_numnum_subsets); + 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_ending_frame();++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_ending_frame(); + ++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_ending_frame(); - ++frame_num) + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_ending_frame(); + ++frame_num) { - result += - this->_single_frame_obj_funcs[frame_num]. - compute_objective_function_without_penalty(dyn_image_estimate[frame_num], - subset_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 +PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData::add_subset_sensitivity(TargetT& sensitivity, + const int subset_num) const { - DynamicDiscretisedDensity dyn_sensitivity=this->_dyn_image_template; + 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_ending_frame();++frame_num) + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_ending_frame(); + ++frame_num) { - dyn_sensitivity[frame_num]=this->_single_frame_obj_funcs[frame_num].get_subset_sensitivity(subset_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)) + if (!input.has_same_characteristics(this->get_sensitivity(), explanation)) { warning("PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:\n" "sensitivity and input for add_multiplication_with_approximate_Hessian_without_penalty\n" @@ -533,64 +534,65 @@ actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& 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_ending_frame()); - for(unsigned int frame_num=this->_patlak_plot_sptr->get_starting_frame(); - frame_num<=this->_patlak_plot_sptr->get_ending_frame(); - ++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_ending_frame()); + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_ending_frame(); + ++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(); + 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]; + /*! /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); +#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]; +#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 +#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_ending_frame(); - ++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_ending_frame(); + ++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 @@ -600,103 +602,100 @@ actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& 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; } -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)) - { - warning("PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:\n" - "sensitivity and input for actual_accumulate_sub_Hessian_times_input_without_penalty\n" - "should have the same characteristics.\n%s", - explanation.c_str()); - return Succeeded::no; - } + { + warning("PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData:\n" + "sensitivity and input for actual_accumulate_sub_Hessian_times_input_without_penalty\n" + "should have the same characteristics.\n%s", + explanation.c_str()); + return Succeeded::no; + } 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; - } - + { + 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_ending_frame(); - ++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 + for (unsigned int frame_num = this->_patlak_plot_sptr->get_starting_frame(); + frame_num <= this->_patlak_plot_sptr->get_ending_frame(); + ++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_ending_frame(); - ++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_ending_frame(); + ++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; - } + { + *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 e625385d1..190014398 100644 --- a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMean.h +++ b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMean.h @@ -22,24 +22,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] @@ -57,8 +56,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 @@ -73,7 +72,7 @@ START_NAMESPACE_STIR This method is utilised by the \c OSMAPOSL algorithm. See also \c PoissonLogLikelihoodWithLinearModelForMeanAndListModeData. - + \par Relation with Kullback-Leibler distance Note that up to terms independent of \f$\bar y\f$, the log likelihood @@ -82,14 +81,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 @@ -105,58 +104,51 @@ 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 +class PoissonLogLikelihoodWithLinearModelForMean : public GeneralisedObjectiveFunction { - private: +private: typedef GeneralisedObjectiveFunction base_type; - public: - - //PoissonLogLikelihoodWithLinearModelForMean(); +public: + // PoissonLogLikelihoodWithLinearModelForMean(); - //! Compute the subset gradient of the (unregularised) objective function - /*! - Implementation in terms of actual_compute_sub_gradient_without_penalty() - This function is used by OSSPS may be used by other gradient ascent/descent algorithms + //! Compute the subset gradient of the (unregularised) objective function + /*! + Implementation in terms of actual_compute_sub_gradient_without_penalty() + This function is used by OSSPS may be used by other gradient ascent/descent algorithms - This computes - \f[ - {\partial L \over \partial \lambda_v} = - \sum_b P_{bv} ({y_b \over Y_b} - 1) + This computes + \f[ + {\partial L \over \partial \lambda_v} = + \sum_b P_{bv} ({y_b \over Y_b} - 1) + \f] + (see the class general documentation). + The sum will however be restricted to a subset. + */ + void compute_sub_gradient_without_penalty(TargetT& gradient, const TargetT& current_estimate, const int subset_num) override; + + //! This should compute the subset gradient of the (unregularised) objective function plus the subset sensitivity + /*! + Implementation in terms of actual_compute_sub_gradient_without_penalty(). + This function is used for instance by OSMAPOSL. + + This computes + \f[ {\partial L \over \partial \lambda_v} + P_v = + \sum_b P_{bv} {y_b \over Y_b} \f] - (see the class general documentation). - The sum will however be restricted to a subset. - */ - void - compute_sub_gradient_without_penalty(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num) override; - - //! This should compute the subset gradient of the (unregularised) objective function plus the subset sensitivity - /*! - Implementation in terms of actual_compute_sub_gradient_without_penalty(). - This function is used for instance by OSMAPOSL. - - This computes - \f[ {\partial L \over \partial \lambda_v} + P_v = - \sum_b P_{bv} {y_b \over Y_b} - \f] - (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); + (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& current_estimate, const int subset_num); //! 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 @@ -167,7 +159,7 @@ public GeneralisedObjectiveFunction Calls set_up_before_sensitivity(). */ - Succeeded set_up(shared_ptr const& target_sptr) override; + Succeeded set_up(shared_ptr const& target_sptr) override; //! Get a const reference to the total sensitivity const TargetT& get_sensitivity() const; @@ -175,12 +167,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; @@ -201,7 +192,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. */ //@{ @@ -227,24 +218,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 override; - - private: + void fill_nonidentifiable_target_parameters(TargetT& target, const float value) const override; +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 @@ -254,13 +242,12 @@ 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(); @@ -280,20 +267,19 @@ public GeneralisedObjectiveFunction \sum_b P_{bv} ({y_b \over Y_b} - 1) \f] */ - virtual void - actual_compute_subset_gradient_without_penalty(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num, - const bool add_sensitivity) = 0; + virtual void actual_compute_subset_gradient_without_penalty(TargetT& gradient, + const TargetT& current_estimate, + const int subset_num, + const bool add_sensitivity) + = 0; - //! 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. */ void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h index 657270e11..7b1aa7613 100644 --- a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h +++ b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h @@ -4,7 +4,7 @@ Copyright (C) 2018, University College London SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details */ /*! @@ -35,40 +35,40 @@ 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 > +class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion + : public RegisteredParsingObject, + GeneralisedObjectiveFunction, + PoissonLogLikelihoodWithLinearModelForMean> { - private: - typedef RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMean > base_type; - typedef PoissonLogLikelihoodWithLinearModelForMeanAndProjData > SingleGateObjFunc ; +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(); @@ -76,39 +76,32 @@ public RegisteredParsingObject const& target_sptr) override; + Succeeded set_up_before_sensitivity(shared_ptr const& target_sptr) override; //! Add subset sensitivity to existing data - void - add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const override; + void add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const override; - Succeeded - actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, - const TargetT& input, - const int subset_num) const override; - Succeeded - actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT &output, - const TargetT ¤t_image_estimate, - const TargetT &input, - const int subset_num) const override; + Succeeded actual_add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, + const TargetT& input, + const int subset_num) const override; + Succeeded actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, + const TargetT& current_image_estimate, + const TargetT& input, + const int subset_num) const override; - 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. */ //@{ @@ -127,7 +120,7 @@ public RegisteredParsingObject&) override; void set_additive_proj_data_sptr(const shared_ptr&) override; - void set_input_data(const shared_ptr &) override; + void set_input_data(const shared_ptr&) override; const GatedProjData& get_input_data() const override; //@} - protected: +protected: //! Filename with input projection data std::string _input_filename; std::string _motion_vectors_filename_prefix; @@ -155,8 +148,7 @@ public RegisteredParsingObject target_parameter_parser; @@ -178,7 +170,8 @@ public RegisteredParsingObject -#include +#include // For Motion #include "stir/spatial_transformation/GatedSpatialTransformation.h" #include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h" @@ -48,65 +48,55 @@ 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); @@ -116,43 +106,43 @@ 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; } - + { + 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); + 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->_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); @@ -165,255 +155,260 @@ post_processing() } template -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion() +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion< + TargetT>::PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion() { this->set_defaults(); } template -TargetT * -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -construct_target_ptr() const +TargetT* +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::construct_target_ptr() const { - return - this->target_parameter_parser.create(this->get_input_data()); + 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) + "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) + 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 + 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 new_num_subsets) +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_num_subsets(const int new_num_subsets) { this->already_set_up = this->already_set_up && (this->num_subsets == new_num_subsets); - for(unsigned int gate_num=1;gate_num<=this->get_time_gate_definitions().get_num_gates();++gate_num) + 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(new_num_subsets) != new_num_subsets) - error("set_num_subsets didn't work"); + if (this->_single_gate_obj_funcs.size() != 0) + if (this->_single_gate_obj_funcs[gate_num].set_num_subsets(new_num_subsets) != new_num_subsets) + error("set_num_subsets didn't work"); } - this->num_subsets=new_num_subsets; + this->num_subsets = new_num_subsets; return this->num_subsets; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_time_gate_definitions(const TimeGateDefinitions & time_gate_definitions) +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_time_gate_definitions( + const TimeGateDefinitions& time_gate_definitions) { this->already_set_up = false; - this->_time_gate_definitions=time_gate_definitions; + this->_time_gate_definitions = time_gate_definitions; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_input_data(const shared_ptr & arg) +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_input_data(const shared_ptr& arg) { this->already_set_up = false; - this->_gated_proj_data_sptr = dynamic_pointer_cast(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) +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_additive_proj_data_sptr( + const shared_ptr& arg) { this->already_set_up = false; - this->_additive_gated_proj_data_sptr = dynamic_pointer_cast(arg); + this->_additive_gated_proj_data_sptr = dynamic_pointer_cast(arg); } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_normalisation_sptr(const shared_ptr& arg) +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_normalisation_sptr( + const shared_ptr& arg) { this->already_set_up = false; -// this->normalisation_sptr = arg; - error("Not implemeted yet"); + // this->normalisation_sptr = arg; + error("Not implemeted yet"); } /*************************************************************** set_up() ***************************************************************/ -template -Succeeded -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -set_up_before_sensitivity(shared_ptr const& target_sptr) +template +Succeeded +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::set_up_before_sensitivity( + shared_ptr const& target_sptr) { - /*!todo define in the PoissonLogLikelihoodWithLinearModelForMean class to return Succeeded::yes + /*!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); + 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); - + (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; } + { + 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); + 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) + 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[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!"); } - }//_single_gate_obj_funcs[gate_num] + } //_single_gate_obj_funcs[gate_num] return Succeeded::yes; } @@ -421,182 +416,162 @@ set_up_before_sensitivity(shared_ptr const& target_sptr) functions that compute the value/gradient of the objective function etc *************************************************************************/ -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:: -actual_compute_subset_gradient_without_penalty(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num, - const bool add_sensitivity) +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::actual_compute_subset_gradient_without_penalty( + TargetT& gradient, const TargetT& current_estimate, const int subset_num, const bool add_sensitivity) { - assert(subset_num>=0); - assert(subset_numnum_subsets); + 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; + 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]. - actual_compute_subset_gradient_without_penalty(gated_gradient[gate_num], - gated_image_estimate[gate_num], - subset_num, - add_sensitivity); - } + 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].actual_compute_subset_gradient_without_penalty( + gated_gradient[gate_num], gated_image_estimate[gate_num], subset_num, add_sensitivity); + } // 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) +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::actual_compute_objective_function_without_penalty( + const TargetT& current_estimate, const int subset_num) { - assert(subset_num>=0); - assert(subset_numnum_subsets); + 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) + 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); + 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 +PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion::add_subset_sensitivity(TargetT& sensitivity, + const int subset_num) const { - GatedDiscretisedDensity gated_subset_sensitivity=this->_gated_image_template; + 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) + 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); + 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)) + 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; + 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) + } + 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]; + 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. + 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)) - { - warning("PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:\n" - "sensitivity and input for actual_accumulate_sub_Hessian_times_input_without_penalty\n" - "should have the same characteristics.\n%s", - explanation.c_str()); - return Succeeded::no; - } + { + warning("PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion:\n" + "sensitivity and input for actual_accumulate_sub_Hessian_times_input_without_penalty\n" + "should have the same characteristics.\n%s", + explanation.c_str()); + return Succeeded::no; + } 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", - explanation.c_str()); - return Succeeded::no; - } + { + 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", + explanation.c_str()); + return Succeeded::no; + } } - 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); - } // end of loop over gates + 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 8d5966b1f..cf3aab520 100644 --- a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.h +++ b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.h @@ -13,7 +13,7 @@ /*! \file \ingroup GeneralisedObjectiveFunction - \brief Declaration of class + \brief Declaration of class stir::PoissonLogLikelihoodWithLinearModelForMeanAndListModeData \author Kris Thielemans @@ -24,7 +24,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" @@ -39,7 +38,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 @@ -62,99 +61,94 @@ START_NAMESPACE_STIR */ template -class PoissonLogLikelihoodWithLinearModelForMeanAndListModeData: -public PoissonLogLikelihoodWithLinearModelForMean +class PoissonLogLikelihoodWithLinearModelForMeanAndListModeData : public PoissonLogLikelihoodWithLinearModelForMean { -private: - +private: typedef PoissonLogLikelihoodWithLinearModelForMean base_type; -public: +public: + PoissonLogLikelihoodWithLinearModelForMeanAndListModeData(); + + // virtual TargetT * construct_target_ptr(); + + Succeeded set_up_before_sensitivity(shared_ptr const& target_sptr) override; - - PoissonLogLikelihoodWithLinearModelForMeanAndListModeData(); - - //virtual TargetT * construct_target_ptr(); - - Succeeded - set_up_before_sensitivity(shared_ptr const& target_sptr) override; - //! 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; - - void set_normalisation_sptr(const shared_ptr&) override; - void set_additive_proj_data_sptr(const shared_ptr&) override; - - void set_input_data(const shared_ptr &) override; - const ListModeData& get_input_data() const override; - //! set maximum segment_number (in listmode data) to process - /*! minimum will be -max_segment_num_to_process - - Use -1 to process all. - */ - void set_max_segment_num_to_process(int); - //! get maximum segment_number (from listmode data) to process - /*! \see set_max_segment_num_to_process */ - int get_max_segment_num_to_process() const; - - /*! \name caching-related methods - These functions can be used to cache listmode events into memory, allowing - parallelised processing. - - Currently, the cached data is written to one or more files (\see get_cache_filename) - \warning This code is experimental and likely to change in future versions. - \warning When re-using an existing cache, there is no check if time-frames etc are - the same as what was used when creating the cache. This is therefore quite risky. - \warning Cache-files are written in a binary format that likely depends on compiler, endianness etc. - \todo It should be possible to read only part of the cache in memory. - */ - //@{ - //! Set the directory where data will be cached - /*! - \param cache_path directory-name (defaults to current directory). The directory has to exist. - */ - virtual void set_cache_path(const std::string& cache_path); - //! Get the directory where data will be cached - virtual std::string get_cache_path() const; - - //! Get the filename for a cache file - /*! - Filenames are currently "my_CACHE%d.bin" with get_cache_path() prepended. - */ - virtual std::string get_cache_filename(unsigned int icache) const; - - //! Set if existing cache files should be used or not - /*! defaults to \c true */ - void set_recompute_cache(bool); - bool get_recompute_cache() const; - - //! Skip reading of listmode file entirely, only read from cache (broken!) - /*! - \warning This currently aborts, as functionality is broken. (We would need to be - able to read proj_data_info and exam_info). - \todo replace with reading from a custom-listmode file (although this - would have to support the additive term). - */ - void set_skip_lm_input_file(const bool arg); - - //! Set maximum size (in bytes) of cache in memory - /*! When all events do not fit in the cache, several cache files will be used. - - As multi-threading occurs over cached events, it is likely that better performance - will be obtained with a large cache size. - */ - virtual void set_cache_max_size(const unsigned long int arg); - - //! Get maximum size (in bytes) of cache - virtual unsigned long int get_cache_max_size() const; - - //@} + TimeFrameDefinitions frame_defs; + + void set_normalisation_sptr(const shared_ptr&) override; + void set_additive_proj_data_sptr(const shared_ptr&) override; + + void set_input_data(const shared_ptr&) override; + const ListModeData& get_input_data() const override; + //! set maximum segment_number (in listmode data) to process + /*! minimum will be -max_segment_num_to_process + + Use -1 to process all. + */ + void set_max_segment_num_to_process(int); + //! get maximum segment_number (from listmode data) to process + /*! \see set_max_segment_num_to_process */ + int get_max_segment_num_to_process() const; + + /*! \name caching-related methods + These functions can be used to cache listmode events into memory, allowing + parallelised processing. + + Currently, the cached data is written to one or more files (\see get_cache_filename) + \warning This code is experimental and likely to change in future versions. + \warning When re-using an existing cache, there is no check if time-frames etc are + the same as what was used when creating the cache. This is therefore quite risky. + \warning Cache-files are written in a binary format that likely depends on compiler, endianness etc. + \todo It should be possible to read only part of the cache in memory. + */ + //@{ + //! Set the directory where data will be cached + /*! + \param cache_path directory-name (defaults to current directory). The directory has to exist. + */ + virtual void set_cache_path(const std::string& cache_path); + //! Get the directory where data will be cached + virtual std::string get_cache_path() const; + + //! Get the filename for a cache file + /*! + Filenames are currently "my_CACHE%d.bin" with get_cache_path() prepended. + */ + virtual std::string get_cache_filename(unsigned int icache) const; + + //! Set if existing cache files should be used or not + /*! defaults to \c true */ + void set_recompute_cache(bool); + bool get_recompute_cache() const; + + //! Skip reading of listmode file entirely, only read from cache (broken!) + /*! + \warning This currently aborts, as functionality is broken. (We would need to be + able to read proj_data_info and exam_info). + \todo replace with reading from a custom-listmode file (although this + would have to support the additive term). + */ + void set_skip_lm_input_file(const bool arg); + + //! Set maximum size (in bytes) of cache in memory + /*! When all events do not fit in the cache, several cache files will be used. + + As multi-threading occurs over cached events, it is likely that better performance + will be obtained with a large cache size. + */ + virtual void set_cache_max_size(const unsigned long int arg); + + //! Get maximum size (in bytes) of cache + virtual unsigned long int get_cache_max_size() const; + + //@} protected: std::string frame_defs_filename; @@ -168,57 +162,57 @@ public PoissonLogLikelihoodWithLinearModelForMean bool reduce_memory_usage; 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 */ void set_defaults() override; //! sets keys /*! Has to be called by initialise_keymap in the leaf-class */ - void initialise_keymap() override; - - bool post_processing() override; - - //! 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; - - //! This is the number of records to be cached. If this parameter is more than zero, then the - //! flag cache_lm_file will be set to true. The listmode file up to this size will be loaded in - //! the RAM, alongside with any additive sinograms. - unsigned long int cache_size; - //! This flag is true when cache_size is more than zero. - bool cache_lm_file; - //! On the first cached run, the cache will be written in the cache_path. - //! If recompute_cache is set to zero then every consecutive reconstruction will use that cache file. - //! If you want to create a new, either delete the previous or set this 1. \todo multiple cache files - //! need to be supported! - bool recompute_cache; - //! This flag is set when we don't set an input lm filename and rely only on the cache file. - bool skip_lm_input_file; - //! Path to read/write the cached listmode file. \todo add the ability to set a filename. - std::string cache_path; - //! The data set has additive corrections - bool has_add; + void initialise_keymap() override; + + bool post_processing() override; + + //! 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; + + //! This is the number of records to be cached. If this parameter is more than zero, then the + //! flag cache_lm_file will be set to true. The listmode file up to this size will be loaded in + //! the RAM, alongside with any additive sinograms. + unsigned long int cache_size; + //! This flag is true when cache_size is more than zero. + bool cache_lm_file; + //! On the first cached run, the cache will be written in the cache_path. + //! If recompute_cache is set to zero then every consecutive reconstruction will use that cache file. + //! If you want to create a new, either delete the previous or set this 1. \todo multiple cache files + //! need to be supported! + bool recompute_cache; + //! This flag is set when we don't set an input lm filename and rely only on the cache file. + bool skip_lm_input_file; + //! Path to read/write the cached listmode file. \todo add the ability to set a filename. + std::string cache_path; + //! The data set has additive corrections + bool has_add; //! ProjDataInfo /*! normally a copy of the one from the listmode file, but could be reduced in size */ shared_ptr proj_data_info_sptr; - private: + +private: //! maximum segment_number (from listmode data) to process /*! \see set_max_segment_num_to_process */ int max_segment_num_to_process; - }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.h b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.h index f070dc000..921fddbd6 100644 --- a/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.h +++ b/src/include/stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.h @@ -23,7 +23,6 @@ #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" @@ -56,23 +55,22 @@ 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; + //! Name which will be used when parsing a GeneralisedObjectiveFunction object + static const char* const registered_name; PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin(); @@ -81,19 +79,17 @@ typedef RegisteredParsingObjectadd_sensitivity = false and use_subset_sensitivities = false will return an error because the gradient will not be correct. Try use_subset_sensitivities = true. */ - - void actual_compute_subset_gradient_without_penalty(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num, - const bool add_sensitivity) override; - TargetT * construct_target_ptr() const override; + void actual_compute_subset_gradient_without_penalty(TargetT& gradient, + const TargetT& current_estimate, + const int subset_num, + const bool add_sensitivity) override; + + TargetT* construct_target_ptr() const override; int set_num_subsets(const int new_num_subsets) override; - const shared_ptr & - get_normalisation_sptr() const - { return this->normalisation_sptr; } + const shared_ptr& get_normalisation_sptr() const { return this->normalisation_sptr; } unique_ptr get_exam_info_uptr_for_target() const override; @@ -108,26 +104,22 @@ typedef RegisteredParsingObject const& target_sptr) override; + Succeeded set_up_before_sensitivity(shared_ptr const& target_sptr) override; - void - add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const override; + void add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const override; -#if STIR_VERSION < 060000 +#if STIR_VERSION < 060000 //! Maximum ring difference to take into account /*! @deprecated */ - int max_ring_difference_num_to_process; + int max_ring_difference_num_to_process; #endif - + //! Triggers calculation of sensitivity using time-of-flight bool use_tofsens; @@ -155,14 +147,13 @@ typedef RegisteredParsingObject record_cache; + std::vector record_cache; - //! This function caches the listmode file, or reads it. It is run during set_up() + //! This function caches the listmode file, or reads it. It is run during set_up() /*! \todo Move this function higher-up in the hierarchy as it doesn't depend on ProjMatrixByBin */ Succeeded cache_listmode_file(); @@ -171,8 +162,6 @@ typedef RegisteredParsingObjectnot \f$r\f$). @@ -101,9 +99,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 := @@ -120,33 +118,32 @@ class DistributedCachingInformation; \endverbatim */ template -class PoissonLogLikelihoodWithLinearModelForMeanAndProjData: -public RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMean > +class PoissonLogLikelihoodWithLinearModelForMeanAndProjData + : public RegisteredParsingObject, + GeneralisedObjectiveFunction, + PoissonLogLikelihoodWithLinearModelForMean> { - private: +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; @@ -155,7 +152,6 @@ public RegisteredParsingObject&) override; - 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&); void set_normalisation_sptr(const shared_ptr&) override; - void set_input_data(const shared_ptr &) override; + void set_input_data(const shared_ptr&) override; const ProjData& get_input_data() const override; -//@} - - void - actual_compute_subset_gradient_without_penalty(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num, - const bool add_sensitivity) override; + //@} - std::unique_ptr - get_exam_info_uptr_for_target() const override; + void actual_compute_subset_gradient_without_penalty(TargetT& gradient, + const TargetT& current_estimate, + const int subset_num, + const bool add_sensitivity) override; + + std::unique_ptr get_exam_info_uptr_for_target() const override; #if 0 // currently not used float sum_projection_data() const; #endif - void - add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const override; + void add_subset_sensitivity(TargetT& sensitivity, const int subset_num) const override; - protected: - Succeeded - set_up_before_sensitivity(shared_ptr const& target_sptr) override; +protected: + Succeeded set_up_before_sensitivity(shared_ptr const& target_sptr) override; - double - actual_compute_objective_function_without_penalty(const TargetT& current_estimate, - const int subset_num) override; + double actual_compute_objective_function_without_penalty(const TargetT& current_estimate, const int subset_num) override; /*! The Hessian (without penalty) is approximately given by: @@ -249,19 +238,19 @@ public RegisteredParsingObject target_parameter_parser; + ParseAndCreateFrom target_parameter_parser; /********************************/ - //! Stores the projectors that are used for the computations shared_ptr projector_pair_ptr; @@ -330,18 +316,17 @@ public RegisteredParsingObject 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; @@ -358,17 +343,18 @@ public RegisteredParsingObject symmetries_sptr; /*! \name variables/methods for TOF sensitivity processing @@ -410,7 +396,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() override; + ~PostsmoothingBackProjectorByBin() override; //! 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. - */ - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; + */ + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; - - 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 override; + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const override; BackProjectorByBin* get_original_back_projector_ptr() const; PostsmoothingBackProjectorByBin* clone() const override; private: - shared_ptr original_back_projector_ptr; #ifdef STIR_PROJECTORS_AS_V3 - void actual_back_project(DiscretisedDensity<3,float>&, + 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); + 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, - const int min_tangential_pos_num, const int max_tangential_pos_num) override; - - void actual_back_project(DiscretisedDensity<3,float>& density, - const Bin& bin); + const int min_axial_pos_num, + const int max_axial_pos_num, + const int min_tangential_pos_num, + const int max_tangential_pos_num) override; - shared_ptr > filtered_density_sptr; + void actual_back_project(DiscretisedDensity<3, float>& density, const Bin& bin); + shared_ptr> filtered_density_sptr; void set_defaults() override; void initialise_keymap() override; diff --git a/src/include/stir/recon_buildblock/PresmoothingForwardProjectorByBin.h b/src/include/stir/recon_buildblock/PresmoothingForwardProjectorByBin.h index 7fea9c543..c33455e78 100644 --- a/src/include/stir/recon_buildblock/PresmoothingForwardProjectorByBin.h +++ b/src/include/stir/recon_buildblock/PresmoothingForwardProjectorByBin.h @@ -25,71 +25,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() override; + ~PresmoothingForwardProjectorByBin() override; //! 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. - */ - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; + */ + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; - - 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 override; + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const override; 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, - const int min_tangential_pos_num, const int max_tangential_pos_num) override; + const int min_axial_pos_num, + const int max_axial_pos_num, + const int min_tangential_pos_num, + const int max_tangential_pos_num) override; #if 0 // disabled as currently not used. needs to be written in the new style anyway void actual_forward_project(Bin&, diff --git a/src/include/stir/recon_buildblock/PriorWithParabolicSurrogate.h b/src/include/stir/recon_buildblock/PriorWithParabolicSurrogate.h index 57dea783d..6cd1d1a80 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 */ @@ -18,7 +18,6 @@ See STIR/LICENSE.txt for details */ - #ifndef __stir_recon_buildblock_PriorWithParabolicSurrogate_H__ #define __stir_recon_buildblock_PriorWithParabolicSurrogate_H__ @@ -31,28 +30,22 @@ 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 @@ -61,10 +54,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 e6cae6643..e5697f6a7 100644 --- a/src/include/stir/recon_buildblock/ProjDataRebinning.h +++ b/src/include/stir/recon_buildblock/ProjDataRebinning.h @@ -11,17 +11,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" @@ -33,7 +32,6 @@ START_NAMESPACE_STIR - class Succeeded; /*! @@ -47,8 +45,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. @@ -64,33 +62,29 @@ 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 ~ProjDataRebinning() override; - + //! 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 @@ -112,19 +106,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; @@ -145,17 +138,14 @@ class ProjDataRebinning : #endif //! used to check acceptable parameter ranges, etc... - bool post_processing() override; + bool post_processing() override; void set_defaults() override; void initialise_keymap() override; - 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 f07728e71..a980b6219 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixByBin.h +++ b/src/include/stir/recon_buildblock/ProjMatrixByBin.h @@ -4,9 +4,9 @@ /*! \file - \ingroup projection + \ingroup projection \brief declaration of stir::ProjMatrixByBin and its helpers classes - + \author Nikos Efthimiou \author Mustapha Sadki \author Kris Thielemans @@ -39,29 +39,29 @@ //#include #include #ifdef STIR_OPENMP -#include +# include #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 @@ -72,48 +72,42 @@ 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: - ~ProjMatrixByBin() override {} //! 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 + 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&) const; + inline void get_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&, const Bin&) const; #if 0 // TODO @@ -124,19 +118,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; @@ -144,30 +138,27 @@ class ProjMatrixByBin : // void reserve_num_elements_in_cache(const std::size_t); //! Remove all elements from the cache void clear_cache() 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 */ void set_defaults() override; @@ -177,37 +168,33 @@ class ProjMatrixByBin : //! Checks if parameters have sensible values /*! Has to be called by post_processing in the leaf-class */ bool post_processing() override; - + /////////////////////////////// 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; + 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&) - const; + void cache_proj_matrix_elems_for_one_bin(const ProjMatrixElemsForOneBin&) const; private: - typedef std::uint64_t CacheKey; //! \name bit-field sizes for the cache key // note: sum needs to be less than 64 - 3 (for the 3 sign bits) @@ -217,16 +204,14 @@ class ProjMatrixByBin : const CacheKey timing_pos_bits = 20; //@} // typedef std::map MapProjMatrixElemsForOneBin; - typedef std::unordered_map MapProjMatrixElemsForOneBin; + typedef std::unordered_map MapProjMatrixElemsForOneBin; typedef MapProjMatrixElemsForOneBin::iterator MapProjMatrixElemsForOneBinIterator; typedef MapProjMatrixElemsForOneBin::const_iterator const_MapProjMatrixElemsForOneBinIterator; - - //! collection of ProjMatrixElemsForOneBin (internal cache ) - mutable - VectorWithOffset > cache_collection; + + //! collection of ProjMatrixElemsForOneBin (internal cache ) + mutable VectorWithOffset> cache_collection; #ifdef STIR_OPENMP - mutable - VectorWithOffset > cache_locks; + mutable VectorWithOffset> cache_locks; #endif //! create the key for caching @@ -236,7 +221,7 @@ class ProjMatrixByBin : //! Activates the application of the timing kernel to the LOR //! and performs initial set_up(). //! \warning Must be called during set_up() - void enable_tof(const shared_ptr& proj_data_info_sptr,const bool v = true); + 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; @@ -246,23 +231,15 @@ class ProjMatrixByBin : //! The function which actually applies the TOF kernel on the LOR. inline void apply_tof_kernel(ProjMatrixElemsForOneBin& probabilities) const; - - //! Get the interal value erf(m - v_j) - erf(m -v_j) inline float get_tof_value(const float d1, const float d2) const; //! erf map FastErf erf_interpolation; - }; - - END_NAMESPACE_STIR #include "stir/recon_buildblock/ProjMatrixByBin.inl" #endif // __ProjMatrixByBin_H__ - - - diff --git a/src/include/stir/recon_buildblock/ProjMatrixByBin.inl b/src/include/stir/recon_buildblock/ProjMatrixByBin.inl index 5fed0c3e8..7ff4ac153 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixByBin.inl +++ b/src/include/stir/recon_buildblock/ProjMatrixByBin.inl @@ -8,7 +8,7 @@ \brief Implementations of inline functions for class stir::ProjMatrixByBin \author Nikos Efthimiou - \author Mustapha Sadki + \author Mustapha Sadki \author Kris Thielemans \author Robert Twyman \author PARAPET project @@ -33,84 +33,81 @@ START_NAMESPACE_STIR const DataSymmetriesForBins* -ProjMatrixByBin:: get_symmetries_ptr() const +ProjMatrixByBin::get_symmetries_ptr() const { - return symmetries_sptr.get(); + return symmetries_sptr.get(); } const shared_ptr -ProjMatrixByBin:: get_symmetries_sptr() const +ProjMatrixByBin::get_symmetries_sptr() const { - return symmetries_sptr; + return symmetries_sptr; } -inline void -ProjMatrixByBin:: -get_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& probabilities, - const Bin& bin) const -{ +inline void +ProjMatrixByBin::get_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& probabilities, const Bin& bin) const +{ // start_timers(); TODO, can't do this in a const member - + // set to empty probabilities.erase(); if (cache_stores_only_basic_bins) - { - // find symmetry operator and 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) - { - // basic bin is not in cache, compute lor probabilities for the basic bin - calculate_proj_matrix_elems_for_one_bin(probabilities); -#ifndef NDEBUG - probabilities.check_state(); -#endif - if (proj_data_info_sptr->is_tof_data() && this->tof_enabled) - { // Apply TOF kernel to basic bin - apply_tof_kernel(probabilities); - } - cache_proj_matrix_elems_for_one_bin(probabilities); - } - - // now transform to original bin (inc. TOF) - symm_ptr->transform_proj_matrix_elems_for_one_bin(probabilities); - } - else - { // !cache_stores_only_basic_bins - probabilities.set_bin(bin); - // if bin is in the cache, get the probabilities - if (get_cached_proj_matrix_elems_for_one_bin(probabilities) == Succeeded::no) { - // bin probabilities not in the cache, check if basic bins are - // find basic bin + // find symmetry operator and 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); + probabilities.set_bin(basic_bin); // check if basic bin is in cache if (get_cached_proj_matrix_elems_for_one_bin(probabilities) == Succeeded::no) - { - // basic bin is not in cache, compute lor probabilities for the basic bin - calculate_proj_matrix_elems_for_one_bin(probabilities); + { + // basic bin is not in cache, compute lor probabilities for the basic bin + calculate_proj_matrix_elems_for_one_bin(probabilities); #ifndef NDEBUG - probabilities.check_state(); + probabilities.check_state(); #endif - if (proj_data_info_sptr->is_tof_data() && this->tof_enabled) - { // Apply TOF kernel to basic bin - apply_tof_kernel(probabilities); + if (proj_data_info_sptr->is_tof_data() && this->tof_enabled) + { // Apply TOF kernel to basic bin + apply_tof_kernel(probabilities); + } + cache_proj_matrix_elems_for_one_bin(probabilities); } - } - // now transform basic bin probabilities into original bin probabilities + + // now transform to original bin (inc. TOF) symm_ptr->transform_proj_matrix_elems_for_one_bin(probabilities); - // cache the probabilities for bin - cache_proj_matrix_elems_for_one_bin(probabilities); } - - } + else + { // !cache_stores_only_basic_bins + probabilities.set_bin(bin); + // if bin is in the cache, get the probabilities + if (get_cached_proj_matrix_elems_for_one_bin(probabilities) == Succeeded::no) + { + // bin probabilities not in the cache, check if basic bins are + // find 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) + { + // basic bin is not in cache, compute lor probabilities for the basic bin + calculate_proj_matrix_elems_for_one_bin(probabilities); +#ifndef NDEBUG + probabilities.check_state(); +#endif + if (proj_data_info_sptr->is_tof_data() && this->tof_enabled) + { // Apply TOF kernel to basic bin + apply_tof_kernel(probabilities); + } + } + // now transform basic bin probabilities into original bin probabilities + symm_ptr->transform_proj_matrix_elems_for_one_bin(probabilities); + // cache the probabilities for bin + cache_proj_matrix_elems_for_one_bin(probabilities); + } + } // stop_timers(); TODO, can't do this in a const member } @@ -118,38 +115,38 @@ void ProjMatrixByBin::apply_tof_kernel(ProjMatrixElemsForOneBin& probabilities) const { - LORInAxialAndNoArcCorrSinogramCoordinates lor; - proj_data_info_sptr->get_LOR(lor, probabilities.get_bin()); - const LORAs2Points lor2(lor); - const CartesianCoordinate3D point1 = lor2.p1(); - const CartesianCoordinate3D point2 = lor2.p2(); + LORInAxialAndNoArcCorrSinogramCoordinates lor; + proj_data_info_sptr->get_LOR(lor, probabilities.get_bin()); + const LORAs2Points lor2(lor); + const CartesianCoordinate3D point1 = lor2.p1(); + const CartesianCoordinate3D point2 = lor2.p2(); - // 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 CartesianCoordinate3D diff_unit_vector(diff/static_cast(norm(diff))); + // 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 CartesianCoordinate3D diff_unit_vector(diff / static_cast(norm(diff))); - for (ProjMatrixElemsForOneBin::iterator element_ptr = probabilities.begin(); - element_ptr != probabilities.end(); ++element_ptr) + for (ProjMatrixElemsForOneBin::iterator element_ptr = probabilities.begin(); element_ptr != probabilities.end(); ++element_ptr) { - Coordinate3D c(element_ptr->get_coords()); - const float d2 = -inner_product(image_info_sptr->get_physical_coordinates_for_indices (c) - middle, diff_unit_vector); + Coordinate3D c(element_ptr->get_coords()); + const float d2 = -inner_product(image_info_sptr->get_physical_coordinates_for_indices(c) - middle, diff_unit_vector); - const float low_dist = ((proj_data_info_sptr->tof_bin_boundaries_mm[probabilities.get_bin().timing_pos_num()].low_lim - d2)); - const float high_dist = ((proj_data_info_sptr->tof_bin_boundaries_mm[probabilities.get_bin().timing_pos_num()].high_lim - d2)); + const float low_dist + = ((proj_data_info_sptr->tof_bin_boundaries_mm[probabilities.get_bin().timing_pos_num()].low_lim - d2)); + const float high_dist + = ((proj_data_info_sptr->tof_bin_boundaries_mm[probabilities.get_bin().timing_pos_num()].high_lim - d2)); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c,element_ptr->get_value() * get_tof_value(low_dist, high_dist)); + *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value() * get_tof_value(low_dist, high_dist)); } } float -ProjMatrixByBin:: -get_tof_value(const float d1, const float d2) const +ProjMatrixByBin::get_tof_value(const float d1, const float d2) const { const float d1_n = d1 * r_sqrt2_gauss_sigma; const float d2_n = d2 * r_sqrt2_gauss_sigma; - if ((d1_n >= 4.f && d2_n >= 4.f) || (d1_n <= -4.f && d2_n <= -4.f)) + if ((d1_n >= 4.f && d2_n >= 4.f) || (d1_n <= -4.f && d2_n <= -4.f)) return 0.F; else return 0.5f * (erf_interpolation(d2_n) - erf_interpolation(d1_n)); diff --git a/src/include/stir/recon_buildblock/ProjMatrixByBinFromFile.h b/src/include/stir/recon_buildblock/ProjMatrixByBinFromFile.h index f625f5f25..c1fbded69 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixByBinFromFile.h +++ b/src/include/stir/recon_buildblock/ProjMatrixByBinFromFile.h @@ -12,7 +12,7 @@ \file \ingroup projection - \brief stir::ProjMatrixByBinFromFile's definition + \brief stir::ProjMatrixByBinFromFile's definition \author Kris Thielemans @@ -28,21 +28,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 @@ -53,62 +52,54 @@ 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 - > +class ProjMatrixByBinFromFile : public RegisteredParsingObject { -public : +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 - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; ProjMatrixByBinFromFile* clone() const override; 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; @@ -120,28 +111,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; - - void - calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin&) const override; + void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const override; void set_defaults() override; void initialise_keymap() override; bool post_processing() override; Succeeded read_data(); - }; END_NAMESPACE_STIR #endif - - - diff --git a/src/include/stir/recon_buildblock/ProjMatrixByBinPinholeSPECTUB.h b/src/include/stir/recon_buildblock/ProjMatrixByBinPinholeSPECTUB.h index 911483754..ec0d561ca 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixByBinPinholeSPECTUB.h +++ b/src/include/stir/recon_buildblock/ProjMatrixByBinPinholeSPECTUB.h @@ -11,7 +11,7 @@ \file \ingroup projection - \brief stir::ProjMatrixByBinPinholeSPECTUB's definition + \brief stir::ProjMatrixByBinPinholeSPECTUB's definition \author Matthew Strugari \author Carles Falcon @@ -21,10 +21,10 @@ #ifndef __stir_recon_buildblock_ProjMatrixByBinPinholeSPECTUB__ #define __stir_recon_buildblock_ProjMatrixByBinPinholeSPECTUB__ -//system libraries +// system libraries #include -//user defined libraries +// user defined libraries #include "stir/RegisteredParsingObject.h" #include "stir/recon_buildblock/ProjMatrixByBin.h" #include "stir/ProjDataInfo.h" @@ -35,13 +35,14 @@ START_NAMESPACE_STIR -template class DiscretisedDensity; +template +class DiscretisedDensity; class Bin; /*! \ingroup projection \brief Generates projection matrix for pinhole SPECT studies - \warning this class currently only works with VoxelsOnCartesianGrid. + \warning this class currently only works with VoxelsOnCartesianGrid. \par Sample parameter file @@ -64,7 +65,7 @@ class Bin; attenuation map := object radius (cm) := 2.3 - mask file := + mask file := ; If no mask file is set, we can either compute it from attenuation map or object radius mask from attenuation map := 0 @@ -74,7 +75,7 @@ class Bin; \endverbatim \par Sample detector file - + \verbatim Information of detector Comments are allowed here or anywhere in lines not containing parameters. @@ -85,7 +86,7 @@ class Bin; #intrinsic PSF# Sigma (cm): 0.0361 Crystal thickness (cm): 0.3 - Crystal attenuation coefficient (cm -1): 4.407 + Crystal attenuation coefficient (cm -1): 4.407 \#……repeat for each ring …………\# Nangles: 4 ang0 (deg): 180. @@ -113,166 +114,158 @@ class Bin; \endverbatim */ -class ProjMatrixByBinPinholeSPECTUB : - public RegisteredParsingObject< - ProjMatrixByBinPinholeSPECTUB, - ProjMatrixByBin, - ProjMatrixByBin - > +class ProjMatrixByBinPinholeSPECTUB + : public RegisteredParsingObject { - public : - //! Name which will be used when parsing a ProjMatrixByBin object - static const char * const registered_name; - - //! Default constructor (calls set_defaults()) - ProjMatrixByBinPinholeSPECTUB(); - - // disable copy-constructor as currently unsafe to copy due to bare pointers - ProjMatrixByBinPinholeSPECTUB(const ProjMatrixByBinPinholeSPECTUB&) = delete; - - //! Destructor (deallocates UB SPECT memory) - ~ProjMatrixByBinPinholeSPECTUB() override; - - //! Checks all necessary geometric info - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; - - //******************** get/set functions ************* - - //! Minimum weight - // no longer set minimum weight, always use 0. - // float get_minimum_weight() const; - // void set_minimum_weight( const float value ); - - //! Maximum number of sigmas - float get_maximum_number_of_sigmas() const; - void set_maximum_number_of_sigmas( const float value ); - - //! Spatial resolution PSF - float get_spatial_resolution_PSF() const; - void set_spatial_resolution_PSF( const float value ); - - //! Subsampling factor PSF - int get_subsampling_factor_PSF() const; - void set_subsampling_factor_PSF( const int value ); - - //! Detector file - //std::string get_detector_file() const; - void set_detector_file( const std::string& value ); - - //! Collimator file - //std::string get_collimator_file() const; - void set_collimator_file( const std::string& value ); - - //! PSF correction - std::string get_psf_correction() const; - void set_psf_correction( const std::string& value ); - - //! Set DOI correction - std::string get_doi_correction() const; - void set_doi_correction( const std::string& value ); - - //! Object radius (cm) - float get_object_radius() const; - void set_object_radius( const float value ); - - //! Type of attenuation modelling - std::string get_attenuation_type() const; - void set_attenuation_type(const std::string& value); - shared_ptr > - get_attenuation_image_sptr() const; - - //! Attenuation image - void set_attenuation_image_sptr(const shared_ptr > value); - void set_attenuation_image_sptr(const std::string& value); - - //! Type of masking - // no longer use mask type - //std::string get_mask_type() const; - //void set_mask_type(const std::string& value); - - //! Mask from mask file - shared_ptr > - get_mask_image_sptr() const; - void set_mask_image_sptr(const shared_ptr > value); - void set_mask_image_sptr(const std::string& value); - - //! Mask from attenuation map - bool get_mask_from_attenuation_map() const; - void set_mask_from_attenuation_map(bool value = false); - - //! Enable keeping the matrix in memory - bool get_keep_all_views_in_cache() const; - void set_keep_all_views_in_cache(bool value = false); - - ProjMatrixByBinPinholeSPECTUB * clone() const override; - - private: - - // parameters that will be parsed - - float minimum_weight; - float maximum_number_of_sigmas; - float spatial_resolution_PSF; - int subsampling_factor_PSF; - std::string detector_file; - std::string collimator_file; - std::string psf_correction; - std::string doi_correction; - std::string attenuation_type; - std::string attenuation_map; - //std::string mask_type; - float object_radius; - std::string mask_file; - bool mask_from_attenuation_map; - bool keep_all_views_in_cache; //!< if set to false, only a single view is kept in memory - - // explicitly list necessary members for image details (should use an Info object instead) - CartesianCoordinate3D voxel_size; - CartesianCoordinate3D origin; - IndexRange<3> densel_range; - - shared_ptr proj_data_info_ptr; - - bool already_setup; - - mutable SPECTUB_mph::wmh_mph_type wmh; // weight matrix header. - mutable SPECTUB_mph::wm_da_type wm; // double array weight matrix structure. - mutable SPECTUB_mph::pcf_type pcf; // pre-calculated functions - - void - calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const override; - - void set_defaults() override; - void initialise_keymap() override; - bool post_processing() override; - - shared_ptr > attenuation_image_sptr; - shared_ptr > mask_image_sptr; - - // wm_SPECT starts here --------------------------------------------------------------------------------------------- - bool *msk_3d; // voxels to be included in matrix (no weight calculated outside the mask) - float *attmap; // attenuation map - - //... variables for estimated sizes of arrays to allocate ................................ - int **Nitems; //!< number of non-zero elements for each weight matrix row - - //... user defined structures (types defined in PinholeSPECTUB_Tools.h) ..................................... - - SPECTUB_mph::volume_type vol; //!< structure with volume (image) information - SPECTUB_mph::prj_mph_type prj; //!< structure with projection information - SPECTUB_mph::bin_type bin; //!< structure with bin information - - // mutable to allow compute_one_subset() const function to change the fields - mutable SPECTUB_mph::psf2d_type psf_bin; // structure for total psf distribution in bins (bidimensional) - mutable SPECTUB_mph::psf2d_type psf_subs; // structure for total psf distribution: mid resolution (bidimensional) - mutable SPECTUB_mph::psf2d_type psf_aux; // structure for total psf distribution: mid resolution auxiliar for convolution (bidimensional) - mutable SPECTUB_mph::psf2d_type kern; // structure for intrinsic psf distribution: mid resolution (bidimensional) - - void compute_one_subset(const int kOS) const; - void delete_PinholeSPECTUB_arrays(); +public: + //! Name which will be used when parsing a ProjMatrixByBin object + static const char* const registered_name; + + //! Default constructor (calls set_defaults()) + ProjMatrixByBinPinholeSPECTUB(); + + // disable copy-constructor as currently unsafe to copy due to bare pointers + ProjMatrixByBinPinholeSPECTUB(const ProjMatrixByBinPinholeSPECTUB&) = delete; + + //! Destructor (deallocates UB SPECT memory) + ~ProjMatrixByBinPinholeSPECTUB() override; + + //! Checks all necessary geometric info + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; + + //******************** get/set functions ************* + + //! Minimum weight + // no longer set minimum weight, always use 0. + // float get_minimum_weight() const; + // void set_minimum_weight( const float value ); + + //! Maximum number of sigmas + float get_maximum_number_of_sigmas() const; + void set_maximum_number_of_sigmas(const float value); + + //! Spatial resolution PSF + float get_spatial_resolution_PSF() const; + void set_spatial_resolution_PSF(const float value); + + //! Subsampling factor PSF + int get_subsampling_factor_PSF() const; + void set_subsampling_factor_PSF(const int value); + + //! Detector file + // std::string get_detector_file() const; + void set_detector_file(const std::string& value); + + //! Collimator file + // std::string get_collimator_file() const; + void set_collimator_file(const std::string& value); + + //! PSF correction + std::string get_psf_correction() const; + void set_psf_correction(const std::string& value); + + //! Set DOI correction + std::string get_doi_correction() const; + void set_doi_correction(const std::string& value); + + //! Object radius (cm) + float get_object_radius() const; + void set_object_radius(const float value); + + //! Type of attenuation modelling + std::string get_attenuation_type() const; + void set_attenuation_type(const std::string& value); + shared_ptr> get_attenuation_image_sptr() const; + + //! Attenuation image + void set_attenuation_image_sptr(const shared_ptr> value); + void set_attenuation_image_sptr(const std::string& value); + + //! Type of masking + // no longer use mask type + // std::string get_mask_type() const; + // void set_mask_type(const std::string& value); + + //! Mask from mask file + shared_ptr> get_mask_image_sptr() const; + void set_mask_image_sptr(const shared_ptr> value); + void set_mask_image_sptr(const std::string& value); + + //! Mask from attenuation map + bool get_mask_from_attenuation_map() const; + void set_mask_from_attenuation_map(bool value = false); + + //! Enable keeping the matrix in memory + bool get_keep_all_views_in_cache() const; + void set_keep_all_views_in_cache(bool value = false); + + ProjMatrixByBinPinholeSPECTUB* clone() const override; + +private: + // parameters that will be parsed + + float minimum_weight; + float maximum_number_of_sigmas; + float spatial_resolution_PSF; + int subsampling_factor_PSF; + std::string detector_file; + std::string collimator_file; + std::string psf_correction; + std::string doi_correction; + std::string attenuation_type; + std::string attenuation_map; + // std::string mask_type; + float object_radius; + std::string mask_file; + bool mask_from_attenuation_map; + bool keep_all_views_in_cache; //!< if set to false, only a single view is kept in memory + + // explicitly list necessary members for image details (should use an Info object instead) + CartesianCoordinate3D voxel_size; + CartesianCoordinate3D origin; + IndexRange<3> densel_range; + + shared_ptr proj_data_info_ptr; + + bool already_setup; + + mutable SPECTUB_mph::wmh_mph_type wmh; // weight matrix header. + mutable SPECTUB_mph::wm_da_type wm; // double array weight matrix structure. + mutable SPECTUB_mph::pcf_type pcf; // pre-calculated functions + + void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const override; + + void set_defaults() override; + void initialise_keymap() override; + bool post_processing() override; + + shared_ptr> attenuation_image_sptr; + shared_ptr> mask_image_sptr; + + // wm_SPECT starts here --------------------------------------------------------------------------------------------- + bool* msk_3d; // voxels to be included in matrix (no weight calculated outside the mask) + float* attmap; // attenuation map + + //... variables for estimated sizes of arrays to allocate ................................ + int** Nitems; //!< number of non-zero elements for each weight matrix row + + //... user defined structures (types defined in PinholeSPECTUB_Tools.h) ..................................... + + SPECTUB_mph::volume_type vol; //!< structure with volume (image) information + SPECTUB_mph::prj_mph_type prj; //!< structure with projection information + SPECTUB_mph::bin_type bin; //!< structure with bin information + + // mutable to allow compute_one_subset() const function to change the fields + mutable SPECTUB_mph::psf2d_type psf_bin; // structure for total psf distribution in bins (bidimensional) + mutable SPECTUB_mph::psf2d_type psf_subs; // structure for total psf distribution: mid resolution (bidimensional) + mutable SPECTUB_mph::psf2d_type + psf_aux; // structure for total psf distribution: mid resolution auxiliar for convolution (bidimensional) + mutable SPECTUB_mph::psf2d_type kern; // structure for intrinsic psf distribution: mid resolution (bidimensional) + + void compute_one_subset(const int kOS) const; + void delete_PinholeSPECTUB_arrays(); }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/ProjMatrixByBinSPECTUB.h b/src/include/stir/recon_buildblock/ProjMatrixByBinSPECTUB.h index 7d32e8812..dc7cacd62 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixByBinSPECTUB.h +++ b/src/include/stir/recon_buildblock/ProjMatrixByBinSPECTUB.h @@ -11,7 +11,7 @@ \file \ingroup projection - \brief stir::ProjMatrixByBinSPECTUB's definition + \brief stir::ProjMatrixByBinSPECTUB's definition \author Berta Marti Fuster \author Kris Thielemans @@ -27,28 +27,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 @@ -61,8 +61,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} @@ -75,18 +75,13 @@ class Bin; End Projection Matrix By Bin SPECT UB Parameters:= \endverbatim */ -//using namespace SPECTUB; -class ProjMatrixByBinSPECTUB : - public RegisteredParsingObject< - ProjMatrixByBinSPECTUB, - ProjMatrixByBin, - ProjMatrixByBin - > +// using namespace SPECTUB; +class ProjMatrixByBinSPECTUB : public RegisteredParsingObject { - public : +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(); @@ -97,10 +92,9 @@ class ProjMatrixByBinSPECTUB : ~ProjMatrixByBinSPECTUB() override; //! Checks all necessary geometric info - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only -) override; + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; bool get_keep_all_views_in_cache() const; //! Enable keeping the matrix in memory @@ -117,8 +111,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. @@ -127,10 +120,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 @@ -147,16 +138,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); - - //Alex - //Fix to compile, missing function definition in header - ProjMatrixByBinSPECTUB * clone() const override; - private: + void set_resolution_model(const float collimator_sigma_0_in_mm, const float collimator_slope_in_mm, const bool full_3D = true); + // Alex + // Fix to compile, missing function definition in header + ProjMatrixByBinSPECTUB* clone() const override; + +private: // parameters that will be parsed - + float minimum_weight; float maximum_number_of_sigmas; float spatial_resolution_PSF; @@ -171,7 +161,7 @@ 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; @@ -180,43 +170,39 @@ class ProjMatrixByBinSPECTUB : mutable SPECTUB::wm_da_type wm; mutable SPECTUB::wmh_type wmh; // this could be an arry of wmh_type for each index - float * Rrad; + float* Rrad; - void - calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin&) const override; + void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const override; void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - 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 float *Rrad) const; + void compute_one_subset(const int kOS, const float* Rrad) const; void delete_UB_SPECT_arrays(); mutable std::vector subset_already_processed; }; @@ -224,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 35fa91a12..6d0a3a208 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixByBinUsingInterpolation.h +++ b/src/include/stir/recon_buildblock/ProjMatrixByBinUsingInterpolation.h @@ -12,7 +12,7 @@ \file \ingroup projection - \brief stir::ProjMatrixByBinUsingInterpolation's definition + \brief stir::ProjMatrixByBinUsingInterpolation's definition \author Kris Thielemans @@ -26,49 +26,43 @@ #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 - > +class ProjMatrixByBinUsingInterpolation + : public RegisteredParsingObject { -public : - //! Name which will be used when parsing a ProjMatrixByBin object - static const char * const registered_name; +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. - */ - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; + */ + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; ProjMatrixByBinUsingInterpolation* clone() const override; @@ -81,97 +75,85 @@ 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; - void - calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin&) const override; + void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const override; void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - 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 ec59ef0b7..3d4239711 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 @@ -26,17 +26,16 @@ #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 \c NEWSCALE is \c \#defined during compilation time of ProjMatrixByBinUsingRayTracing.cxx. @@ -50,16 +49,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). @@ -73,7 +72,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): @@ -90,7 +89,7 @@ class ProjDataInfo; do_symmetry_shift_z := 1 End Ray Tracing Matrix Parameters := \endverbatim - + \par Implementation details The implementation uses RayTraceVoxelsOnCartesianGrid(). @@ -100,37 +99,32 @@ 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 - > +class ProjMatrixByBinUsingRayTracing + : public RegisteredParsingObject { -public : - //! Name which will be used when parsing a ProjMatrixByBin object - static const char * const registered_name; +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. - */ - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; + */ + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; ProjMatrixByBinUsingRayTracing* clone() const override; @@ -189,23 +183,17 @@ 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; - void - calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin&) const override; + void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const override; - void set_defaults() override; - void initialise_keymap() override; - bool post_processing() override; - + void set_defaults() override; + void initialise_keymap() override; + bool post_processing() override; }; END_NAMESPACE_STIR #endif - - - diff --git a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBin.h b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBin.h index ca6f5e825..a006b02f4 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBin.h +++ b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBin.h @@ -8,14 +8,14 @@ \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 @@ -28,8 +28,6 @@ See STIR/LICENSE.txt for details */ - - #include "stir/recon_buildblock/ProjMatrixElemsForOneBinValue.h" #include "stir/Bin.h" #include @@ -38,10 +36,8 @@ START_NAMESPACE_STIR class Succeeded; class RelatedBins; -template class DiscretisedDensity; - - - +template +class DiscretisedDensity; /*! \brief This stores the non-zero projection matrix elements @@ -57,22 +53,22 @@ 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 *'. @@ -80,14 +76,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; @@ -95,30 +92,29 @@ 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 const Bin& get_bin() const; //! and set the bin coordinates inline void set_bin(const Bin&); //! 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; @@ -127,29 +123,29 @@ class ProjMatrixElemsForOneBin //! remove a single value_type inline iterator erase(iterator it); //! 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 @@ -157,7 +153,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. @@ -166,15 +162,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 @@ -184,28 +178,21 @@ 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; - }; - 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 e74e2cf9f..b71bbcd98 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBin.inl +++ b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneBin.inl @@ -26,56 +26,58 @@ START_NAMESPACE_STIR const Bin& -ProjMatrixElemsForOneBin:: -get_bin() const +ProjMatrixElemsForOneBin::get_bin() const { 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 53b290be6..a616551fe 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 @@ -24,17 +24,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 @@ -44,17 +44,14 @@ template class BasicCoordinate; */ 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; @@ -70,12 +67,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 @@ -86,20 +82,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 6562baa6d..29090012c 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 @@ -23,16 +23,14 @@ #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) +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])), @@ -44,112 +42,100 @@ ProjMatrixElemsForOneBinValue(const BasicCoordinate<3,int>& coords, assert(coords[2] >= SHRT_MIN); assert(coords[1] <= SHRT_MAX); assert(coords[1] >= SHRT_MIN); -} +} -ProjMatrixElemsForOneBinValue:: -ProjMatrixElemsForOneBinValue() +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); +} -BasicCoordinate<3,int> -ProjMatrixElemsForOneBinValue:: -get_coords() const +int +ProjMatrixElemsForOneBinValue::coord2() const { - return Coordinate3D(c1,c2,c3); + return static_cast(c2); } -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) +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) +bool +ProjMatrixElemsForOneBinValue::coordinates_equal(const ProjMatrixElemsForOneBinValue& el1, + const ProjMatrixElemsForOneBinValue& el2) { - return el1.c3==el2.c3 && el1.c2==el2.c2 && el1.c1==el2.c1; + return el1.c3 == el2.c3 && el1.c2 == el2.c2 && el1.c1 == el2.c1; } -bool -ProjMatrixElemsForOneBinValue:: -coordinates_less(const ProjMatrixElemsForOneBinValue& el1, const ProjMatrixElemsForOneBinValue& el2) +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'. @@ -48,22 +44,22 @@ 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 *'. @@ -71,14 +67,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; @@ -86,59 +83,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 const 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 @@ -146,13 +142,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 @@ -177,17 +172,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 1339f9125..f91b7297d 100644 --- a/src/include/stir/recon_buildblock/ProjMatrixElemsForOneDensel.inl +++ b/src/include/stir/recon_buildblock/ProjMatrixElemsForOneDensel.inl @@ -23,56 +23,57 @@ START_NAMESPACE_STIR const Densel& -ProjMatrixElemsForOneDensel:: -get_densel() const +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 379f6c2f4..4709f1e90 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 @@ -25,11 +25,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 @@ -39,11 +38,10 @@ 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(); @@ -51,15 +49,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 @@ -70,17 +68,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 a2a0c539a..802b40955 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 @@ -18,105 +18,85 @@ See STIR/LICENSE.txt for details */ - START_NAMESPACE_STIR -ProjMatrixElemsForOneDenselValue:: -ProjMatrixElemsForOneDenselValue(const Bin& bin) -: Bin(bin) -{ -} +ProjMatrixElemsForOneDenselValue::ProjMatrixElemsForOneDenselValue(const Bin& bin) + : Bin(bin) +{} -ProjMatrixElemsForOneDenselValue:: -ProjMatrixElemsForOneDenselValue() +ProjMatrixElemsForOneDenselValue::ProjMatrixElemsForOneDenselValue() : Bin() -{} +{} - - -ProjMatrixElemsForOneDenselValue& -ProjMatrixElemsForOneDenselValue:: -operator+=(const ProjMatrixElemsForOneDenselValue& el2) +ProjMatrixElemsForOneDenselValue& +ProjMatrixElemsForOneDenselValue::operator+=(const ProjMatrixElemsForOneDenselValue& el2) { - //TODO assert(get_coords() == el2.get_coords()); + // 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) +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(); + 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) +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()))))); + 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) +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(); ~ProjectorByBinPair() override {} //! 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 symmetries. @@ -82,13 +75,12 @@ 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; @@ -97,17 +89,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 34e698d7e..b9b7b0ef2 100644 --- a/src/include/stir/recon_buildblock/ProjectorByBinPairUsingProjMatrixByBin.h +++ b/src/include/stir/recon_buildblock/ProjectorByBinPairUsingProjMatrixByBin.h @@ -31,22 +31,17 @@ 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 @@ -54,20 +49,17 @@ class ProjectorByBinPairUsingProjMatrixByBin : //! Stores all necessary geometric info /*! First constructs forward and back projectors and then calls base_type::setup */ - Succeeded set_up( - const shared_ptr& proj_data_info_sptr, - const shared_ptr >& density_info_sptr // TODO should be Info only - ) override; + Succeeded set_up(const shared_ptr& proj_data_info_sptr, + const shared_ptr>& density_info_sptr // TODO should be Info only + ) override; - 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() override; void initialise_keymap() override; @@ -76,5 +68,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 7b082b6f1..f2d92579d 100644 --- a/src/include/stir/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.h +++ b/src/include/stir/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.h @@ -25,36 +25,28 @@ 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() override; void initialise_keymap() override; bool post_processing() override; @@ -62,5 +54,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 4209ab8ba..d426a391a 100644 --- a/src/include/stir/recon_buildblock/QuadraticPrior.h +++ b/src/include/stir/recon_buildblock/QuadraticPrior.h @@ -18,11 +18,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" @@ -32,7 +30,6 @@ START_NAMESPACE_STIR - /*! \ingroup priors \brief @@ -42,26 +39,26 @@ START_NAMESPACE_STIR \f[ f = \frac{1}{4} \sum_{r,dr} w_{dr} (\lambda_r - \lambda_{r+dr})^2 * \kappa_r * \kappa_{r+dr} \f] - with gradient + with gradient \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 @@ -72,118 +69,111 @@ 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 > - > +class QuadraticPrior : public RegisteredParsingObject, + GeneralisedPrior>, + PriorWithParabolicSurrogate>> { - private: - typedef - RegisteredParsingObject< QuadraticPrior, - GeneralisedPrior >, - PriorWithParabolicSurrogate > > - base_type; - - public: +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); - - bool - parabolic_surrogate_curvature_depends_on_argument() const override - { return false; } + + bool parabolic_surrogate_curvature_depends_on_argument() const override { return false; } bool is_convex() const override; //! compute the value of the function - double - compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate) override; + double compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate) override; - //! compute gradient - void compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) override; + //! compute gradient + void compute_gradient(DiscretisedDensity<3, elemT>& prior_gradient, + const DiscretisedDensity<3, elemT>& current_image_estimate) override; //! 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) override; + void parabolic_surrogate_curvature(DiscretisedDensity<3, elemT>& parabolic_surrogate_curvature, + const DiscretisedDensity<3, elemT>& current_image_estimate) override; - void - compute_Hessian(DiscretisedDensity<3,elemT>& prior_Hessian_for_single_densel, - const BasicCoordinate<3,int>& coords, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) const override; + void compute_Hessian(DiscretisedDensity<3, elemT>& prior_Hessian_for_single_densel, + const BasicCoordinate<3, int>& coords, + const DiscretisedDensity<3, elemT>& current_image_estimate) const override; //! Call accumulate_Hessian_times_input - void - add_multiplication_with_approximate_Hessian(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& input) const override; + void add_multiplication_with_approximate_Hessian(DiscretisedDensity<3, elemT>& output, + const DiscretisedDensity<3, elemT>& input) const override; //! 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. - void accumulate_Hessian_times_input(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& current_estimate, - const DiscretisedDensity<3,elemT>& input) const override; + void accumulate_Hessian_times_input(DiscretisedDensity<3, elemT>& output, + const DiscretisedDensity<3, elemT>& current_estimate, + const DiscretisedDensity<3, elemT>& input) const override; //! 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 - Succeeded set_up(shared_ptr > const& target_sptr) override; - + Succeeded set_up(shared_ptr> const& target_sptr) override; + 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 - void check(DiscretisedDensity<3,elemT> const& current_image_estimate) const override; + void check(DiscretisedDensity<3, elemT> const& current_image_estimate) const override; void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - private: - shared_ptr > kappa_ptr; + +private: + shared_ptr> kappa_ptr; //! The second partial derivatives of the Quadratic Prior /*! @@ -199,8 +189,6 @@ class QuadraticPrior: public //@} }; - END_NAMESPACE_STIR #endif - diff --git a/src/include/stir/recon_buildblock/RayTraceVoxelsOnCartesianGrid.h b/src/include/stir/recon_buildblock/RayTraceVoxelsOnCartesianGrid.h index eb04f7d20..9aac91fc7 100644 --- a/src/include/stir/recon_buildblock/RayTraceVoxelsOnCartesianGrid.h +++ b/src/include/stir/recon_buildblock/RayTraceVoxelsOnCartesianGrid.h @@ -24,10 +24,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. @@ -40,7 +41,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 @@ -52,7 +53,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 @@ -65,11 +66,10 @@ 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 ce45165f5..ac5b4d398 100644 --- a/src/include/stir/recon_buildblock/Reconstruction.h +++ b/src/include/stir/recon_buildblock/Reconstruction.h @@ -13,9 +13,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 @@ -37,7 +37,6 @@ START_NAMESPACE_STIR - class Succeeded; /*! @@ -47,7 +46,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 @@ -58,7 +57,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 := @@ -67,30 +66,27 @@ class Succeeded; */ template -class Reconstruction : - public RegisteredObject >, - public TimedObject +class Reconstruction : public RegisteredObject>, public TimedObject { public: //! default constructor (calls set_defaults()) Reconstruction(); //! virtual destructor - ~Reconstruction() override {}; - + ~Reconstruction() override{}; + //! 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. @@ -100,12 +96,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 @@ -113,23 +108,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; @@ -152,19 +147,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 @@ -175,12 +169,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. @@ -189,19 +183,19 @@ class Reconstruction : return Succeeded (or throw an exception). */ void initialise(const std::string& parameter_filename); - + void set_defaults() override; void initialise_keymap() override; //! 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() ). */ @@ -210,7 +204,7 @@ class Reconstruction : //! //! \brief target_data_sptr //! - shared_ptr target_data_sptr; + shared_ptr target_data_sptr; //! //! \brief _disable_output @@ -220,14 +214,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 652e67ca4..410150488 100644 --- a/src/include/stir/recon_buildblock/RelatedBins.h +++ b/src/include/stir/recon_buildblock/RelatedBins.h @@ -30,19 +30,18 @@ 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; @@ -52,8 +51,8 @@ class RelatedBins //! typedefs to make it partly comply with STL requirements typedef std::vector::iterator iterator; typedef std::vector::const_iterator const_iterator; - //!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; @@ -61,36 +60,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 @@ -98,5 +92,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 ff9d2f21c..032ead662 100644 --- a/src/include/stir/recon_buildblock/RelatedBins.inl +++ b/src/include/stir/recon_buildblock/RelatedBins.inl @@ -26,15 +26,14 @@ START_NAMESPACE_STIR - - RelatedBins::RelatedBins() -:related_bins(),symmetries() + : 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 @@ -50,7 +49,6 @@ RelatedBins::get_basic_bin() const return related_bins[0]; } - #if 0 const ProjDataInfo * RelatedBins:: get_proj_data_info_sptr() const @@ -60,30 +58,34 @@ RelatedBins:: get_proj_data_info_sptr() const } #endif - const DataSymmetriesForBins* RelatedBins::get_symmetries_ptr() const { return symmetries.get(); } - -RelatedBins::iterator +RelatedBins::iterator RelatedBins::begin() -{ return related_bins.begin();} +{ + return related_bins.begin(); +} RelatedBins::iterator RelatedBins::end() -{return related_bins.end();} +{ + return related_bins.end(); +} -RelatedBins::const_iterator +RelatedBins::const_iterator RelatedBins::begin() const -{return related_bins.begin();} +{ + return related_bins.begin(); +} -RelatedBins::const_iterator +RelatedBins::const_iterator RelatedBins::end() const -{return related_bins.end();} - +{ + 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 8c6310aee..c11910ea8 100644 --- a/src/include/stir/recon_buildblock/RelatedDensels.h +++ b/src/include/stir/recon_buildblock/RelatedDensels.h @@ -32,18 +32,17 @@ 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; @@ -53,8 +52,8 @@ class RelatedDensels //! typedefs to make it partly comply with STL requirements typedef std::vector::iterator iterator; typedef std::vector::const_iterator const_iterator; - //!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; @@ -62,36 +61,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 @@ -99,5 +93,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 c36648cb5..68299b694 100644 --- a/src/include/stir/recon_buildblock/RelatedDensels.inl +++ b/src/include/stir/recon_buildblock/RelatedDensels.inl @@ -26,15 +26,15 @@ START_NAMESPACE_STIR - - RelatedDensels::RelatedDensels() -:related_densels(),symmetries() + : 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 @@ -50,7 +50,6 @@ RelatedDensels::get_basic_densel() const return related_densels[0]; } - #if 0 const ProjDataInfo * RelatedDensels:: get_proj_data_info_sptr() const @@ -60,30 +59,34 @@ RelatedDensels:: get_proj_data_info_sptr() const } #endif - const DataSymmetriesForDensels* RelatedDensels::get_symmetries_ptr() const { return symmetries.get(); } - -RelatedDensels::iterator +RelatedDensels::iterator RelatedDensels::begin() -{ return related_densels.begin();} +{ + return related_densels.begin(); +} RelatedDensels::iterator RelatedDensels::end() -{return related_densels.end();} +{ + return related_densels.end(); +} -RelatedDensels::const_iterator +RelatedDensels::const_iterator RelatedDensels::begin() const -{return related_densels.begin();} +{ + return related_densels.begin(); +} -RelatedDensels::const_iterator +RelatedDensels::const_iterator RelatedDensels::end() const -{return related_densels.end();} - +{ + 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 a9fe33bba..26f950870 100644 --- a/src/include/stir/recon_buildblock/RelativeDifferencePrior.h +++ b/src/include/stir/recon_buildblock/RelativeDifferencePrior.h @@ -20,11 +20,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" @@ -34,7 +32,6 @@ START_NAMESPACE_STIR - /*! \ingroup priors \brief @@ -43,8 +40,8 @@ START_NAMESPACE_STIR The value of the prior is computed as follows: \f[ - f= \sum_{r,dr} \frac{w_{dr}}{2} \frac{(\lambda_r - \lambda_{r+dr})^2}{(\lambda_r+ \lambda_{r+dr} + \gamma |\lambda_r - \lambda_{r+dr}| + \epsilon)} * \kappa_r * \kappa_{r+dr} - \f] + f= \sum_{r,dr} \frac{w_{dr}}{2} \frac{(\lambda_r - \lambda_{r+dr})^2}{(\lambda_r+ \lambda_{r+dr} + \gamma |\lambda_r - +\lambda_{r+dr}| + \epsilon)} * \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. \f$\gamma\f$ is @@ -54,7 +51,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. @@ -66,7 +63,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 @@ -79,30 +76,26 @@ 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 > - > +class RelativeDifferencePrior : public RegisteredParsingObject, + GeneralisedPrior>, + GeneralisedPrior>> { - private: - typedef - RegisteredParsingObject< RelativeDifferencePrior, - GeneralisedPrior >, - GeneralisedPrior > - > - base_type; - - public: +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(); @@ -111,25 +104,23 @@ class RelativeDifferencePrior: public RelativeDifferencePrior(const bool only_2D, float penalization_factor, float gamma, float epsilon); //! compute the value of the function - double - compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate) override; + double compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate) override; - //! compute gradient - void compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) override; + //! compute gradient + void compute_gradient(DiscretisedDensity<3, elemT>& prior_gradient, + const DiscretisedDensity<3, elemT>& current_image_estimate) override; - void compute_Hessian(DiscretisedDensity<3,elemT>& prior_Hessian_for_single_densel, - const BasicCoordinate<3,int>& coords, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) const override; + void compute_Hessian(DiscretisedDensity<3, elemT>& prior_Hessian_for_single_densel, + const BasicCoordinate<3, int>& coords, + const DiscretisedDensity<3, elemT>& current_image_estimate) const override; - void - add_multiplication_with_approximate_Hessian(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& input) const override; + void add_multiplication_with_approximate_Hessian(DiscretisedDensity<3, elemT>& output, + const DiscretisedDensity<3, elemT>& input) const override; - //! Compute the multiplication of the hessian of the prior multiplied by the input. - void accumulate_Hessian_times_input(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& current_estimate, - const DiscretisedDensity<3,elemT>& input) const override; + //! Compute the multiplication of the hessian of the prior multiplied by the input. + void accumulate_Hessian_times_input(DiscretisedDensity<3, elemT>& output, + const DiscretisedDensity<3, elemT>& current_estimate, + const DiscretisedDensity<3, elemT>& input) const override; //! get the gamma value used in RDP float get_gamma() const; @@ -141,28 +132,27 @@ 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); + bool is_convex() const override; - + protected: //! Create variable gamma for Relative Difference Penalty float gamma; @@ -174,28 +164,29 @@ 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 - void check(DiscretisedDensity<3,elemT> const& current_image_estimate) const override; + void check(DiscretisedDensity<3, elemT> const& current_image_estimate) const override; void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - private: - shared_ptr > kappa_ptr; + +private: + shared_ptr> kappa_ptr; //! The second partial derivatives of the Relative Difference Prior /*! @@ -214,8 +205,6 @@ class RelativeDifferencePrior: public //@} }; - 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 467aae3e3..4007f6a1e 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. @@ -18,360 +18,355 @@ #include -namespace SPECTUB { +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) - + 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; + 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 - + 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 +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) - + 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 +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 + // 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 +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 - + 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) + 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) - + 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 - + 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 +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; + 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; //! 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 - + 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; //! 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 - +{ + 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; //! 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; + 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; //::: functions ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - //... functions from wmtools_SPECT.cpp ......................................... +void write_wm_FC(wm_da_type& wm); // to write double array weight matrix -void write_wm_FC (wm_da_type &wm); // to write double array weight matrix +void write_wm_hdr(wm_da_type& wm, wmh_type& wmh); // to write header of a matrix -void write_wm_hdr (wm_da_type &wm, wmh_type &wmh); // to write header of a matrix +void write_wm_STIR(SPECTUB::wm_da_type& wm); // to write matrix in STIR format -void write_wm_STIR (SPECTUB::wm_da_type& wm); // to write matrix in STIR format +void index_calc(int* indexs, wmh_type& wmh); // to calculate projection index order in subsets - -void index_calc (int *indexs , wmh_type &wmh); // to calculate projection index order in subsets - -void read_Rrad (float *Rrad, wmh_type &wmh); // to read variable rotation radius from a text file (1 radius per line) +void read_Rrad(float* Rrad, wmh_type& wmh); // to read variable rotation radius from a text file (1 radius per line) // -//void col_params ( collim_type *COL ); // to fill collimator structure +// 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 , wmh_type &wmh, const float *Rrad); // to fill angle structure - -void generate_msk (bool *msk_3d, bool *msk_2d, float *att, volume_type *vol, wmh_type &wmh); // to create a boolean mask for wm (no weights outside the msk) - -void read_msk_file (bool * msk , wmh_type &wmh); // to read mask from a file - - -void read_att_map (float *attmap , wmh_type &wmh); // to read attenuation map from a file +// void read_col_params ( collim_type *COL); // to read collimator parameters from a file +void fill_ang(angle_type* ang, wmh_type& wmh, const float* Rrad); // to fill angle structure -int max_psf_szb (angle_type *ang , wmh_type &wmh); +void generate_msk(bool* msk_3d, + bool* msk_2d, + float* att, + volume_type* vol, + wmh_type& wmh); // 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, wmh_type& wmh); // to read mask from a file -float calc_sigma_v (voxel_type vox, collim_type COL, wmh_type &wmh); +void read_att_map(float* attmap, wmh_type& wmh); // to read attenuation map from a file +int max_psf_szb(angle_type* ang, wmh_type& wmh); -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, wmh_type& wmh); -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, @@ -379,17 +374,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 8f15d9346..9817d8262 100644 --- a/src/include/stir/recon_buildblock/SPECTUB_Weight3d.h +++ b/src/include/stir/recon_buildblock/SPECTUB_Weight3d.h @@ -1,13 +1,13 @@ - /* - 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. - SPDX-License-Identifier: Apache-2.0 + SPDX-License-Identifier: Apache-2.0 - See STIR/LICENSE.txt for details + See STIR/LICENSE.txt for details - \author Carles Falcon + \author Carles Falcon */ @@ -20,83 +20,95 @@ 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 */ -namespace SPECTUB { +namespace SPECTUB +{ void wm_calculation(const int kOS, - const SPECTUB::angle_type *const ang, + const SPECTUB::angle_type* const ang, SPECTUB::voxel_type vox, bin_type bin, const SPECTUB::volume_type& vol, const proj_type& prj, - const float *attmap, - const bool *msk_3d, - const bool *msk_2d, + const float* attmap, + const bool* msk_3d, + const bool* msk_2d, const int maxszb, - const SPECTUB::discrf_type *const gaussdens, - const int *const NITEMS, + const SPECTUB::discrf_type* const gaussdens, + const int* const NITEMS, SPECTUB::wm_da_type& wm, SPECTUB::wmh_type& wmh, - const float *Rrad - ); - -void wm_size_estimation (int kOS, - const SPECTUB::angle_type * const ang, - SPECTUB::voxel_type vox, - bin_type bin, - const SPECTUB::volume_type& vol, - const SPECTUB::proj_type& prj, - const bool * const msk_3d, - const bool *const msk_2d, - const int maxszb, - const SPECTUB::discrf_type * const gaussdens, - int *NITEMS, - SPECTUB::wmh_type &wmh, - const float *Rrad); - + const float* Rrad); + +void wm_size_estimation(int kOS, + const SPECTUB::angle_type* const ang, + SPECTUB::voxel_type vox, + bin_type bin, + const SPECTUB::volume_type& vol, + const SPECTUB::proj_type& prj, + const bool* const msk_3d, + const bool* const msk_2d, + const int maxszb, + const SPECTUB::discrf_type* const gaussdens, + int* NITEMS, + SPECTUB::wmh_type& wmh, + const float* Rrad); //... geometric component ............................................ -void calc_gauss ( SPECTUB::discrf_type *gaussdens ); - -void calc_vxprj ( SPECTUB::angle_type *ang ); +void calc_gauss(SPECTUB::discrf_type* gaussdens); -void voxel_projection (SPECTUB::voxel_type *vox, float * eff, float lngcmd2 , SPECTUB::wmh_type &wmh); +void calc_vxprj(SPECTUB::angle_type* ang); -void fill_psf_no(SPECTUB::psf2da_type *psf, SPECTUB::psf1d_type *psf1d_h, const SPECTUB::voxel_type& vox, const angle_type * const ang, float szdx , SPECTUB::wmh_type &wmh); +void voxel_projection(SPECTUB::voxel_type* vox, float* eff, float lngcmd2, SPECTUB::wmh_type& wmh); -void fill_psf_2d( SPECTUB::psf2da_type *psf, SPECTUB::psf1d_type *psf1d_h, const SPECTUB::voxel_type& vox, SPECTUB::discrf_type const*const gaussdens, float szdx, SPECTUB::wmh_type &wmh); +void fill_psf_no(SPECTUB::psf2da_type* psf, + SPECTUB::psf1d_type* psf1d_h, + const SPECTUB::voxel_type& vox, + const angle_type* const ang, + float szdx, + SPECTUB::wmh_type& wmh); -void fill_psf_3d(SPECTUB::psf2da_type *psf, - SPECTUB::psf1d_type *psf1d_h, - SPECTUB::psf1d_type *psf1d_v, - const SPECTUB::voxel_type& vox, SPECTUB::discrf_type const * const gaussdens, - float szdx, float thdx, float thcmd2, - wmh_type &wmh); +void fill_psf_2d(SPECTUB::psf2da_type* psf, + SPECTUB::psf1d_type* psf1d_h, + const SPECTUB::voxel_type& vox, + SPECTUB::discrf_type const* const gaussdens, + float szdx, + SPECTUB::wmh_type& wmh); -void calc_psf_bin (float center_psf, float binszcm, SPECTUB::discrf_type const * const vxprj, SPECTUB::psf1d_type *psf , SPECTUB::wmh_type &wmh); +void fill_psf_3d(SPECTUB::psf2da_type* psf, + SPECTUB::psf1d_type* psf1d_h, + SPECTUB::psf1d_type* psf1d_v, + const SPECTUB::voxel_type& vox, + SPECTUB::discrf_type const* const gaussdens, + float szdx, + float thdx, + float thcmd2, + wmh_type& wmh); +void calc_psf_bin( + float center_psf, float binszcm, SPECTUB::discrf_type const* const vxprj, SPECTUB::psf1d_type* psf, SPECTUB::wmh_type& wmh); //... 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 SPECTUB::voxel_type& vox, const SPECTUB::volume_type& vol, SPECTUB::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 SPECTUB::attpth_type *const attpth, const float *const attmap, int islc , SPECTUB::wmh_type &wmh); +void +calc_att_path(const bin_type& bin, const SPECTUB::voxel_type& vox, const SPECTUB::volume_type& vol, SPECTUB::attpth_type* attpth); -int comp_dist ( float dx, float dy, float dz, float dlast ); +float calc_att(const SPECTUB::attpth_type* const attpth, const float* const attmap, int islc, SPECTUB::wmh_type& wmh); +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 7c2ce32ac..4f49612d1 100644 --- a/src/include/stir/recon_buildblock/SqrtHessianRowSum.h +++ b/src/include/stir/recon_buildblock/SqrtHessianRowSum.h @@ -55,102 +55,100 @@ 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() override; - - //! 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() override; + + //! 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: - bool _already_setup = false; + bool _already_setup = false; private: + //! 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; + /// Verbosity level + int _verbosity; - /// Verbosity level - int _verbosity; - - //! used to check acceptable parameter ranges, etc... - bool post_processing() override; - void initialise_keymap() override; + //! used to check acceptable parameter ranges, etc... + bool post_processing() override; + void initialise_keymap() override; }; 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 a29f2f136..b25481cc6 100644 --- a/src/include/stir/recon_buildblock/SumOfGeneralisedObjectiveFunctions.h +++ b/src/include/stir/recon_buildblock/SumOfGeneralisedObjectiveFunctions.h @@ -20,7 +20,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 @@ -31,33 +30,26 @@ 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 @@ -66,39 +58,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; @@ -107,8 +89,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 987bb7d4e..2035200c0 100644 --- a/src/include/stir/recon_buildblock/SumOfGeneralisedObjectiveFunctions.inl +++ b/src/include/stir/recon_buildblock/SumOfGeneralisedObjectiveFunctions.inl @@ -24,32 +24,27 @@ 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 template @@ -65,9 +60,8 @@ 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; @@ -77,26 +71,22 @@ set_up(shared_ptr const& target_sptr) while (iter != end_iter) { if (iter->set_up(target_sptr) == Succeeded::no) - return 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->compute_sub_gradient_without_penalty(gradient, current_estimate, subset_num); ++iter; } @@ -104,29 +94,24 @@ compute_sub_gradient_without_penalty(TargetT& gradient, 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); + 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(); @@ -135,7 +120,7 @@ set_num_subsets(const int new_num_subsets) { // 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); + error("set_num_subsets failed to set to %d subsets", this->num_subsets); ++iter; } return this->num_subsets; @@ -143,15 +128,15 @@ set_num_subsets(const int new_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; + return false; ++iter; } return true; diff --git a/src/include/stir/recon_buildblock/SymmetryOperation.h b/src/include/stir/recon_buildblock/SymmetryOperation.h index 06a0afa37..077874f5f 100644 --- a/src/include/stir/recon_buildblock/SymmetryOperation.h +++ b/src/include/stir/recon_buildblock/SymmetryOperation.h @@ -24,24 +24,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, @@ -49,7 +48,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 @@ -63,31 +62,21 @@ 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 @@ -96,22 +85,14 @@ class SymmetryOperation class TrivialSymmetryOperation : public SymmetryOperation { public: - inline bool is_trivial() const override { return true;} - inline void - transform_bin_coordinates(Bin& b) const override {} - inline void - transform_view_segment_indices(ViewSegmentNumbers& n) const override {} - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override {} - inline void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override {} - - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override {} -}; + inline bool is_trivial() const override { return true; } + inline void transform_bin_coordinates(Bin& b) const override {} + inline void transform_view_segment_indices(ViewSegmentNumbers& n) const override {} + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override {} + inline void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override {} + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override {} +}; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/SymmetryOperations_PET_CartesianGrid.h b/src/include/stir/recon_buildblock/SymmetryOperations_PET_CartesianGrid.h index 1214f026f..ea93d0431 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 @@ -38,7 +38,6 @@ See STIR/LICENSE.txt for details */ - #ifndef __SymmetryOperations_PET_CartesianGrid_H__ #define __SymmetryOperations_PET_CartesianGrid_H__ @@ -50,25 +49,20 @@ 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 override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& ) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int axial_pos_shift; @@ -79,26 +73,22 @@ 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) + : view180(num_views), + axial_pos_shift(axial_pos_shift), + z_shift(z_shift), + q(q) {} - inline void - transform_bin_coordinates(Bin&) const override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; - - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int view180; @@ -107,33 +97,31 @@ class SymmetryOperation_PET_CartesianGrid_swap_xmx_zq : public SymmetryOperation int q; }; - /////////////////////////////////////// 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) + 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 override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; - - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int view180; @@ -142,31 +130,29 @@ class SymmetryOperation_PET_CartesianGrid_swap_xmy_yx_zq : public SymmetryOperat int q; }; - 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) + 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 override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; - - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int view180; @@ -179,26 +165,21 @@ 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) + : view180(num_views), + axial_pos_shift(axial_pos_shift), + z_shift(z_shift) {} - inline void - transform_bin_coordinates(Bin&) const override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; - - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int view180; @@ -206,31 +187,25 @@ class SymmetryOperation_PET_CartesianGrid_swap_xmy_yx : public SymmetryOperation int z_shift; }; - 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) + 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 override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; - - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int view180; @@ -238,32 +213,25 @@ class SymmetryOperation_PET_CartesianGrid_swap_xy_yx : public SymmetryOperation int z_shift; }; - - 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 override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int view180; @@ -275,57 +243,48 @@ 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) + : view180(num_views), + axial_pos_shift(axial_pos_shift), + z_shift(z_shift) {} - inline void - transform_bin_coordinates(Bin&) const override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; - - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int view180; int axial_pos_shift; int z_shift; - }; +}; 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) + : view180(num_views), + axial_pos_shift(axial_pos_shift), + z_shift(z_shift), + q(q) {} - inline void - transform_bin_coordinates(Bin&) const override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; - - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int view180; @@ -338,26 +297,25 @@ class SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy_zq : public SymmetryOpera { 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) + 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 override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; - - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int view180; @@ -370,26 +328,25 @@ class SymmetryOperation_PET_CartesianGrid_swap_xy_ymx_zq : public SymmetryOperat { 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) + 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 override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int view180; @@ -402,26 +359,21 @@ 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) + : view180(num_views), + axial_pos_shift(axial_pos_shift), + z_shift(z_shift) {} - inline void - transform_bin_coordinates(Bin&) const override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; - - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int view180; @@ -433,26 +385,21 @@ class SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx : public SymmetryOperatio { 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) + : view180(num_views), + axial_pos_shift(axial_pos_shift), + z_shift(z_shift) {} - inline void - transform_bin_coordinates(Bin&) const override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; - - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int view180; @@ -464,26 +411,22 @@ 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 override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int view180; @@ -496,26 +439,21 @@ class SymmetryOperation_PET_CartesianGrid_swap_xmx_ymy : public SymmetryOperatio { 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) + : view180(num_views), + axial_pos_shift(axial_pos_shift), + z_shift(z_shift) {} - inline void - transform_bin_coordinates(Bin&) const override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; - - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int view180; @@ -527,26 +465,25 @@ class SymmetryOperation_PET_CartesianGrid_swap_xmy_ymx_zq : public SymmetryOpera { 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) + 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 override; - inline void - transform_view_segment_indices(ViewSegmentNumbers&) const override; - inline void - transform_image_coordinates(BasicCoordinate<3,int>& c) const override; - - void - transform_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin& lor) const override; + inline void transform_bin_coordinates(Bin&) const override; + inline void transform_view_segment_indices(ViewSegmentNumbers&) const override; + inline void transform_image_coordinates(BasicCoordinate<3, int>& c) const override; + void transform_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const override; - void - transform_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel&) const override; + void transform_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; private: int view180; @@ -555,11 +492,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 a40639501..c6a966f38 100644 --- a/src/include/stir/recon_buildblock/SymmetryOperations_PET_CartesianGrid.inl +++ b/src/include/stir/recon_buildblock/SymmetryOperations_PET_CartesianGrid.inl @@ -34,76 +34,70 @@ 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_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_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]; @@ -113,27 +107,25 @@ 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 -{ + +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; @@ -142,45 +134,43 @@ 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; - } + if (b.view_num() < view180 / 2) + { + b.view_num() += view180 / 2; + } else - { - b.segment_num() *= -1; - b.view_num() -= view180/2; - b.tangential_pos_num() *= -1; - } - assert(0<=b.view_num()); - assert(b.view_num()&c) const -{ + { + vs.segment_num() *= -1; + vs.view_num() -= view180 / 2; + } + assert(0 <= vs.view_num()); + assert(vs.view_num() < view180); +} + +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; @@ -188,417 +178,386 @@ 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) - { - b.segment_num() *= -1; - b.view_num() = view180/2 - b.view_num(); - } + 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.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) - { - b.segment_num() *= -1; - b.view_num() = view180 - b.view_num(); - } + if (b.view_num() != 0) + { + b.segment_num() *= -1; + b.view_num() = view180 - b.view_num(); + } 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) - { - b.view_num() = view180 - b.view_num(); - b.tangential_pos_num() *= -1; - } + if (b.view_num() != 0) + { + b.view_num() = view180 - b.view_num(); + b.tangential_pos_num() *= -1; + } 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; b.timing_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; - b.tangential_pos_num() *= -1; - } + if (b.view_num() < view180 / 2) + { + b.view_num() += view180 / 2; + b.tangential_pos_num() *= -1; + } else - { - 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_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) - { - b.segment_num() *= -1; - b.view_num() += view180/2; - b.tangential_pos_num() *= -1; - } + if (b.view_num() < view180 / 2) + { + b.segment_num() *= -1; + b.view_num() += view180 / 2; + b.tangential_pos_num() *= -1; + } 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(); - b.tangential_pos_num() *= -1; - } + if (b.view_num() <= view180 / 2) + { + b.view_num() = view180 / 2 - b.view_num(); + b.tangential_pos_num() *= -1; + } else - { - b.segment_num() *= -1; - b.view_num() = 3*view180/2 - b.view_num(); - } - assert(0<=b.view_num()); - assert(b.view_num()&c) const -{ + { + vs.segment_num() *= -1; + vs.view_num() = 3 * view180 / 2 - vs.view_num(); + } + assert(0 <= vs.view_num()); + assert(vs.view_num() < view180); +} + +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; b.timing_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 36b1c6ceb..f07079020 100644 --- a/src/include/stir/recon_buildblock/TrivialBinNormalisation.h +++ b/src/include/stir/recon_buildblock/TrivialBinNormalisation.h @@ -31,24 +31,22 @@ 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; inline void apply(RelatedViewgrams&) const override {} inline void undo(RelatedViewgrams&) const override {} - - inline float get_bin_efficiency(const Bin& bin) const override { return 1.F;} - inline bool is_trivial() const override { return true;} + inline float get_bin_efficiency(const Bin& bin) const override { return 1.F; } + + inline bool is_trivial() const override { return true; } private: inline void set_defaults() override {} inline void initialise_keymap() override {} - }; END_NAMESPACE_STIR diff --git a/src/include/stir/recon_buildblock/TrivialDataSymmetriesForBins.h b/src/include/stir/recon_buildblock/TrivialDataSymmetriesForBins.h index b0d8264fd..7bbc43360 100644 --- a/src/include/stir/recon_buildblock/TrivialDataSymmetriesForBins.h +++ b/src/include/stir/recon_buildblock/TrivialDataSymmetriesForBins.h @@ -25,7 +25,6 @@ START_NAMESPACE_STIR - /*! \ingroup symmetries \brief A class derived from DataSymmetriesForBins that says that there are @@ -37,49 +36,43 @@ class TrivialDataSymmetriesForBins : public DataSymmetriesForBins public: TrivialDataSymmetriesForBins(const shared_ptr& proj_data_info_ptr); - - TrivialDataSymmetriesForBins * clone() const override; + TrivialDataSymmetriesForBins* clone() const override; - 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, const int max_timing_pos_num0) const override; + 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, + const int max_timing_pos_num0) const override; - 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 override; + 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 override; - int - num_related_bins(const Bin& b) const override; + int num_related_bins(const Bin& b) const override; - unique_ptr - find_symmetry_operation_from_basic_bin(Bin&) const override; + unique_ptr find_symmetry_operation_from_basic_bin(Bin&) const override; - bool - find_basic_bin(Bin& b) const override; + bool find_basic_bin(Bin& b) const override; - bool - is_basic(const Bin& v_s) const override; + bool is_basic(const Bin& v_s) const override; - unique_ptr - find_symmetry_operation_from_basic_view_segment_numbers(ViewSegmentNumbers&) const override; + unique_ptr find_symmetry_operation_from_basic_view_segment_numbers(ViewSegmentNumbers&) const override; - void - get_related_view_segment_numbers(std::vector&, const ViewSegmentNumbers&) const override; + void get_related_view_segment_numbers(std::vector&, const ViewSegmentNumbers&) const override; - int - num_related_view_segment_numbers(const ViewSegmentNumbers&) const override; - bool - find_basic_view_segment_numbers(ViewSegmentNumbers&) const override; + int num_related_view_segment_numbers(const ViewSegmentNumbers&) const override; + bool find_basic_view_segment_numbers(ViewSegmentNumbers&) const override; private: - bool blindly_equals(const root_type * const) const override; + bool blindly_equals(const root_type* const) const override; }; END_NAMESPACE_STIR - #endif - diff --git a/src/include/stir/recon_buildblock/distributable.h b/src/include/stir/recon_buildblock/distributable.h index 498601724..7377f7442 100644 --- a/src/include/stir/recon_buildblock/distributable.h +++ b/src/include/stir/recon_buildblock/distributable.h @@ -32,8 +32,10 @@ START_NAMESPACE_STIR -template class RelatedViewgrams; -template class DiscretisedDensity; +template +class RelatedViewgrams; +template +class DiscretisedDensity; class BinNormalisation; class ProjData; class ProjDataInfo; @@ -48,33 +50,32 @@ class ProjMatrixByBin; //! \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 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(); @@ -86,16 +87,17 @@ 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. @@ -107,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). @@ -119,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. @@ -143,40 +145,42 @@ 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, +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, + 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, + 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, + RPC_process_related_viewgrams_type* RPC_process_related_viewgrams, DistributedCachingInformation* caching_info_ptr, - int min_timing_pos_num, int max_timing_pos_num); + int min_timing_pos_num, + int max_timing_pos_num); /*! \brief This function essentially implements a loop over a cached listmode file @@ -185,35 +189,33 @@ void distributable_computation( \param has_add if \c true, the additive term in \c record_cache is taken into account \param accumulate if \c true, add to \c output_image_ptr, otherwise fill it with zeroes before doing anything. !*/ -void LM_distributable_computation( - const shared_ptr PM_sptr, - const shared_ptr& proj_data_info_sptr, - DiscretisedDensity<3,float>* output_image_ptr, - const DiscretisedDensity<3,float>* input_image_ptr, - const std::vector& record_cache, - const int subset_num, const int num_subsets, - const bool has_add, - const bool accumulate); - - /*! \name Tag-names currently used by stir::distributable_computation and related functions - \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; - - //!@} +void LM_distributable_computation(const shared_ptr PM_sptr, + const shared_ptr& proj_data_info_sptr, + DiscretisedDensity<3, float>* output_image_ptr, + const DiscretisedDensity<3, float>* input_image_ptr, + const std::vector& record_cache, + const int subset_num, + const int num_subsets, + const bool has_add, + const bool accumulate); + +/*! \name Tag-names currently used by stir::distributable_computation and related functions + \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 e3bd20f4f..0d81c297e 100644 --- a/src/include/stir/recon_buildblock/distributableMPICacheEnabled.h +++ b/src/include/stir/recon_buildblock/distributableMPICacheEnabled.h @@ -32,11 +32,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 @@ -48,32 +46,31 @@ class DistributedCachingInformation; \internal */ -void distributable_computation_cache_enabled( - const shared_ptr& forward_projector_ptr, +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, + 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, + int subset_num, + int num_subsets, + int min_segment_num, + int max_segment_num, bool zero_seg0_end_planes, - double* double_out_ptr, + 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, + RPC_process_related_viewgrams_type* RPC_process_related_viewgrams, DistributedCachingInformation* caching_info_ptr, - int min_timing_pos_num, int max_timing_pos_num - ); + int min_timing_pos_num, + int max_timing_pos_num); - -void test_image_estimate(shared_ptr > input_image_ptr); +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 8a9b8725d..4a0c0b598 100644 --- a/src/include/stir/recon_buildblock/distributable_main.h +++ b/src/include/stir/recon_buildblock/distributable_main.h @@ -31,12 +31,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 @@ -49,11 +49,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 412f2082d..d71ad8faa 100644 --- a/src/include/stir/recon_buildblock/distributed_functions.h +++ b/src/include/stir/recon_buildblock/distributed_functions.h @@ -12,9 +12,9 @@ #define __stir_recon_buildblock_DistributedFunctions_h__ /*! - \file + \file \ingroup distributable - + \brief Declaration of functions in the distributed namespace \author Tobias Beisel @@ -25,11 +25,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 @@ -39,8 +39,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 @@ -54,16 +54,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 @@ -78,357 +78,347 @@ #include "stir/VoxelsOnCartesianGrid.h" #include "stir/ProjDataInfo.h" -namespace stir { - class ExamInfo; +namespace stir +{ +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; - //!@} -} +/*! \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 2cf80921b..c3f7d6dc5 100644 --- a/src/include/stir/recon_buildblock/distributed_test_functions.h +++ b/src/include/stir/recon_buildblock/distributed_test_functions.h @@ -13,36 +13,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" @@ -55,41 +54,39 @@ 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(); -} +//-----------------------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 822570696..f3f45ea96 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 @@ -18,7 +18,6 @@ \author Kris Thielemans */ - #include "stir/ViewSegmentNumbers.h" #include @@ -27,23 +26,24 @@ 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 - - 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); - -} +/*! + \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); + +} // 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 89adf808d..3b53b6117 100644 --- a/src/include/stir/recon_buildblock/test/PoissonLLReconstructionTests.h +++ b/src/include/stir/recon_buildblock/test/PoissonLLReconstructionTests.h @@ -30,16 +30,16 @@ 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& projector_pair_filename = "", - const std::string &proj_data_filename = "", - const std::string & density_filename = "") - : base_type(proj_data_filename, density_filename) - { - this->construct_projector_pair(projector_pair_filename); - } + explicit inline PoissonLLReconstructionTests(const std::string& projector_pair_filename = "", + const std::string& proj_data_filename = "", + const std::string& density_filename = "") + : base_type(proj_data_filename, density_filename) + { + this->construct_projector_pair(projector_pair_filename); + } //! parses projector-pair file to initialise the projector pair /*! defaults to using the ray-tracing matrix */ @@ -47,18 +47,17 @@ class PoissonLLReconstructionTests : public ReconstructionTests //! 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; shared_ptr _projector_pair_sptr; }; template void -PoissonLLReconstructionTests:: -construct_projector_pair(const std::string& filename) +PoissonLLReconstructionTests::construct_projector_pair(const std::string& filename) { if (filename.empty()) { @@ -66,7 +65,7 @@ construct_projector_pair(const std::string& filename) this->_projector_pair_sptr.reset(new ProjectorByBinPairUsingProjMatrixByBin(proj_matrix_sptr)); return; } - + KeyParser parser; parser.add_start_key("projector pair parameters"); parser.add_parsing_key("projector pair type", &this->_projector_pair_sptr); @@ -77,12 +76,11 @@ construct_projector_pair(const std::string& filename) } 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); + PoissonLogLikelihoodWithLinearModelForMeanAndProjData& objective_function + = reinterpret_cast&>(*this->_objective_function_sptr); objective_function.set_proj_data_sptr(this->_proj_data_sptr); if (!this->_projector_pair_sptr) error("Internal error: need to set the projector pair first"); diff --git a/src/include/stir/recon_buildblock/test/ReconstructionTests.h b/src/include/stir/recon_buildblock/test/ReconstructionTests.h index 523d730d8..6c8d3bd15 100644 --- a/src/include/stir/recon_buildblock/test/ReconstructionTests.h +++ b/src/include/stir/recon_buildblock/test/ReconstructionTests.h @@ -35,15 +35,12 @@ 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 = ""); ~ReconstructionTests() override {} //! default proj_data_info - virtual inline std::unique_ptr - construct_default_proj_data_info_uptr() const; + virtual inline std::unique_ptr construct_default_proj_data_info_uptr() const; //! creates input /*! sets \c _proj_data_sptr and \c _input_density_sptr from @@ -69,78 +66,68 @@ 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 std::unique_ptr -ReconstructionTests:: -construct_default_proj_data_info_uptr() const +ReconstructionTests::construct_default_proj_data_info_uptr() const { // construct a small scanner and sinogram shared_ptr scanner_sptr(new Scanner(Scanner::E953)); scanner_sptr->set_num_rings(5); - std::unique_ptr proj_data_info_uptr( - ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span=*/3, - /*max_delta=*/4, - /*num_views=*/128, - /*num_tang_poss=*/128)); + std::unique_ptr proj_data_info_uptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span=*/3, + /*max_delta=*/4, + /*num_views=*/128, + /*num_tang_poss=*/128)); return proj_data_info_uptr; } template void -ReconstructionTests:: -construct_input_data() -{ +ReconstructionTests::construct_input_data() +{ Verbosity::set(1); if (this->_proj_data_filename.empty()) { shared_ptr proj_data_info_sptr(this->construct_default_proj_data_info_uptr()); 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)); + _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(); + 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)); + 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; + 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)); + 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)); + 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_fwhms(make_coordinate(10.F, 10.F, 10.F)); filter.set_up(*vox_sptr); filter.apply(*vox_sptr); this->_input_density_sptr = vox_sptr; @@ -153,11 +140,9 @@ construct_input_data() // 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); } @@ -165,31 +150,26 @@ 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) +ReconstructionTests::compare(const shared_ptr output_sptr) { - if (!check(this->_input_density_sptr->has_same_characteristics(*output_sptr), - "output image has wrong characteristics")) + if (!check(this->_input_density_sptr->has_same_characteristics(*output_sptr), "output image has wrong characteristics")) return; shared_ptr diff_sptr(output_sptr->clone()); @@ -198,13 +178,13 @@ 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")) + << "[" << 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); diff --git a/src/include/stir/round.h b/src/include/stir/round.h index 3fda795d8..b2bd86def 100644 --- a/src/include/stir/round.h +++ b/src/include/stir/round.h @@ -13,12 +13,12 @@ /*! \file \ingroup buildblock - + \brief Declaration of the stir::round functions - + \author Kris Thielemans \author Charalampos Tsoumpas - + */ #include "stir/BasicCoordinate.h" @@ -27,26 +27,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); @@ -56,9 +56,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 /*! @@ -72,16 +70,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 037d799be..45bcdfb89 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 @@ -25,71 +25,70 @@ template inline void round_to(integerT& result, const float x) { - if (x>=0) - result = static_cast(x+0.5F); + 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); + 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); + result = static_cast(x + 0.5); } inline void round_to(unsigned long& result, const double x) { - result = static_cast(x+0.5); + result = static_cast(x + 0.5); } /* could be implemented in terms of the above */ -int round(const float x) +int +round(const float x) { - if (x>=0) - return static_cast(x+0.5F); + 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) +int +round(const double x) { - if (x>=0) - return static_cast(x+0.5); + 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 +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 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) +inline void +round_to(BasicCoordinate& result, const BasicCoordinate& x) { - for(int i=1;i<=num_dimensions;++i) - round_to(result[i], x[i]); + 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 deaf7f2f8..c1dfc857c 100644 --- a/src/include/stir/scale_sinograms.h +++ b/src/include/stir/scale_sinograms.h @@ -12,7 +12,7 @@ \file \ingroup projdata \brief declaration of stir::scale_sinograms and stir::get_scale_factors_per_sinogram - + \author Charalampos Tsoumpas \author Kris Thielemans @@ -31,9 +31,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 @@ -51,9 +50,8 @@ 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 28704c364..76942c5be 100644 --- a/src/include/stir/scatter/CreateTailMaskFromACFs.h +++ b/src/include/stir/scatter/CreateTailMaskFromACFs.h @@ -43,7 +43,6 @@ #include "stir/Succeeded.h" #include "stir/is_null_ptr.h" - #include "stir/ParsingObject.h" #include "stir/ProjDataInMemory.h" @@ -58,62 +57,62 @@ START_NAMESPACE_STIR 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() override; - bool post_processing() override; - void set_defaults() override; + void initialise_keymap() override; + bool post_processing() override; + void set_defaults() override; 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 7a43fcf28..11e8def83 100644 --- a/src/include/stir/scatter/ScatterEstimation.h +++ b/src/include/stir/scatter/ScatterEstimation.h @@ -6,7 +6,7 @@ Copyright (C) 2018 - 2019 University of Hull Copyright (C) 2016,2020 University College London Copyright (C) 2022 National Physical Laboratory - + This file is part of STIR. SPDX-License-Identifier: Apache-2.0 @@ -17,7 +17,7 @@ \file \ingroup scatter \brief Definition of class stir::ScatterEstimation. - + \author Nikos Efthimiou \author Kris Thielemans \author Daniel Deidda @@ -42,7 +42,8 @@ START_NAMESPACE_STIR -template class PostFiltering; +template +class PostFiltering; class BinNormalisation; //! A struct to hold the parameters for image masking. @@ -52,7 +53,7 @@ struct MaskingParameters //! 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; }; /*! @@ -81,316 +82,308 @@ 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 = BSpline::BSplineType::linear, - 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; - - //!make projdata 2D shared pointer - shared_ptr make_2D_projdata_sptr(const shared_ptr in_3d_sptr); - shared_ptr make_2D_projdata_sptr(const shared_ptr in_3d_sptr, string template_filename); - - //! - //! \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 = BSpline::BSplineType::linear, + 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; + + //! make projdata 2D shared pointer + shared_ptr make_2D_projdata_sptr(const shared_ptr in_3d_sptr); + shared_ptr make_2D_projdata_sptr(const shared_ptr in_3d_sptr, string template_filename); + + //! + //! \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); - - void set_max_scale_value(float value); - void set_min_scale_value(float value); - void set_mask_projdata_filename(std::string name); - void set_mask_image_filename(std::string name); - void set_output_additive_estimate_prefix(std::string name); - void set_run_debug_mode(bool debug); - void set_restart_reconstruction_every_scatter_iteration(bool setting); - bool get_restart_reconstruction_every_scatter_iteration() const; - - //! 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 - void set_defaults() override; - void initialise_keymap() override; - bool post_processing() override; - - //! 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; - //! If set to true, the activity image will be reset to 1 in - //! each iteration of the scatter estimation. Therefore, more - //! reconstruction subiterations will be required for convergence. - bool restart_reconstruction_every_scatter_iteration; - - //! 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; - - //! variable to check if we have called set_up() - bool _already_setup; + 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); + + void set_max_scale_value(float value); + void set_min_scale_value(float value); + void set_mask_projdata_filename(std::string name); + void set_mask_image_filename(std::string name); + void set_output_additive_estimate_prefix(std::string name); + void set_run_debug_mode(bool debug); + void set_restart_reconstruction_every_scatter_iteration(bool setting); + bool get_restart_reconstruction_every_scatter_iteration() const; + + //! 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 + void set_defaults() override; + void initialise_keymap() override; + bool post_processing() override; + + //! 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; + //! If set to true, the activity image will be reset to 1 in + //! each iteration of the scatter estimation. Therefore, more + //! reconstruction subiterations will be required for convergence. + bool restart_reconstruction_every_scatter_iteration; + + //! 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; -private: + std::string output_additive_estimate_prefix; - //! 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); - - //! 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); - - //! \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; + +private: + //! 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); + + //! 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); + + //! \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 ef1260bcf..1abba41c5 100644 --- a/src/include/stir/scatter/ScatterEstimation.inl +++ b/src/include/stir/scatter/ScatterEstimation.inl @@ -3,72 +3,63 @@ 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 8ab104815..0a2723b92 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -85,379 +85,334 @@ START_NAMESPACE_STIR class ScatterSimulation : public RegisteredObject { public: + //! Default constructor + ScatterSimulation(); + + ~ScatterSimulation() override; + + 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_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); + + //! Get and set methods for the downsample_scanner_bool + //@{ + void set_downsample_scanner_bool(const bool arg); + bool get_downsample_scanner_bool() const; + //@} + + //! Get and set methods for downsample_scanner_rings + //@{ + int get_num_downsample_scanner_rings() const; + void set_num_downsample_scanner_rings(const int arg); + //@} + + //! Get and set methods for downsample_scanner_dets + //@{ + int get_num_downsample_scanner_dets() const; + void set_num_downsample_scanner_dets(const int arg); + //@} + + //! 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(); - //! Default constructor - ScatterSimulation(); - - ~ScatterSimulation() override; - - 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_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); - - - //! Get and set methods for the downsample_scanner_bool - //@{ - void set_downsample_scanner_bool(const bool arg); - bool get_downsample_scanner_bool() const; - //@} - - //! Get and set methods for downsample_scanner_rings - //@{ - int get_num_downsample_scanner_rings() const; - void set_num_downsample_scanner_rings(const int arg); - //@} - - //! Get and set methods for downsample_scanner_dets - //@{ - int get_num_downsample_scanner_dets() const; - void set_num_downsample_scanner_dets(const int arg); - //@} - - //! 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(); - - //! gamma-energy-part of the detection efficiency - /*! - Formula used is based on a Gaussian pdf for the efficiency, with - \f[ FWHM_E = \alpha \sqrt(E) \f] - where the proportionality constant \f$\alpha\f$ is determined by the - energy FWHM of the Scanner at the reference energy. - - This pdf is then integrated from the lower to the upper energy window limits. - - \sa Scanner::get_energy_resolution - \sa Scanner::get_reference_energy - */ - float detection_efficiency(const float energy) const; - - //! \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); - - //! Enable/disable caching of line integrals - void set_use_cache(const bool); - //! Return if line integrals are cached or not - bool get_use_cache() const; + //! gamma-energy-part of the detection efficiency + /*! + Formula used is based on a Gaussian pdf for the efficiency, with + \f[ FWHM_E = \alpha \sqrt(E) \f] + where the proportionality constant \f$\alpha\f$ is determined by the + energy FWHM of the Scanner at the reference energy. -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); - - - - void set_defaults() override; - void initialise_keymap() override; - //! \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. - bool post_processing() override; - - enum image_type{act_image_type, att_image_type}; - struct ScatterPoint - { - CartesianCoordinate3D coord; - float mu_value; - }; - - std::vector< ScatterPoint> scatt_points_vector; - - float scatter_volume; - - //! 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(); + This pdf is then integrated from the lower to the upper energy window limits. - //! 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(); + \sa Scanner::get_energy_resolution + \sa Scanner::get_reference_energy + */ + float detection_efficiency(const float energy) const; - //! 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(); + //! \name Compton scatter cross sections + //@{ + static inline float dif_Compton_cross_section(const float cos_theta, float energy); - /** \name detection related functions - * - * @{ - */ + static inline float total_Compton_cross_section(float energy); - //! 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); + static inline float photon_energy_after_Compton_scatter(const float cos_theta, const float energy); - //! 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); + static inline float photon_energy_after_Compton_scatter_511keV(const float cos_theta); - virtual - void - find_detectors(unsigned& det_num_A, unsigned& det_num_B, const Bin& bin) const; + static inline float total_Compton_cross_section_relative_to_511keV(const float energy); + //@} - 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; - - // next needs to be mutable because find_in_detection_points_vector is const - mutable std::vector > detection_points_vector; + virtual Succeeded set_up(); - //!@} - - //! virtual function that computes the scatter for one (downsampled) bin - virtual double - scatter_estimate(const Bin& bin) = 0; + //! Output the log of the process. + virtual void write_log(const double simulation_time, const float total_scatter); - //! \name integrating functions - //@{ - static - float - integral_between_2_points(const DiscretisedDensity<3,float>& density, - const CartesianCoordinate3D& point1, - const CartesianCoordinate3D& point2); + //! Enable/disable caching of line integrals + void set_use_cache(const bool); + //! Return if line integrals are cached or not + bool get_use_cache() const; - float - exp_integral_over_attenuation_image_between_scattpoint_det (const CartesianCoordinate3D& scatter_point, - const CartesianCoordinate3D& detector_coord); - - - - float - integral_over_activity_image_between_scattpoint_det (const CartesianCoordinate3D& scatter_point, - const CartesianCoordinate3D& detector_coord); - - - - float - cached_integral_over_activity_image_between_scattpoint_det(const unsigned scatter_point_num, - const unsigned det_num); - - float - cached_exp_integral_over_attenuation_image_between_scattpoint_det(const unsigned scatter_point_num, - const unsigned det_num); - //@} - - std::string template_proj_data_filename; - - shared_ptr proj_data_info_sptr; - //! \details Exam info extracted from the scanner template - shared_ptr template_exam_info_sptr; - - std::string density_image_filename; +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); - std::string density_image_for_scatter_points_filename; + float compute_emis_to_det_points_solid_angle_factor(const CartesianCoordinate3D& emis_point, + const CartesianCoordinate3D& detector_coord); - std::string density_image_for_scatter_points_output_filename; + void set_defaults() override; + void initialise_keymap() override; + //! \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. + bool post_processing() override; - shared_ptr< const DiscretisedDensity<3, float> > density_image_sptr; + enum image_type + { + act_image_type, + att_image_type + }; + struct ScatterPoint + { + CartesianCoordinate3D coord; + float mu_value; + }; - //! Pointer to hold the current activity estimation - shared_ptr > activity_image_sptr; - - //! 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::vector scatt_points_vector; - //! Output proj_data fileanme prefix - std::string output_proj_data_filename; - //! Shared ptr to hold the simulated data. - shared_ptr output_proj_data_sptr; + float scatter_volume; - //! threshold below which a voxel in the attenuation image will not be considered as a candidate scatter point - float attenuation_threshold; + //! 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(); - //! 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; + //! 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(); + + //! 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(); + + /** \name detection related functions + * + * @{ + */ + + //! 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); + + //! 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); + + virtual void find_detectors(unsigned& det_num_A, unsigned& det_num_B, const Bin& bin) const; + + 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; + + // 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; + + //! \name integrating functions + //@{ + static float integral_between_2_points(const DiscretisedDensity<3, float>& density, + const CartesianCoordinate3D& point1, + const CartesianCoordinate3D& point2); + + float exp_integral_over_attenuation_image_between_scattpoint_det(const CartesianCoordinate3D& scatter_point, + const CartesianCoordinate3D& detector_coord); + + float integral_over_activity_image_between_scattpoint_det(const CartesianCoordinate3D& scatter_point, + const CartesianCoordinate3D& detector_coord); + + float cached_integral_over_activity_image_between_scattpoint_det(const unsigned scatter_point_num, const unsigned det_num); + + float cached_exp_integral_over_attenuation_image_between_scattpoint_det(const unsigned scatter_point_num, + const unsigned det_num); + //@} + + std::string template_proj_data_filename; + + shared_ptr proj_data_info_sptr; + //! \details Exam info extracted from the scanner template + shared_ptr template_exam_info_sptr; + + std::string density_image_filename; + + std::string density_image_for_scatter_points_filename; + + std::string density_image_for_scatter_points_output_filename; + + shared_ptr> density_image_sptr; + + //! Pointer to hold the current activity estimation + shared_ptr> activity_image_sptr; + + //! 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; - bool _already_set_up; + //! 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; + //! 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 @@ -465,5 +420,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 e56a53a85..4128043b5 100644 --- a/src/include/stir/scatter/ScatterSimulation.inl +++ b/src/include/stir/scatter/ScatterSimulation.inl @@ -30,53 +30,49 @@ START_NAMESPACE_STIR /**************** Functions to set images ****************/ float -ScatterSimulation:: -dif_Compton_cross_section(const float cos_theta, float energy) +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)); + 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) +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 + 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) +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 + return 511.f / (2.f - cos_theta); // for a given energy, energy := 511 keV } float -ScatterSimulation:: -total_Compton_cross_section(const float energy) +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 + 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) +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 + 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 6c0f359c8..679a8efa4 100644 --- a/src/include/stir/scatter/SingleScatterSimulation.h +++ b/src/include/stir/scatter/SingleScatterSimulation.h @@ -21,7 +21,6 @@ #include "stir/scatter/ScatterSimulation.h" #include "stir/RegisteredParsingObject.h" - START_NAMESPACE_STIR /*! @@ -30,67 +29,51 @@ 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); + ~SingleScatterSimulation() override; - ~SingleScatterSimulation() override; + Succeeded process_data() override; + //! gives method information + std::string method_info() const override; + //! prompts the user to enter parameter values manually + void ask_parameters() override; + //! Perform checks and intialisations + Succeeded set_up() override; - Succeeded process_data() override; - //! gives method information - std::string method_info() const override; - //! prompts the user to enter parameter values manually - void ask_parameters() override; - //! Perform checks and intialisations - Succeeded set_up() override; protected: + void initialise(const std::string& parameter_filename); - void initialise(const std::string& parameter_filename); - - void set_defaults() override; - void initialise_keymap() override; + void set_defaults() override; + void initialise_keymap() override; - //! used to check acceptable parameter ranges, etc... - bool post_processing() override; + //! used to check acceptable parameter ranges, etc... + bool post_processing() override; + //! + //! \brief simulate single scatter for one scatter point + double simulate_for_one_scatter_point(const std::size_t scatter_point_num, const unsigned det_num_A, const unsigned det_num_B); - //! - //! \brief simulate single scatter for one scatter point - double - simulate_for_one_scatter_point(const std::size_t scatter_point_num, - const unsigned det_num_A, - const unsigned det_num_B); + double scatter_estimate(const Bin& bin) override; - double - scatter_estimate(const Bin& bin) override; + 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 ab3fbf5b1..1b7fd14ff 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. @@ -23,25 +23,27 @@ #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" -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 -} +# 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 +} // namespace stir #else -#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 -} +# 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 +} // namespace stir #endif #endif diff --git a/src/include/stir/spatial_transformation/GatedSpatialTransformation.h b/src/include/stir/spatial_transformation/GatedSpatialTransformation.h index 611893a06..a11cc1fd6 100644 --- a/src/include/stir/spatial_transformation/GatedSpatialTransformation.h +++ b/src/include/stir/spatial_transformation/GatedSpatialTransformation.h @@ -2,17 +2,17 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + 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__ @@ -33,53 +33,45 @@ 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() override; //!< 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() override; - Succeeded set_up() override; + Succeeded set_up() override; //@} - private: - typedef RegisteredParsingObject base_type; +private: + typedef RegisteredParsingObject base_type; void initialise_keymap() override; - bool post_processing() override; + bool post_processing() override; 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 6d816562f..98a9d3ff0 100644 --- a/src/include/stir/spatial_transformation/InvertAxis.h +++ b/src/include/stir/spatial_transformation/InvertAxis.h @@ -2,15 +2,15 @@ /* Copyright (C) 2019 National Physical Laboratory This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details - */ + */ /*! \file \ingroup spatial_transformation - + \brief This invert the selected image axis. \author Daniel Deidda */ @@ -22,28 +22,24 @@ 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 f4d0ee670..b7940a605 100644 --- a/src/include/stir/spatial_transformation/SpatialTransformation.h +++ b/src/include/stir/spatial_transformation/SpatialTransformation.h @@ -2,17 +2,17 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + 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__ @@ -23,15 +23,15 @@ 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 0716ca119..b58b1721a 100644 --- a/src/include/stir/spatial_transformation/warp_image.h +++ b/src/include/stir/spatial_transformation/warp_image.h @@ -2,15 +2,15 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details - */ + */ /*! \file \ingroup spatial_transformation - + \brief This warps an image. \author Charalampos Tsoumpas */ @@ -23,12 +23,12 @@ 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 40b62955c..3b3c89678 100644 --- a/src/include/stir/stir_math.h +++ b/src/include/stir/stir_math.h @@ -1,9 +1,9 @@ /* Copyright (C) 2016, UCL This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details */ @@ -28,17 +28,21 @@ USING_NAMESPACE_STIR class pow_times_add { 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) + 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; @@ -48,4 +52,3 @@ class pow_times_add }; #endif - diff --git a/src/include/stir/stream.h b/src/include/stir/stream.h index 1f28ae098..eb3c05b11 100644 --- a/src/include/stir/stream.h +++ b/src/include/stir/stream.h @@ -38,52 +38,44 @@ 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 Outputs a Bin to a stream. @@ -94,12 +86,12 @@ operator<<(std::ostream& str, const std::vector& v); [segment_num=xx,....., value=..] \endverbatim */ -inline std::ostream& operator<<(std::ostream& out, const Bin& bin) +inline std::ostream& +operator<<(std::ostream& out, const Bin& bin) { return out << "[segment_num=" << bin.segment_num() << ", axial_pos_num=" << bin.axial_pos_num() << ", view_num=" << bin.view_num() << ", tangential_pos_num=" << bin.tangential_pos_num() - << ", timing_pos_num=" << bin.timing_pos_num() - << ", time_frame_num=" << bin.time_frame_num() + << ", timing_pos_num=" << bin.timing_pos_num() << ", time_frame_num=" << bin.time_frame_num() << ", value=" << bin.get_bin_value() << "]"; } @@ -113,7 +105,8 @@ inline std::ostream& operator<<(std::ostream& out, const Bin& bin) \endverbatim */ template -inline std::ostream& operator<<(std::ostream& out, const DetectionPosition& det_pos) +inline std::ostream& +operator<<(std::ostream& out, const DetectionPosition& det_pos) { return out << "[tangential=" << det_pos.tangential_coord() << ", axial=" << det_pos.axial_coord() << ", radial=" << det_pos.radial_coord() << "]"; @@ -129,37 +122,35 @@ inline std::ostream& operator<<(std::ostream& out, const DetectionPosition& d \endverbatim */ template -inline std::ostream& operator<<(std::ostream& out, const DetectionPositionPair& det_pos) +inline std::ostream& +operator<<(std::ostream& out, const DetectionPositionPair& det_pos) { - return out << "[pos1=" << det_pos.pos1() << ", pos2=" << det_pos.pos2() - << ", timing_pos=" << det_pos.timing_pos() << "]"; + return out << "[pos1=" << det_pos.pos1() << ", pos2=" << det_pos.pos2() << ", timing_pos=" << det_pos.timing_pos() << "]"; } /*! \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 @@ -168,12 +159,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. @@ -181,34 +172,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 e65aae03d..9efea94b3 100644 --- a/src/include/stir/stream.inl +++ b/src/include/stir/stream.inl @@ -32,53 +32,52 @@ START_NAMESPACE_STIR template -std::ostream& +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; + if (v.get_length() > 0) + str << v[v.get_max_index()]; + str << '}' << std::endl; + return str; } template -std::ostream& +std::ostream& operator<<(std::ostream& str, const BasicCoordinate& v) { - str << '{'; - for (int i=1; i0) - str << v[num_dimensions]; - str << '}'; - return str; -} + 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& +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 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& +std::istream& operator>>(std::istream& str, std::vector& v) { v.resize(0); @@ -86,39 +85,38 @@ operator>>(std::istream& str, std::vector& v) str >> std::ws >> c; if (!str || c != '{') return str; - + elemT t; do - { - str >> t; - if (!str.fail()) - { - v.push_back(t); - str >> std::ws >> c; - } - else - break; - } - while (str && c == ','); + { + str >> t; + if (!str.fail()) + { + v.push_back(t); + str >> std::ws >> c; + } + else + break; + } while (str && c == ','); if (str.fail()) - { - str.clear(); - str >> std::ws >> c; - } + { + str.clear(); + str >> std::ws >> c; + } 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!= '}') + { + warning("\nreading a vector, expected closing }, but found EOF or worse. Length of vector returned is %ud\n", v.size()); + return str; + } + + 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& +std::istream& operator>>(std::istream& str, VectorWithOffset& v) { std::vector vv; @@ -129,36 +127,39 @@ operator>>(std::istream& str, VectorWithOffset& v) } template -std::istream& +std::istream& operator>>(std::istream& str, BasicCoordinate& v) { char c = '\0'; str >> std::ws >> c; if (!str || c != '{') - { - warning("reading a coordinate of dimension %d, expected opening {, found %c instead.\n" - "Elements will be undefined", num_dimensions, c); - return str; - } - for (int i=1; i<=num_dimensions; i++) - { - c = '\0'; - str >> v[i]; - str >> std::ws >> c; - if (i> v[i]; + str >> std::ws >> c; + if (i < num_dimensions && (!str || c != ',')) + { + warning("reading a coordinate of dimension %d, expected comma, found %c instead.\n" + "Remaining elements will be undefined", + num_dimensions, + c); + return str; + } + if (i == num_dimensions && (!str || c != '}')) + { + warning("reading a coordinate of dimension %d, expected closing }, found %c instead.", num_dimensions, c); + return str; + } } - } return str; - } END_NAMESPACE_STIR diff --git a/src/include/stir/thresholding.h b/src/include/stir/thresholding.h index b90a2ca00..e62e3d0eb 100644 --- a/src/include/stir/thresholding.h +++ b/src/include/stir/thresholding.h @@ -9,12 +9,12 @@ See STIR/LICENSE.txt for details */ #ifndef __stir_thresholding_H__ -#define __stir_thresholding_H__ +#define __stir_thresholding_H__ /*! \file \ingroup buildblock - \brief Declaration of functions that threshold sequences (specified + \brief Declaration of functions that threshold sequences (specified by iterators). \author Kris Thielemans @@ -33,7 +33,7 @@ START_NAMESPACE_STIR //! Threshold a sequence from above and below /*! \par Type requirements: - +
    • \c forw_iterT is a forward iterator
    • \c elemT must be assignable to *forw_iterT @@ -42,54 +42,50 @@ START_NAMESPACE_STIR */ template inline void -threshold_upper_lower(forw_iterT begin, forw_iterT end, - const elemT new_min, const elemT new_max) +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; + *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) +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; + *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) +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; + *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(). @@ -99,17 +95,15 @@ 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) +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); + 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); + if (smallest_positive_element_iter != end) + threshold_lower(begin, end, (*smallest_positive_element_iter) * small_number); else std::fill(begin, end, small_number); } @@ -119,4 +113,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 dafdca7ae..61d3c12aa 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. @@ -27,8 +27,9 @@ #include "stir/common.h" #include // simply use std::unique_ptr -namespace stir { - using std::unique_ptr; +namespace stir +{ +using std::unique_ptr; } #endif diff --git a/src/include/stir/utilities.h b/src/include/stir/utilities.h index 5629b058e..c0270e996 100644 --- a/src/include/stir/utilities.h +++ b/src/include/stir/utilities.h @@ -8,9 +8,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. @@ -24,42 +24,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 ****/ @@ -75,16 +67,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). @@ -95,14 +84,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 @@ -115,22 +102,16 @@ 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); } @@ -141,65 +122,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); @@ -207,7 +183,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 @@ -218,7 +194,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. @@ -226,7 +202,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. @@ -234,8 +210,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 @@ -243,18 +218,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. @@ -264,9 +237,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'. /*! @@ -276,27 +247,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) @@ -304,20 +271,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. @@ -343,9 +307,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 @@ -372,10 +334,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); //@} @@ -386,10 +345,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 8ab9fa8af..408a4e92b 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 @@ -23,41 +23,34 @@ 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) - { - std::string input; - std::cerr << "\n" << str - << "[" << minimum_value << "," << maximum_value - << " D:" << default_value << "]: "; - std::getline(std::cin, input); - std::istringstream ss(input.c_str()); - - NUMBER value = default_value; - ss >> value; - if ((value>=minimum_value) && (maximum_value>=value)) - return value; - std::cerr << "\nOut of bounds. Try again."; - } -} +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::getline(std::cin, input); + std::istringstream ss(input.c_str()); + NUMBER value = default_value; + ss >> 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 @@ -65,41 +58,47 @@ inline IFSTREAM& open_read_binary(IFSTREAM& s, // 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()); } + { + error("Error opening file %s\n", name.c_str()); + } return s; } template -inline OFSTREAM& open_write_binary(OFSTREAM& s, - const std::string& name) +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; + 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) +char* +strupr(char* const str) { - for (char *a = str; *a; a++) - { - if ((*a >= 'a')&&(*a <= 'z')) *a += 'A'-'a'; - }; + for (char* a = str; *a; a++) + { + if ((*a >= 'a') && (*a <= 'z')) + *a += 'A' - 'a'; + }; return str; } #endif diff --git a/src/include/stir/warning.h b/src/include/stir/warning.h index f775bc269..7d7fc5678 100644 --- a/src/include/stir/warning.h +++ b/src/include/stir/warning.h @@ -38,9 +38,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 @@ -49,7 +47,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. @@ -67,13 +65,12 @@ template inline void warning(const STRING& string, const int verbosity_level = 1) { - if (Verbosity::get() >= verbosity_level) { - std::stringstream sstr; - sstr << "\nWARNING: " - << string - << std::endl; - writeText(sstr.str().c_str(), WARNING_CHANNEL); - } + if (Verbosity::get() >= verbosity_level) + { + std::stringstream sstr; + sstr << "\nWARNING: " << string << std::endl; + writeText(sstr.str().c_str(), WARNING_CHANNEL); + } } END_NAMESPACE_STIR #endif diff --git a/src/include/stir/zoom.h b/src/include/stir/zoom.h index cbc78f9dd..1b8779d0f 100644 --- a/src/include/stir/zoom.h +++ b/src/include/stir/zoom.h @@ -9,11 +9,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 @@ -24,15 +24,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) @@ -42,13 +42,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 @@ -57,27 +57,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. */ @@ -86,12 +86,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 @@ -103,34 +109,34 @@ 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 @@ -138,21 +144,20 @@ 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. @@ -169,19 +174,18 @@ 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. @@ -190,49 +194,46 @@ 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 1b9608db8..6a8711bea 100644 --- a/src/include/stir_experimental/AbsTimeInterval.h +++ b/src/include/stir_experimental/AbsTimeInterval.h @@ -28,35 +28,27 @@ START_NAMESPACE_STIR Absolute time means at present 'secs since midnight 1/1/1970 UTC' */ -class AbsTimeInterval: public RegisteredObject +class AbsTimeInterval : public RegisteredObject { public: ~AbsTimeInterval() override {} 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: + : _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 bbdbe9762..fb602be85 100644 --- a/src/include/stir_experimental/AbsTimeIntervalFromDynamicData.h +++ b/src/include/stir_experimental/AbsTimeIntervalFromDynamicData.h @@ -30,7 +30,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 @@ -44,27 +44,25 @@ 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; ~AbsTimeIntervalFromDynamicData() override {} //! default constructor gives ill-defined values AbsTimeIntervalFromDynamicData(); //! read info from file /*! will call error() if something goes wrong */ - AbsTimeIntervalFromDynamicData(const std::string& filename, + 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; @@ -73,9 +71,7 @@ class AbsTimeIntervalFromDynamicData void initialise_keymap() override; bool post_processing() override; - Succeeded set_times(); - }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/AbsTimeIntervalFromECAT7ACF.h b/src/include/stir_experimental/AbsTimeIntervalFromECAT7ACF.h index 7c39292a1..12cea4dd3 100644 --- a/src/include/stir_experimental/AbsTimeIntervalFromECAT7ACF.h +++ b/src/include/stir_experimental/AbsTimeIntervalFromECAT7ACF.h @@ -28,30 +28,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 +class AbsTimeIntervalFromECAT7ACF : 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; ~AbsTimeIntervalFromECAT7ACF() override {} //! 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; void set_defaults() override; @@ -59,7 +55,6 @@ class AbsTimeIntervalFromECAT7ACF bool post_processing() override; Succeeded set_times(); - }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/AbsTimeIntervalWithParsing.h b/src/include/stir_experimental/AbsTimeIntervalWithParsing.h index 81463c48d..c602969f1 100644 --- a/src/include/stir_experimental/AbsTimeIntervalWithParsing.h +++ b/src/include/stir_experimental/AbsTimeIntervalWithParsing.h @@ -30,28 +30,23 @@ 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; ~AbsTimeIntervalWithParsing() override {} //! default constructor sets times to invalid values AbsTimeIntervalWithParsing(); - - private: +private: void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/DAVArrayFilter3D.h b/src/include/stir_experimental/DAVArrayFilter3D.h index d331db0d0..59670a6a3 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. */ @@ -20,39 +20,33 @@ 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 9ccc494aa..e7d5c9ebd 100644 --- a/src/include/stir_experimental/DAVImageFilter3D.h +++ b/src/include/stir_experimental/DAVImageFilter3D.h @@ -16,13 +16,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" @@ -31,42 +30,36 @@ 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 407b0fa5e..57fedf62c 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 @@ -15,9 +15,8 @@ See STIR/LICENSE.txt for details */ - #ifndef __FILTER_H__ -#define __FILTER_H__ +#define __FILTER_H__ #include "stir/TimedObject.h" #include "stir/Array.h" @@ -26,8 +25,8 @@ START_NAMESPACE_STIR -template class Array; - +template +class Array; /*! \brief Preliminary class for 1D filtering using FFTs @@ -35,112 +34,118 @@ 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) - {} + : 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); @@ -149,24 +154,22 @@ 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++) - { - // 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); - } + 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); + } 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 e7ff49682..f683a7e1a 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 @@ -22,8 +22,6 @@ #ifndef __stir_ModifiedInverseAveragingImageFilterAll_H__ #define __stir_ModifiedInverseAveragingImageFilterAll_H__ - - #include "stir_experimental/ModifiedInverseAverigingArrayFilter.h" #include "stir/DiscretisedDensity.h" #include "stir/DataProcessor.h" @@ -35,106 +33,96 @@ #include "stir/shared_ptr.h" - - - START_NAMESPACE_STIR // TODO!! remove define #define num_dimensions 3 - template -class ModifiedInverseAveragingImageFilterAll: -public - RegisteredParsingObject< - ModifiedInverseAveragingImageFilterAll, - DataProcessor >, - DataProcessor > - > +class ModifiedInverseAveragingImageFilterAll + : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { - private: - typedef - RegisteredParsingObject< - ModifiedInverseAveragingImageFilterAll, - DataProcessor >, - DataProcessor > - > - base_type; -public: - static const char * const registered_name; +private: + typedef RegisteredParsingObject, + DataProcessor>, + DataProcessor>> + base_type; - //! 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: +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: 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 dec32e7d5..dc8392d1d 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 @@ -33,48 +33,40 @@ #include "stir/Array.h" #include "stir/IndexRange.h" - START_NAMESPACE_STIR -class FFT_routines +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; - +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 f64632763..ede950d6d 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 @@ -22,7 +22,6 @@ #ifndef __stir_ModifiedInverseAverigingImageFilter_H__ #define __stir_ModifiedInverseAverigingImageFilter_H__ - #include "stir_experimental/ModifiedInverseAverigingArrayFilter.h" #include "stir/DiscretisedDensity.h" #include "stir/DataProcessor.h" @@ -31,89 +30,74 @@ #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 > - > +class ModifiedInverseAverigingImageFilter + : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { - private: - typedef - RegisteredParsingObject< - ModifiedInverseAverigingImageFilter, - DataProcessor >, - DataProcessor > - > - base_type; -public: - static const char * const registered_name; +private: + typedef RegisteredParsingObject, + DataProcessor>, + DataProcessor>> + base_type; - //! 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: +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: 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 60113ea2d..357c317e2 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 @@ -22,8 +22,6 @@ #ifndef __stir_NonseparableSpatiallyVaryingFilters_H__ #define __stir_NonseparableSpatiallyVaryingFilters_H__ - - #include "stir_experimental/ModifiedInverseAverigingArrayFilter.h" #include "stir/DiscretisedDensity.h" #include "stir/DataProcessor.h" @@ -35,101 +33,85 @@ #include "stir/shared_ptr.h" - - - START_NAMESPACE_STIR // TODO!! remove define #define num_dimensions 3 - template -class NonseparableSpatiallyVaryingFilters: -public - RegisteredParsingObject< - NonseparableSpatiallyVaryingFilters, - DataProcessor >, - DataProcessor > - > +class NonseparableSpatiallyVaryingFilters + : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { - private: - typedef - RegisteredParsingObject< - NonseparableSpatiallyVaryingFilters, - DataProcessor >, - DataProcessor > - > - base_type; -public: - static const char * const registered_name; +private: + typedef RegisteredParsingObject, + DataProcessor>, + DataProcessor>> + base_type; - //! 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: +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: 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 61f7be7af..4ba22ae19 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 @@ -21,8 +21,6 @@ #ifndef __stir_NonseparableSpatiallyVaryingFilters3D_H__ #define __stir_NonseparableSpatiallyVaryingFilters3D_H__ - - #include "stir_experimental/ModifiedInverseAverigingArrayFilter.h" #include "stir/DiscretisedDensity.h" #include "stir/DataProcessor.h" @@ -34,101 +32,87 @@ #include "stir/shared_ptr.h" - - - START_NAMESPACE_STIR // TODO!! remove define #define num_dimensions 3 - template -class NonseparableSpatiallyVaryingFilters3D: -public - RegisteredParsingObject< - NonseparableSpatiallyVaryingFilters3D, - DataProcessor >, - DataProcessor > - > +class NonseparableSpatiallyVaryingFilters3D + : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { - private: - typedef - RegisteredParsingObject< - NonseparableSpatiallyVaryingFilters3D, - DataProcessor >, - DataProcessor > - > - base_type; -public: - static const char * const registered_name; +private: + typedef RegisteredParsingObject, + DataProcessor>, + DataProcessor>> + base_type; - //! 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: +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: 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 a9d368690..86eb4d316 100644 --- a/src/include/stir_experimental/Quaternion.h +++ b/src/include/stir_experimental/Quaternion.h @@ -15,8 +15,6 @@ \author Kris Thielemans */ - - #ifndef __stir_Quaternion_H__ #define __stir_Quaternion_H__ @@ -25,41 +23,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 5dd9deb3b..6fc24bdbd 100644 --- a/src/include/stir_experimental/Quaternion.inl +++ b/src/include/stir_experimental/Quaternion.inl @@ -15,58 +15,54 @@ \author Kris Thielemans */ - - START_NAMESPACE_STIR - template -coordT norm_squared(const Quaternion& q) +coordT +norm_squared(const Quaternion& q) { - return square(q[1]) + square(q[2]) +square(q[3])+ square(q[4]); + 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) +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])); + 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) +Quaternion& +Quaternion::operator*=(const coordT& a) { - for (int i=1; i<=4; i++) + 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; @@ -75,8 +71,8 @@ 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; @@ -84,20 +80,19 @@ Quaternion::operator* (const coordT& a) const } template -Quaternion& -Quaternion:: operator/= (const coordT& a) +Quaternion& +Quaternion::operator/=(const coordT& a) { - for (int i=1; i<=4; i++) + for (int i = 1; i <= 4; i++) (*this)[i] /= a; return *this; - } template -Quaternion& -Quaternion::operator/= (const Quaternion& q) +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])); + 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; @@ -105,72 +100,68 @@ Quaternion::operator/= (const Quaternion& q) } template -Quaternion +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 () +void +Quaternion::neg_quaternion() { - (*this)[1] =-(*this)[1]; - (*this)[2] =-(*this)[2]; - (*this)[3] =-(*this)[3]; - (*this)[4] =-(*this)[4]; - + (*this)[1] = -(*this)[1]; + (*this)[2] = -(*this)[2]; + (*this)[3] = -(*this)[3]; + (*this)[4] = -(*this)[4]; } - - template -void -Quaternion:: conjugate() +void +Quaternion::conjugate() { -// (*this)[1] =(*this)[1]; - (*this)[2] =-(*this)[2]; - (*this)[3] =-(*this)[3]; - (*this)[4] =-(*this)[4]; + // (*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(); @@ -178,7 +169,8 @@ Quaternion conjugate(const Quaternion& q) } template -Quaternion inverse(const Quaternion& q) +Quaternion +inverse(const Quaternion& q) { Quaternion tmp = q; tmp.inverse(); diff --git a/src/include/stir_experimental/SeparableGaussianArrayFilter.h b/src/include/stir_experimental/SeparableGaussianArrayFilter.h index 582a970b7..43ce7df05 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,23 @@ START_NAMESPACE_STIR - template -class SeparableGaussianArrayFilter: - public SeparableArrayFunctionObject +class SeparableGaussianArrayFilter : public SeparableArrayFunctionObject { -public: - +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; + 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 9e3438d0a..2a4b18171 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,39 @@ START_NAMESPACE_STIR #define num_dimensions 3 template -class SeparableGaussianImageFilter : - public - RegisteredParsingObject< - SeparableGaussianImageFilter, - DataProcessor >, - DataProcessor > - > +class SeparableGaussianImageFilter : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { - private: - typedef - RegisteredParsingObject< - SeparableGaussianImageFilter, - DataProcessor >, - DataProcessor > - > - base_type; +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 +70,3 @@ class SeparableGaussianImageFilter : END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir_experimental/SeparableLowPassArrayFilter.h b/src/include/stir_experimental/SeparableLowPassArrayFilter.h index 95367aafb..095e72398 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 @@ -29,24 +29,20 @@ START_NAMESPACE_STIR - template -class SeparableLowPassArrayFilter: - public SeparableArrayFunctionObject +class SeparableLowPassArrayFilter : public SeparableArrayFunctionObject { -public: - +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 d11b93aa1..eb7080757 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 */ @@ -33,127 +33,105 @@ 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 +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 + // 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 +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; + 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 +class SeparableLowPassArrayFilter2 : public SeparableArrayFunctionObject2 { -public: - +public: //! Default constructor - SeparableLowPassArrayFilter2(); - + SeparableLowPassArrayFilter2(); + SeparableLowPassArrayFilter2(const VectorWithOffset& filter_coefficients); - + private: - VectorWithOffset filter_coefficients; - + VectorWithOffset filter_coefficients; }; - template -SeparableLowPassArrayFilter2:: -SeparableLowPassArrayFilter2() +SeparableLowPassArrayFilter2::SeparableLowPassArrayFilter2() { - for (int i=1;i<=num_dimensions;i++) - { - all_1d_array_filters[i-1] = - new ArrayFilter1DUsingConvolution(); - } + 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) +template +SeparableLowPassArrayFilter2::SeparableLowPassArrayFilter2( + const VectorWithOffset& filter_coefficients_v) + : filter_coefficients(filter_coefficients_v) { - assert(num_dimensions==3); + 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 f9b1cc61d..cd778d795 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 @@ -19,13 +19,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 @@ -33,49 +31,40 @@ START_NAMESPACE_STIR #define num_dimensions 3 template -class SeparableLowPassImageFilter : - public - RegisteredParsingObject< - SeparableLowPassImageFilter, - DataProcessor >, - DataProcessor > - > +class SeparableLowPassImageFilter : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { - private: - typedef - RegisteredParsingObject< - SeparableLowPassImageFilter, - DataProcessor >, - DataProcessor > - > - base_type; +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 @@ -83,5 +72,3 @@ class SeparableLowPassImageFilter : END_NAMESPACE_STIR #endif - - diff --git a/src/include/stir_experimental/fft.h b/src/include/stir_experimental/fft.h index f760ac76b..8f52831aa 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 eb68edc5d..3a36e4c38 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 @@ -11,49 +11,52 @@ #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 e462b4b99..006e43bc6 100644 --- a/src/include/stir_experimental/listmode/CListModeDataLMF.h +++ b/src/include/stir_experimental/listmode/CListModeDataLMF.h @@ -4,9 +4,9 @@ \file \ingroup ClearPET_utilities \brief Declaration of class stir::CListModeDataLMF - + \author Kris Thielemans - + */ /* Copyright (C) 2003- 2004, Hammersmith Imanet Ltd @@ -22,7 +22,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 @@ -30,53 +30,40 @@ START_NAMESPACE_STIR - //! A class that reads the listmode data from an LMF file 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 cbe0a4acd..26109e2ea 100644 --- a/src/include/stir_experimental/listmode/CListRecordLMF.h +++ b/src/include/stir_experimental/listmode/CListRecordLMF.h @@ -3,10 +3,10 @@ /*! \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 @@ -29,27 +29,23 @@ class CListModeDataLMF; //! Class for storing and using a coincidence event from a listmode file /*! \ingroup ClearPET_utilities */ -class CListEventDataLMF +class CListEventDataLMF { - public: - inline bool is_prompt() const { return true; } // TODO +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,16 +56,17 @@ class CListRecordLMF; */ 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; } +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 @@ -81,54 +78,39 @@ That's obviously not necessary nor desirable. 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; } + { + 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 e4b1bacfd..381c565ca 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" @@ -35,37 +34,32 @@ START_NAMESPACE_STIR 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; void process_new_time_event(const ListTime& time_event) override; Succeeded set_up() override; - -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; void start_new_time_frame(const unsigned int new_frame_num) override; - void set_defaults() override; void initialise_keymap() override; bool post_processing() override; 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 ff8c04677..f6f6ff271 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 082d7cd07..caa531dce 100644 --- a/src/include/stir_experimental/modelling/BloodFrame.h +++ b/src/include/stir_experimental/modelling/BloodFrame.h @@ -15,7 +15,7 @@ \brief Declaration of class stir::PlasmaData \author Charalampos Tsoumpas - + */ #ifndef __stir_modelling_BloodFrame_H__ @@ -28,41 +28,41 @@ START_NAMESPACE_STIR 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 f3ac55e98..1706fe6af 100644 --- a/src/include/stir_experimental/modelling/BloodFrame.inl +++ b/src/include/stir_experimental/modelling/BloodFrame.inl @@ -19,61 +19,86 @@ START_NAMESPACE_STIR - //! default constructor +//! 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) +{} +//! 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 ); + 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. +//! 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 ); + BloodFrame::set_frame_num(frame_num); + BloodFrame::set_blood_counts_in_kBq(blood_sample_counts); } - //! default destructor +//! 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 ; } +{} - //! 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 52ce5d699..fde860f38 100644 --- a/src/include/stir_experimental/modelling/BloodFrameData.h +++ b/src/include/stir_experimental/modelling/BloodFrameData.h @@ -15,7 +15,7 @@ \brief Declaration of class stir::BloodFrameData \author Charalampos Tsoumpas - + */ #ifndef __stir_modelling_BloodFrameData_H__ @@ -26,87 +26,83 @@ 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 ) ; - - */ + 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); + // ChT::ToDO: Better to use iterators + 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 8dfa3bc5e..a4e862b0b 100644 --- a/src/include/stir_experimental/modelling/BloodFrameData.inl +++ b/src/include/stir_experimental/modelling/BloodFrameData.inl @@ -23,115 +23,136 @@ START_NAMESPACE_STIR //! default constructor BloodFrameData::BloodFrameData() -{ } +{} //! constructor giving a vector -//ChT::ToDO: Better to use iterators -BloodFrameData::BloodFrameData(const std::vector & blood_plot) -{this->_blood_plot=blood_plot;} +// ChT::ToDO: Better to use iterators +BloodFrameData::BloodFrameData(const std::vector& blood_plot) +{ + this->_blood_plot = blood_plot; +} //! default destructor 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) +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"); + 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); - } - } + 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) +//! 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); + 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())); + 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() ; } +{ + return this->_blood_plot.begin(); +} BloodFrameData::const_iterator BloodFrameData::end() const -{ return this->_blood_plot.end() ; } +{ + return this->_blood_plot.end(); +} unsigned int BloodFrameData::size() const -{ return this->_blood_plot.size() ; } +{ + 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 1df3da40b..a9518cb74 100644 --- a/src/include/stir_experimental/modelling/OneParamModel.h +++ b/src/include/stir_experimental/modelling/OneParamModel.h @@ -26,21 +26,20 @@ START_NAMESPACE_STIR class OneParamModel { - public: - +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 72d20a395..8ae74ece6 100644 --- a/src/include/stir_experimental/modelling/OneParamModel.inl +++ b/src/include/stir_experimental/modelling/OneParamModel.inl @@ -21,42 +21,45 @@ START_NAMESPACE_STIR //! default constructor OneParamModel::OneParamModel() -{ _matrix_is_stored=false; } +{ + _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; + this->_matrix_is_stored = false; + this->_starting_frame = starting_frame; + this->_last_frame = last_frame; } //! default destructor 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) +{} + +//! 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; + 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; _unit_matrix.set_model_array(unit_array); - _matrix_is_stored=true; + _matrix_is_stored = true; } - return _unit_matrix ; + 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 2671fd6f5..506b7f16d 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" @@ -33,13 +33,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: @@ -47,7 +47,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. @@ -60,9 +60,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 @@ -71,7 +71,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 @@ -85,44 +85,39 @@ 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 { 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 std::string& get_image_filename_prefix() const - { return _image_filename_prefix; } - - const RigidObject3DMotion& get_motion() const - { return *_ro3d_sptr; } + const std::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 void set_defaults() override; void initialise_keymap() override; @@ -136,11 +131,12 @@ class MatchTrackerAndScanner : public ParsingObject std::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 e0f7e1843..14e0bd027 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,46 @@ 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 +107,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 10491ae31..60c13aa0e 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,23 @@ 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; ~ObjectTransformation() override {} - //! 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 59ddf2935..293f349d9 100644 --- a/src/include/stir_experimental/motion/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h +++ b/src/include/stir_experimental/motion/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.h @@ -20,7 +20,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" @@ -38,38 +37,34 @@ class GatedProjData; \brief */ template -class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion -: public RegisteredParsingObject - , - GeneralisedObjectiveFunction, - SumOfGeneralisedObjectiveFunctions, - TargetT, - PoissonLogLikelihoodWithLinearModelForMean > -> +class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion + : public RegisteredParsingObject< + PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion, + GeneralisedObjectiveFunction, + SumOfGeneralisedObjectiveFunctions, + TargetT, + PoissonLogLikelihoodWithLinearModelForMean>> { - private: - typedef - RegisteredParsingObject - , - GeneralisedObjectiveFunction, - SumOfGeneralisedObjectiveFunctions, - TargetT, - PoissonLogLikelihoodWithLinearModelForMean > - > - base_type; +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. */ @@ -78,28 +73,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; @@ -113,12 +100,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 @@ -135,7 +122,6 @@ class PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion double Zoffset; /********************************/ - //! Stores the projectors that are used for the computations shared_ptr projector_pair_ptr; @@ -145,13 +131,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(); @@ -161,7 +147,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 1b57460da..dd3684754 100644 --- a/src/include/stir_experimental/motion/Polaris_MT_File.h +++ b/src/include/stir_experimental/motion/Polaris_MT_File.h @@ -25,11 +25,15 @@ #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 +53,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,7 +63,7 @@ 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 @@ -68,46 +72,47 @@ 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; - }; + 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 c5fb7a095..862eea268 100644 --- a/src/include/stir_experimental/motion/RigidObject3DMotion.h +++ b/src/include/stir_experimental/motion/RigidObject3DMotion.h @@ -29,51 +29,43 @@ 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: ~RigidObject3DMotion() override {} - //! 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 +78,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 +97,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: void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - }; END_NAMESPACE_STIR diff --git a/src/include/stir_experimental/motion/RigidObject3DMotionFromPolaris.h b/src/include/stir_experimental/motion/RigidObject3DMotionFromPolaris.h index a1d1808d8..60c6a17fc 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(); - RigidObject3DTransformation - compute_average_motion_in_tracker_coords_rel_time(const double start_time, const double end_time) const override; + RigidObject3DTransformation compute_average_motion_in_tracker_coords_rel_time(const double start_time, + const double end_time) const override; - - RigidObject3DTransformation - get_motion_in_tracker_coords_rel_time(const double time) const override; + RigidObject3DTransformation get_motion_in_tracker_coords_rel_time(const double time) const override; - std::vector - get_rel_time_of_samples(const double start_time, const double end_time) const override; + std::vector get_rel_time_of_samples(const double start_time, const double end_time) const override; //! 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: Succeeded synchronise() override; double secs_since_1970_to_rel_time(std::time_t) const override; - const RigidObject3DTransformation& - get_transformation_to_scanner_coords() const override; - const RigidObject3DTransformation& - get_transformation_from_scanner_coords() const override; - void - set_transformation_from_scanner_coords(const RigidObject3DTransformation&) override; + const RigidObject3DTransformation& get_transformation_to_scanner_coords() const override; + const RigidObject3DTransformation& get_transformation_from_scanner_coords() const override; + void set_transformation_from_scanner_coords(const RigidObject3DTransformation&) override; 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); bool is_synchronised() const override; 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 0072c0863..4f4923033 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] @@ -63,15 +62,11 @@ class Succeeded; \todo define Euler angles (the code is derived from the Polaris manual) */ class RigidObject3DTransformation - : - public - RegisteredParsingObject, - ObjectTransformation<3,float> > + : 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 +75,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 +85,32 @@ 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 +122,25 @@ class RigidObject3DTransformation Succeeded set_euler_angles(); #endif - //! Transform point + //! Transform point // can't return CartesianCoordinate3D anymore because virtual function - - BasicCoordinate<3,float> - transform_point(const BasicCoordinate<3,float>& point) const override; + + BasicCoordinate<3, float> transform_point(const BasicCoordinate<3, float>& point) const override; //! Computes the jacobian for the transformation (which is always 1) - float jacobian(const BasicCoordinate<3,float>& point) const override - { return 1; } + float jacobian(const BasicCoordinate<3, float>& point) const override + { + return 1; + } //! Transform bin from some projection data /*! Finds 'closest' (in some sense) bin to the transformed LOR. - if \c NEW_ROT is not \c \#defined at compilation time, + if \c NEW_ROT is not \c \#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 +158,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 +187,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 a5ceed744..7f6d88898 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,7 +57,7 @@ START_NAMESPACE_STIR END := \endverbatim -*/ +*/ class TimeFrameMotion : public ParsingObject { public: @@ -74,40 +74,32 @@ 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 void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - private: std::string _frame_definition_filename; bool _do_move_to_reference; @@ -116,13 +108,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 759b34936..3d98ec86c 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,26 @@ 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 > - > +class Transform3DObjectImageProcessor : public RegisteredParsingObject, + DataProcessor>, + DataProcessor>> { - typedef DataProcessor > base_type; + 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 +59,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 +83,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 2205ea6cf..5858fa484 100644 --- a/src/include/stir_experimental/motion/bin_interpolate.h +++ b/src/include/stir_experimental/motion/bin_interpolate.h @@ -26,12 +26,11 @@ START_NAMESPACE_STIR -static -Succeeded +static Succeeded get_transformed_LOR(LORInAxialAndNoArcCorrSinogramCoordinates& out_lor, - const RigidObject3DTransformation& transformation, - const Bin& bin, - const ProjDataInfo& in_proj_data_info) + const RigidObject3DTransformation& transformation, + const Bin& bin, + const ProjDataInfo& in_proj_data_info) { LORInAxialAndNoArcCorrSinogramCoordinates lor; in_proj_data_info.get_LOR(lor, bin); @@ -40,38 +39,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 +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 +static Coordinate4D bin_to_coords(const Bin& bin) { Coordinate4D coord; @@ -82,9 +77,7 @@ bin_to_coords(const Bin& bin) return coord; } - -static -Bin +static Bin coords_to_bin(const Coordinate4D& coord) { Bin bin; @@ -95,127 +88,119 @@ 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) +inline Coordinate4D +sign(const Coordinate4D& c) { - return Coordinate4D (sign(c[1]),sign(c[2]),sign(c[3]),sign(c[4])); + return Coordinate4D(sign(c[1]), sign(c[2]), sign(c[3]), sign(c[4])); } -inline -Coordinate4D abs (const Coordinate4D& c) +inline Coordinate4D +abs(const Coordinate4D& c) { - return Coordinate4D (fabs(c[1]),fabs(c[2]),fabs(c[3]),fabs(c[4])); + 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) +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; + (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += value; } -static -bool +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()) - ) + 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()); + 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 +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()) + if (bin.view_num() < proj_data_info.get_min_view_num()) { swap_direction = true; - bin.view_num()+=proj_data_info.get_num_views(); + 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(); + 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()); + 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; + bin.tangential_pos_num() *= -1; + bin.segment_num() *= -1; } return bin; } - -static -Succeeded +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) + 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); + 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; + 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; @@ -223,74 +208,70 @@ 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 ddf2ad78b..77bf011c1 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,11 @@ 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 +64,11 @@ 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 +77,64 @@ 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) +inline void +assign(std::pair, float>& x, T2 y) { - BasicCoordinate<3,float> tmp; - assign(tmp,y); - x = std::make_pair(tmp,float(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 ddc0848bc..03407f1fc 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,65 @@ 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) - { - 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); - 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); - } + 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); + 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); + } 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) - { - 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); - 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); - - } + 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); + 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); + } 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 670e171f4..e7df7abd1 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 @@ -18,7 +18,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" @@ -26,51 +25,43 @@ 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 5b5cecdb0..631dac2b8 100644 --- a/src/include/stir_experimental/numerics/linear_extrapolation.h +++ b/src/include/stir_experimental/numerics/linear_extrapolation.h @@ -9,7 +9,7 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics \brief stir::linear_extrapolation @@ -17,17 +17,15 @@ */ - #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 9be43b200..9019dff1a 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,23 @@ 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 +59,56 @@ 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) + : _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); + 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) + : _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); + 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 +117,56 @@ PushTransposeLinearInterpolator \todo preliminary. We might want to derive this from a class or so. */ template -class -PullNearestNeighbourInterpolator +class PullNearestNeighbourInterpolator { public: PullNearestNeighbourInterpolator() - : _input_ptr(0) + : _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); + 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) + : _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); + 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 c04de3c1d..b4506e92d 100644 --- a/src/include/stir_experimental/numerics/more_interpolators.inl +++ b/src/include/stir_experimental/numerics/more_interpolators.inl @@ -17,24 +17,20 @@ #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) +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); + // 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() && - 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()) + 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]; } @@ -44,70 +40,52 @@ pull_nearest_neighbour_interpolate(const Array<3, elemT>& in, template void -push_nearest_neighbour_interpolate(Array& out, - const BasicCoordinate& point_in_output_coords, - valueT value) +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); -} - + 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); +} template elemT -pull_linear_interpolate(const Array<3, elemT>& in, - const BasicCoordinate<3, positionT>& point_in_input_coords) +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]))); + // 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() && - 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()) + 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 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])) - ); + 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; @@ -115,46 +93,41 @@ pull_linear_interpolate(const Array<3, elemT>& in, template void -push_transpose_linear_interpolate(Array<3, elemT>& out, - const BasicCoordinate<3, positionT>& point_in_output_coords, - valueT value) +push_transpose_linear_interpolate(Array<3, elemT>& out, const BasicCoordinate<3, positionT>& point_in_output_coords, valueT value) { - if (value==0) - return; + 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() && - 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()) + 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 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[z2][y1][x1] += ixc * iyc * iz * value; out[z1][y2][x1] += ixc * iy * izc * value; - out[z2][y2][x1] += ixc * iy * iz * 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[z2][y1][x2] += ix * iyc * iz * value; out[z1][y2][x2] += ix * iy * izc * value; - out[z2][y2][x2] += ix * iy * iz * value; + out[z2][y2][x2] += ix * iy * iz * value; } } diff --git a/src/include/stir_experimental/phantoms/CylindersWithLineSource.h b/src/include/stir_experimental/phantoms/CylindersWithLineSource.h index bd9b8dafe..d093a7df8 100644 --- a/src/include/stir_experimental/phantoms/CylindersWithLineSource.h +++ b/src/include/stir_experimental/phantoms/CylindersWithLineSource.h @@ -6,153 +6,129 @@ #include "stir/Shape/EllipsoidalCylinder.h" #include "stir/Shape/CombinedShape3D.h" - - - START_NAMESPACE_STIR 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); + A_ptr = new EllipsoidalCylinder(150, 0, 0, CartesianCoordinate3D(0, 0, 0), 0, 0, 0); } -void +void LineSource_phantom::translate(const CartesianCoordinate3D& direction) { - A_ptr->translate(direction); + A_ptr->translate(direction); } -void +void LineSource_phantom::scale(const CartesianCoordinate3D& scale3D) { - //check this!!! + // 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 ; - + shared_ptr full_A = get_A_ptr()->clone(); + return full_A; } 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() { // 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 + // 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 /* 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 +137,59 @@ 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 +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); + // A_ptr->translate(direction); + B_ptr->translate(direction); + C_ptr->translate(direction); + // B1_ptr->translate(direction); + // C1_ptr->translate(direction); } -void +void CylindersWithLineSource_phantom::scale(const CartesianCoordinate3D& scale3D) { - //check this!!! - //A_ptr->scale_around_origin(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; - - -} + // 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 bd27afd8b..ad8a57517 100644 --- a/src/include/stir_experimental/phantoms/Utah.h +++ b/src/include/stir_experimental/phantoms/Utah.h @@ -11,7 +11,7 @@ #ifndef __stir_phantoms_Utah_H__ #define __stir_phantoms_Utah_H__ /*! - \file + \file \ingroup Shape \brief inline implementations for stir::Utah_phantom. @@ -25,54 +25,47 @@ #include "stir/Shape/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 { 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) @@ -80,7 +73,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) @@ -103,63 +96,52 @@ class Utah_phantom 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); + // 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 +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 +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 +void Utah_phantom::translate(const CartesianCoordinate3D& direction) { A_ptr->translate(direction); @@ -171,7 +153,7 @@ Utah_phantom::translate(const CartesianCoordinate3D& direction) E_ptr->translate(direction); } -void +void Utah_phantom::scale(const CartesianCoordinate3D& scale3D) { A_ptr->scale(scale3D); diff --git a/src/include/stir_experimental/recon_buildblock/BinNormalisationFromML2D.h b/src/include/stir_experimental/recon_buildblock/BinNormalisationFromML2D.h index fd41fb6a4..3bb68a261 100644 --- a/src/include/stir_experimental/recon_buildblock/BinNormalisationFromML2D.h +++ b/src/include/stir_experimental/recon_buildblock/BinNormalisationFromML2D.h @@ -34,7 +34,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 @@ -54,16 +54,15 @@ 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. */ @@ -73,16 +72,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. */ void apply(RelatedViewgrams& viewgrams) const override; //! 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. */ void undo(RelatedViewgrams& viewgrams) const override; @@ -101,7 +100,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 f460c5b15..71ef223cb 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,21 @@ 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 +54,13 @@ class BinNormalisationSinogramRescaling : float get_bin_efficiency(const Bin& bin) const override; //! Normalise some data - /*! + /*! This means \c multiply with the data in the scale factors file. */ void apply(RelatedViewgrams& viewgrams) const override; //! Undo the normalisation of some data - /*! + /*! This means \c divide with the data in th scale factors file. */ void undo(RelatedViewgrams& viewgrams) const override; @@ -73,7 +69,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 void set_defaults() override; @@ -83,7 +79,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 e19d48c87..13bc3d13b 100644 --- a/src/include/stir_experimental/recon_buildblock/BinNormalisationUsingProfile.h +++ b/src/include/stir_experimental/recon_buildblock/BinNormalisationUsingProfile.h @@ -24,12 +24,11 @@ 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(); @@ -39,10 +38,10 @@ class BinNormalisationUsingProfile : void undo(RelatedViewgrams& viewgrams) const override; - float get_bin_efficiency(const Bin& bin) const override { return 1;} - + float get_bin_efficiency(const Bin& bin) const override { return 1; } + private: - mutable Array<1,float> profile; + mutable Array<1, float> profile; std::string profile_filename; void set_defaults() override; @@ -53,4 +52,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 8343c7b4d..4b139c991 100644 --- a/src/include/stir_experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.h +++ b/src/include/stir_experimental/recon_buildblock/DataSymmetriesForDensels_PET_CartesianGrid.h @@ -16,12 +16,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" @@ -33,12 +32,14 @@ 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 @@ -49,22 +50,19 @@ class DataSymmetriesForDensels_PET_CartesianGrid : public DataSymmetriesForDense 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); - #ifndef STIR_NO_COVARIANT_RETURN_TYPES - DataSymmetriesForDensels_PET_CartesianGrid * + DataSymmetriesForDensels_PET_CartesianGrid* #else - DataSymmetriesForDensels * + DataSymmetriesForDensels* #endif - clone() const override; + clone() const override; - bool - operator ==(const DataSymmetriesForDensels_PET_CartesianGrid&) const; + bool operator==(const DataSymmetriesForDensels_PET_CartesianGrid&) const; #if 0 TODO! @@ -73,33 +71,26 @@ class DataSymmetriesForDensels_PET_CartesianGrid : public DataSymmetriesForDense get_basic_densel_index_range() const; #endif - inline void - get_related_densels(std::vector&, const Densel& b) const override; + inline void get_related_densels(std::vector&, const Densel& b) const override; - inline int - num_related_densels(const Densel& b) const override; + inline int num_related_densels(const Densel& b) const override; - inline unique_ptr - find_symmetry_operation_from_basic_densel(Densel&) const override; + inline unique_ptr find_symmetry_operation_from_basic_densel(Densel&) const override; - inline bool - find_basic_densel(Densel& b) const override; - + inline bool find_basic_densel(Densel& b) const override; //! 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; @@ -122,11 +113,9 @@ class DataSymmetriesForDensels_PET_CartesianGrid : public DataSymmetriesForDense cartesian_grid_info_ptr() const; #endif - bool blindly_equals(const root_type * const) const override; - - inline SymmetryOperation* - find_sym_op_general_densel( const int z, const int y, const int x) const; - + bool blindly_equals(const root_type* const) const override; + + 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 2bf872b5f..1cd11fcdb 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,87 @@ 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(); + + 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); + return new SymmetryOperation_PET_CartesianGrid_z_shift(axial_pos_num_shift, z_shift); } - else if ( x>=0 && y>x) // [ 45, 90] + 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] + else if (x < 0 && y >= 0) // [ 135, 180] { - assert(y<=-x); + 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 && -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] + else if (x <= 0 && y < 0) // [ 225, 270] { - assert(-y>-x); + 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 > 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); + 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 +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]) - ); + unique_ptr sym_op(find_sym_op_general_densel(c[1], c[2], c[3])); #ifndef NDEBUG const Densel copy_original = c; #endif @@ -129,31 +119,28 @@ 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(std::vector& v, const Densel& d) const +DataSymmetriesForDensels_PET_CartesianGrid::get_related_densels(std::vector& v, const Densel& d) const { #ifndef NDEBUG { @@ -163,54 +150,53 @@ get_related_densels(std::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; 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, y, -x)); + } + if (y > 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 < num_planes; z += num_independent_planes) + v.push_back(Densel(z, -y, -x)); + } + 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 cc1cb84ee..acbb938f5 100644 --- a/src/include/stir_experimental/recon_buildblock/ParametricQuadraticPrior.h +++ b/src/include/stir_experimental/recon_buildblock/ParametricQuadraticPrior.h @@ -19,11 +19,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" @@ -43,26 +41,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 @@ -73,54 +71,46 @@ 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 - > +class ParametricQuadraticPrior : public RegisteredParsingObject, + GeneralisedPrior, + PriorWithParabolicSurrogate> { - private: - typedef - RegisteredParsingObject< ParametricQuadraticPrior, - GeneralisedPrior, - PriorWithParabolicSurrogate > - base_type; - shared_ptr kappa_ptr; - VectorWithOffset > _single_quadratic_priors; - - public: +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, @@ -128,47 +118,46 @@ 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); - + 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 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(TargetT const& current_image_estimate) const; @@ -176,11 +165,8 @@ class ParametricQuadraticPrior: public 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 f2b9c257b..dbeeaf9a0 100644 --- a/src/include/stir_experimental/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData.h +++ b/src/include/stir_experimental/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData.h @@ -27,11 +27,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 @@ -39,22 +39,23 @@ START_NAMESPACE_STIR */ template -class PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData: -public RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMean > +class PoissonLogLikelihoodWithLinearModelForMeanAndDynamicProjData + : public RegisteredParsingObject, + GeneralisedObjectiveFunction, + PoissonLogLikelihoodWithLinearModelForMean> { - private: - typedef RegisteredParsingObject, - GeneralisedObjectiveFunction, - PoissonLogLikelihoodWithLinearModelForMean > base_type; - typedef PoissonLogLikelihoodWithLinearModelForMeanAndProjData > SingleFrameObjFunc ; +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). @@ -92,7 +93,7 @@ public RegisteredParsingObject _additive_dyn_proj_data_sptr; /*! the normalisation or/and attenuation data */ @@ -146,14 +147,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. - */ - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; + */ + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; - - 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 override; - + const DataSymmetriesForViewSegmentNumbers* get_symmetries_used() const override; private: - shared_ptr original_forward_projector_ptr; VectorWithOffset tang_kernel; VectorWithOffset ax_kernel; @@ -77,19 +71,24 @@ 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) override; + const int min_axial_pos_num, + const int max_axial_pos_num, + const int min_tangential_pos_num, + const int max_tangential_pos_num) override; 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; - + 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 set_defaults() override; void initialise_keymap() override; diff --git a/src/include/stir_experimental/recon_buildblock/ProjMatrixByBinSinglePhoton.h b/src/include/stir_experimental/recon_buildblock/ProjMatrixByBinSinglePhoton.h index 78068f7d4..8ecb8c273 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 - > +class ProjMatrixByBinSinglePhoton : public RegisteredParsingObject { -public : - //! Name which will be used when parsing a ProjMatrixByBin object - static const char * const registered_name; +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. - */ - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; + */ + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; 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; + void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const override; - void - calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin&) const override; - - void set_defaults() override; - void initialise_keymap() override; - + void set_defaults() override; + void initialise_keymap() override; }; 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 c9bb08dd5..cae069b00 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,51 @@ #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 - > +class ProjMatrixByBinUsingSolidAngle + : public RegisteredParsingObject { -public : - //! Name which will be used when parsing a ProjMatrixByBin object - static const char * const registered_name; +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. - */ - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; + */ + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; 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; + void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const override; - void - calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin&) const override; - - void set_defaults() override; - void initialise_keymap() override; - + void set_defaults() override; + void initialise_keymap() override; }; 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 56a4f066f..9d9b50f39 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,40 @@ #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 - > +class ProjMatrixByBinWithPositronRange + : public RegisteredParsingObject { -public : - //! Name which will be used when parsing a ProjMatrixByBin object - static const char * const registered_name; +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. - */ - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; + */ + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; 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 +66,15 @@ public : int positron_range_zoom; int positron_num_samples; - shared_ptr proj_data_info_ptr; + void calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin&) const override; - void - calculate_proj_matrix_elems_for_one_bin( - ProjMatrixElemsForOneBin&) const override; - - void set_defaults() override; - void initialise_keymap() override; - bool post_processing() override; - + void set_defaults() override; + void initialise_keymap() override; + bool post_processing() override; }; 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 76b59fba0..49706caca 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" @@ -29,55 +27,51 @@ #include "stir/shared_ptr.h" 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: - ~ProjMatrixByDensel() override {} //! 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&) const; - + inline void get_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&, const Densel&) const; + #if 0 // TODO /*! \brief Facility to write the 'independent' part of the matrix to file. @@ -87,81 +81,65 @@ 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&) - const; + inline void cache_proj_matrix_elems_for_one_densel(const ProjMatrixElemsForOneDensel&) const; private: - typedef unsigned int CacheKey; - typedef std::map MapProjMatrixElemsForOneDensel; + typedef std::map MapProjMatrixElemsForOneDensel; typedef MapProjMatrixElemsForOneDensel::iterator MapProjMatrixElemsForOneDenselIterator; typedef MapProjMatrixElemsForOneDensel::const_iterator const_MapProjMatrixElemsForOneDenselIterator; - - //! collection of ProjMatrixElemsForOneDensel (internal cache ) - mutable - MapProjMatrixElemsForOneDensel cache_collection; - + + //! collection of ProjMatrixElemsForOneDensel (internal cache ) + mutable 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" #endif // __ProjMatrixByDensel_H__ - - - diff --git a/src/include/stir_experimental/recon_buildblock/ProjMatrixByDensel.inl b/src/include/stir_experimental/recon_buildblock/ProjMatrixByDensel.inl index 00e0dd922..7824c340b 100644 --- a/src/include/stir_experimental/recon_buildblock/ProjMatrixByDensel.inl +++ b/src/include/stir_experimental/recon_buildblock/ProjMatrixByDensel.inl @@ -20,79 +20,66 @@ START_NAMESPACE_STIR -void ProjMatrixByDensel:: -get_proj_matrix_elems_for_one_densel( - ProjMatrixElemsForOneDensel& probabilities, - const Densel& densel) const -{ +void +ProjMatrixByDensel::get_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel& probabilities, const Densel& densel) 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) - - { - // call 'calculate' just for the basic densel - calculate_proj_matrix_elems_for_one_densel(probabilities); + // 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(); + 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) 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) 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 3725b43cd..43682244e 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,16 +21,15 @@ #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 \c NEWSCALE is \c \#defined during compilation time of ProjMatrixByDenselOnCartesianGridUsingElement.cxx. @@ -38,37 +37,34 @@ template class DiscretisedDensity; 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 +class ProjMatrixByDenselOnCartesianGridUsingElement : public ProjMatrixByDensel { -public : - +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. */ - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; //! this member computes a single element of the projection matrix /*! \param bin The bin-coordinates specifying the row of the projection matrix @@ -78,39 +74,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 override; - - + void calculate_proj_matrix_elems_for_one_densel(ProjMatrixElemsForOneDensel&) const override; }; 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 3149ad04c..6805d38ff 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,17 +20,16 @@ #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 \c NEWSCALE is \c \#defined during compilation time of ProjMatrixByDenselUsingRayTracing.cxx. @@ -38,46 +37,42 @@ class DataSymmetriesForDensels_PET_CartesianGrid; 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. - */ - void set_up( - const shared_ptr& proj_data_info_ptr, - const shared_ptr >& density_info_ptr // TODO should be Info only - ) override; + */ + void set_up(const shared_ptr& proj_data_info_ptr, + const shared_ptr>& density_info_ptr // TODO should be Info only + ) override; - const DataSymmetriesForDensels* get_symmetries_ptr() const override; + const DataSymmetriesForDensels* get_symmetries_ptr() const override; - float - get_element(const Bin&, const CartesianCoordinate3D&) const override; + float get_element(const Bin&, const CartesianCoordinate3D&) const override; private: shared_ptr symmetries_ptr; @@ -88,12 +83,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 +96,11 @@ public : float yhalfsize; float zhalfsize; - - - void set_defaults() override; - void initialise_keymap() override; - bool post_processing() override; - + void set_defaults() override; + void initialise_keymap() override; + bool post_processing() override; }; END_NAMESPACE_STIR #endif - - - diff --git a/src/iterative/KOSMAPOSL/KOSMAPOSL.cxx b/src/iterative/KOSMAPOSL/KOSMAPOSL.cxx index 757365bf6..24c8868ed 100644 --- a/src/iterative/KOSMAPOSL/KOSMAPOSL.cxx +++ b/src/iterative/KOSMAPOSL/KOSMAPOSL.cxx @@ -36,9 +36,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 { @@ -47,23 +49,20 @@ 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 adc5ccc09..ba04ca0cb 100644 --- a/src/iterative/KOSMAPOSL/KOSMAPOSLReconstruction.cxx +++ b/src/iterative/KOSMAPOSL/KOSMAPOSLReconstruction.cxx @@ -23,7 +23,7 @@ \author Ashley Gillman \author Palak Wadhwa \author Kris Thielemans - + */ #include "stir/KOSMAPOSL/KOSMAPOSLReconstruction.h" @@ -55,7 +55,7 @@ #include #ifdef STIR_OPENMP -#include +# include #endif #include "stir/num_threads.h" @@ -73,141 +73,137 @@ using std::endl; START_NAMESPACE_STIR - // worker functions +namespace +{ // priave namespace for internal 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 -precalculate_patch_euclidean_distances(Array<3, float>& distance, int num_neighbours, bool only_2D, - const CartesianCoordinate3D& grid_spacing) { +precalculate_patch_euclidean_distances(Array<3, float>& distance, + int num_neighbours, + bool only_2D, + const CartesianCoordinate3D& grid_spacing) +{ int min_dx, max_dx, min_dy, max_dy, min_dz, max_dz; - if (only_2D) { - min_dz = max_dz = 0; - } - 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; - - 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) { - distance[z][y][x] = - sqrt(square(x * grid_spacing.x()) - + square(y * grid_spacing.y()) - + square(z * grid_spacing.z()))/grid_spacing.x(); - } + if (only_2D) + { + min_dz = max_dz = 0; } - } -}} + 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; + + 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) + { + distance[z][y][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->freeze_iterative_kernel_at_subiter_num=-1; + this->kernelised_output_filename_prefix = ""; + this->hybrid = 0; + this->freeze_iterative_kernel_at_subiter_num = -1; } 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("freeze iterative kernel at subiteration number",&this->freeze_iterative_kernel_at_subiter_num); + this->parser.add_key("kernelised output filename prefix", &this->kernelised_output_filename_prefix); + this->parser.add_key("freeze iterative kernel at subiteration number", &this->freeze_iterative_kernel_at_subiter_num); } - template -void KOSMAPOSLReconstruction:: -ask_parameters() +void +KOSMAPOSLReconstruction::ask_parameters() { - OSMAPOSLReconstruction::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()){ + + 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++) + } + 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); + 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])) { @@ -220,119 +216,116 @@ post_processing() //*********** 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) +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"); - - if(this->freeze_iterative_kernel_at_subiter_num==0) - error("The kernel cannot be frozen at subiteration 0 as subiteration number starts from 1."); - - 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); - } - } + 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"); + + if (this->freeze_iterative_kernel_at_subiter_num == 0) + error("The kernel cannot be frozen at subiteration 0 as subiteration number starts from 1."); + + 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; } template -bool -KOSMAPOSLReconstruction:: -still_updating_iterative_kernel() { - return this->freeze_iterative_kernel_at_subiter_num<0 || - this->subiteration_numfreeze_iterative_kernel_at_subiter_num; +bool +KOSMAPOSLReconstruction::still_updating_iterative_kernel() +{ + return this->freeze_iterative_kernel_at_subiter_num < 0 + || this->subiteration_num < this->freeze_iterative_kernel_at_subiter_num; } /*************************************************************** @@ -341,122 +334,127 @@ still_updating_iterative_kernel() { 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; +} template const int -KOSMAPOSLReconstruction:: -get_freeze_iterative_kernel_at_subiter_num() const -{ return this->freeze_iterative_kernel_at_subiter_num; } - +KOSMAPOSLReconstruction::get_freeze_iterative_kernel_at_subiter_num() const +{ + return this->freeze_iterative_kernel_at_subiter_num; +} /*************************************************************** 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; @@ -464,8 +462,7 @@ set_num_neighbours(const int 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; @@ -473,39 +470,35 @@ set_num_non_zero_feat(const int arg) template void -KOSMAPOSLReconstruction:: -set_sigma_m(const double arg, const int index) +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); + 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) +KOSMAPOSLReconstruction::set_sigma_m(const double arg) { - this->_already_set_up = false; - this->sigma_m.resize(1); - this->sigma_m[0] = 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) +KOSMAPOSLReconstruction::set_sigma_p(const double arg) { - this->_already_set_up = false; - this->sigma_p = 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; @@ -513,8 +506,7 @@ set_sigma_dp(const double 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; @@ -522,8 +514,7 @@ set_sigma_dm(const double 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; @@ -531,8 +522,7 @@ set_only_2D(const bool arg) template void -KOSMAPOSLReconstruction:: -set_hybrid(const bool arg) +KOSMAPOSLReconstruction::set_hybrid(const bool arg) { this->_already_set_up = false; this->hybrid = arg; @@ -540,8 +530,7 @@ set_hybrid(const bool arg) template void -KOSMAPOSLReconstruction:: -set_freeze_iterative_kernel_at_subiter_num(const int arg) +KOSMAPOSLReconstruction::set_freeze_iterative_kernel_at_subiter_num(const int arg) { this->freeze_iterative_kernel_at_subiter_num = arg; } @@ -550,20 +539,20 @@ set_freeze_iterative_kernel_at_subiter_num(const int 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) +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; + // 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)); + 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]; @@ -573,614 +562,579 @@ 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++) + // 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 y = min_y; y <= max_y; y++) { - for (int x=min_x;x<= max_x;x++) + 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); + 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); + 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) + // 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 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 (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]) ; - } + 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 + // 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; + 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; + } - 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; } - o=q+j+k*this->dimx+n*dimx*dimy+1; - } - - else{ - o=q+j+k*this->dimx+n*dimx*dimy; - } + 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; + 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]); } - 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) +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])); + 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) +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++){ + 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; + 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]; + 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!"); + 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 += (*anatomical_prior_sptrs[i])[z][y][x]; + nv += 1; } } - kmean=kmean / nv; + } + 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) +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])) + 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; + bool use_compact_implementation = this->num_non_zero_feat == 1; - // Something very weird happens here if I do not get_empty_copy() - // KImage elements will be all nan + // 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()); + unique_ptr kImage_uptr(current_alpha_estimate.get_empty_copy()); - if (!use_compact_implementation && this->get_hybrid()) { + 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; - - if(still_updating_iterative_kernel()) - calculate_norm_matrix(*this->kpnorm_sptr, dimf_row, dimf_col, - current_alpha_estimate); - } + int dimf_col = this->num_non_zero_feat - 1; + if (still_updating_iterative_kernel()) + calculate_norm_matrix(*this->kpnorm_sptr, dimf_row, dimf_col, current_alpha_estimate); + } - // calculate kernelised image - int min_z, max_z, min_y, max_y, min_x, max_x; - - 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); + 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 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; + } } + } - 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; - - } - + if (current_alpha_estimate[z][y][x] == 0) + { + continue; + } - kernelised_image_out[z][y][x] /= kernel_sum; - } - } - } + 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) { - - 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; +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; } 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; + = 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) { - - 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]); +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]); 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 - + shared_ptr iterative_kernel_image_sptr; - + // 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); - -// the following condition sets the "iterative_kernel_image_frozen_sptr" member to the image ptr -// we have at the iteration select by "freeze_iterative_kernel_at_subiter_num" - if (this->freeze_iterative_kernel_at_subiter_num>0 && - this->subiteration_num==this->freeze_iterative_kernel_at_subiter_num) - - this->iterative_kernel_image_frozen_sptr=shared_ptr(current_alpha_coefficent_image.clone()); - -// the following condition decides whether the "iterative_kernel_image" to use for the kernel calculation -// should be equal to the current update (if we did not set freeze_iterative_kernel_at_subiter_num or if the current subiteration -// is smaller than the one chosen trhough freeze_iterative_kernel_at_subiter_num) or the frozen image + + // the following condition sets the "iterative_kernel_image_frozen_sptr" member to the image ptr + // we have at the iteration select by "freeze_iterative_kernel_at_subiter_num" + if (this->freeze_iterative_kernel_at_subiter_num > 0 && this->subiteration_num == this->freeze_iterative_kernel_at_subiter_num) + + this->iterative_kernel_image_frozen_sptr = shared_ptr(current_alpha_coefficent_image.clone()); + + // the following condition decides whether the "iterative_kernel_image" to use for the kernel calculation + // should be equal to the current update (if we did not set freeze_iterative_kernel_at_subiter_num or if the current + // subiteration + // is smaller than the one chosen trhough freeze_iterative_kernel_at_subiter_num) or the frozen image if (still_updating_iterative_kernel()) - iterative_kernel_image_sptr=shared_ptr(current_alpha_coefficent_image.clone()); + iterative_kernel_image_sptr = shared_ptr(current_alpha_coefficent_image.clone()); else - iterative_kernel_image_sptr=this->iterative_kernel_image_frozen_sptr; - - unique_ptr< TargetT > current_update_image_ptr(current_alpha_coefficent_image.get_empty_copy()); + iterative_kernel_image_sptr = this->iterative_kernel_image_frozen_sptr; + + unique_ptr current_update_image_ptr(current_alpha_coefficent_image.get_empty_copy()); compute_kernelised_image(*current_update_image_ptr, current_alpha_coefficent_image, *iterative_kernel_image_sptr); + 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, *iterative_kernel_image_sptr); -unique_ptr< TargetT > ksens_ptr(sensitivity.get_empty_copy()); + // divide by subset sensitivity + compute_kernelised_image(*ksens_ptr, sensitivity, *iterative_kernel_image_sptr); - //apply kernel to the multiplicative update - compute_kernelised_image (*kmultiplicative_update_ptr, *multiplicative_update_image_ptr, *iterative_kernel_image_sptr); + int count = 0; - // divide by subset sensitivity - compute_kernelised_image (*ksens_ptr, sensitivity, *iterative_kernel_image_sptr); + // 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); - + divide(kmultiplicative_update_ptr->begin_all(), kmultiplicative_update_ptr->end_all(), (*ksens_ptr).begin_all(), small_num); } - else + 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); - + 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" ) + if (this->MAP_model == "additive") { - // multiplicative form - // lambda_new = lambda / (p_v*(1 + beta*prior_gradient)) * + // 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 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/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; + } + } } - } 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); - } - + + 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) - { - // 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]; - 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); - delete[] fname; - } - + { + // 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]; + 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); + 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; + 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) - { + 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; + ++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,*iterative_kernel_image_sptr); - - //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); - } + compute_kernelised_image(*kcurrent_ptr, current_alpha_coefficent_image, *iterative_kernel_image_sptr); + + // 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); + } } - + #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 904bb4c03..108a88475 100644 --- a/src/iterative/OSMAPOSL/OSMAPOSL.cxx +++ b/src/iterative/OSMAPOSL/OSMAPOSL.cxx @@ -31,9 +31,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 { @@ -42,23 +44,20 @@ 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 6ef87b80f..f60f587bc 100644 --- a/src/iterative/OSMAPOSL/OSMAPOSLReconstruction.cxx +++ b/src/iterative/OSMAPOSL/OSMAPOSLReconstruction.cxx @@ -60,38 +60,28 @@ using std::max; using std::cerr; using std::endl; - START_NAMESPACE_STIR template -const char * const -OSMAPOSLReconstruction ::registered_name = - "OSMAPOSL"; +const char* const OSMAPOSLReconstruction::registered_name = "OSMAPOSL"; template -PoissonLogLikelihoodWithLinearModelForMean& -OSMAPOSLReconstruction:: -objective_function() +PoissonLogLikelihoodWithLinearModelForMean& +OSMAPOSLReconstruction::objective_function() { - return - static_cast&> - (*this->objective_function_sptr); + return static_cast&>(*this->objective_function_sptr); } template -PoissonLogLikelihoodWithLinearModelForMean const& -OSMAPOSLReconstruction:: -objective_function() const +PoissonLogLikelihoodWithLinearModelForMean const& +OSMAPOSLReconstruction::objective_function() const { - return - static_cast&> - (*this->objective_function_sptr); + 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(); @@ -100,9 +90,8 @@ get_objective_function() const //*********** parameters *********** template -void -OSMAPOSLReconstruction:: -set_defaults() +void +OSMAPOSLReconstruction::set_defaults() { base_type::set_defaults(); enforce_initial_positivity = true; @@ -111,268 +100,233 @@ 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); - - const std::string inter_update_filter_type = ask_string(""); - - inter_update_filter_ptr.reset(DataProcessor::read_registered_object(0, inter_update_filter_type)); - - } + 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)); + } 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()) - { - // 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); - } + { + // 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); + } return false; } //*********** set_ functions *********** template void -OSMAPOSLReconstruction:: -set_inter_update_filter_interval(const int arg) +OSMAPOSLReconstruction::set_inter_update_filter_interval(const int arg) { - this->inter_update_filter_interval = arg; + this->inter_update_filter_interval = arg; } template void -OSMAPOSLReconstruction:: -set_inter_update_filter_ptr(const shared_ptr > & arg) +OSMAPOSLReconstruction::set_inter_update_filter_ptr(const shared_ptr>& arg) { - this->inter_update_filter_ptr = arg; + this->inter_update_filter_ptr = arg; } template void -OSMAPOSLReconstruction:: -set_maximum_relative_change(const double arg) +OSMAPOSLReconstruction::set_maximum_relative_change(const double arg) { - this->maximum_relative_change = arg; + this->maximum_relative_change = arg; } template void -OSMAPOSLReconstruction:: -set_minimum_relative_change(const double arg) +OSMAPOSLReconstruction::set_minimum_relative_change(const double arg) { - this->minimum_relative_change = arg; + this->minimum_relative_change = arg; } -template -void -OSMAPOSLReconstruction:: -set_enforce_initial_positivity(const bool arg) +template +void +OSMAPOSLReconstruction::set_enforce_initial_positivity(const bool arg) { this->enforce_initial_positivity = arg; } - + template void -OSMAPOSLReconstruction:: -set_write_update_image(const int arg) +OSMAPOSLReconstruction::set_write_update_image(const int arg) { - this->write_update_image = arg; + this->write_update_image = arg; } template void -OSMAPOSLReconstruction:: -set_MAP_model(const std::string& arg) +OSMAPOSLReconstruction::set_MAP_model(const std::string& arg) { - this->MAP_model = 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? std::ostringstream s; - 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) +Succeeded +OSMAPOSLReconstruction::set_up(shared_ptr const& target_image_ptr) { - // 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; 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()); + 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) + { + 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)) + 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 + 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, + // Note however that at present, info("Building inter-update filter kernel"); - if (this->inter_update_filter_ptr->set_up(*target_image_ptr) - == Succeeded::no) + 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)) + 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); + shared_ptr> thresholding_sptr( + new ThresholdMinToSmallPositiveValueDataProcessor); this->inter_iteration_filter_ptr.reset( - new ChainedDataProcessor( - this->inter_iteration_filter_ptr, - thresholding_sptr - )); + 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) + 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 @@ -381,18 +335,15 @@ 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) +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); + 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) @@ -400,47 +351,41 @@ 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(); + 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; - } + { + *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( @@ -451,125 +396,113 @@ update_estimate(TargetT ¤t_image_estimate) 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(), - 0.F); // no need to find a threshold for division by sensitivity - } + + // 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(), + 0.F); // no need to find a threshold for division by sensitivity + } 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); - - 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" ) { - // 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) + 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") { - *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; + // 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 between .1 and 10 - while (denominator_iter != denominator_end) + else { - *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; + 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; + } + } } - } + + // do the division + // TODO: The thresholding implied in "divide" potentially fails with parametric images + // as the different parametric images can have very different scales. + // See https://github.com/UCL/STIR/issues/906 + divide(multiplicative_update_image_ptr->begin_all(), + multiplicative_update_image_ptr->end_all(), + denominator_ptr->begin_all(), + small_num); } - // do the division - // TODO: The thresholding implied in "divide" potentially fails with parametric images - // as the different parametric images can have very different scales. - // See https://github.com/UCL/STIR/issues/906 - 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)) - { - info("Applying inter-update filter"); - this->inter_update_filter_ptr->apply(current_image_estimate); - } - + + 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); + } + // KT 17/08/2000 limit update // TODO move below thresholding? 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]; - 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); - delete[] fname; - } - + { + // 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]; + 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); + 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); + 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; + // current_image_estimate *= *multiplicative_update_image_ptr; apply_multiplicative_update(current_image_estimate, *multiplicative_update_image_ptr); #ifdef PARALLEL @@ -578,7 +511,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 a47032469..defe7addd 100644 --- a/src/iterative/OSSPS/OSSPS.cxx +++ b/src/iterative/OSSPS/OSSPS.cxx @@ -15,7 +15,7 @@ \author Sanida Mustafovic \author Kris Thielemans - + */ #include "stir/OSSPS/OSSPSReconstruction.h" #include "stir/DiscretisedDensity.h" @@ -25,18 +25,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 5005acb4b..be9d0ffb1 100644 --- a/src/iterative/OSSPS/OSSPSReconstruction.cxx +++ b/src/iterative/OSSPS/OSSPSReconstruction.cxx @@ -10,13 +10,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" @@ -48,20 +48,16 @@ using std::endl; using boost::lambda::_1; using boost::lambda::_2; - 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; @@ -69,29 +65,27 @@ set_defaults() 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); @@ -101,56 +95,46 @@ 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; @@ -160,47 +144,44 @@ 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? - + std::ostringstream s; - + // 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(); @@ -208,22 +189,17 @@ 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); // Assume that the objective function is convex and add_multiplication_with_approximate_Hessian_without_penalty // will compute the precomputed_denominator_ptr to be non-positive. - 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); // In fact, for for OSSPS, we want a non-negative precomputed denominator, so flip the signs on the voxels - std::for_each(precomputed_denominator_ptr->begin_all(), precomputed_denominator_ptr->end_all(), - [](float& a) { return a=-a; } ); + std::for_each( + precomputed_denominator_ptr->begin_all(), precomputed_denominator_ptr->end_all(), [](float& a) { return a = -a; }); timer.stop(); info(boost::format("Precomputing denominator took %1% s CPU time") % timer.value()); @@ -236,249 +212,215 @@ precompute_denominator_of_conditioner_without_penalty() // 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) + if (this->relaxation_parameter <= 0) { - warning("OSSPS: relaxation parameter should be positive but is %g", - this->relaxation_parameter); + warning("OSSPS: relaxation parameter should be positive but is %g", this->relaxation_parameter); return Succeeded::no; } - if (this->relaxation_gamma<0) + if (this->relaxation_gamma < 0) { - warning("OSSPS: relaxation_gamma parameter should be non-negative but is %g", - this->relaxation_gamma); + 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) - { - warning("OSSPS: Prior must be of a type derived from PriorWithParabolicSurrogate\n"); - return Succeeded::no; - } + 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=="") - { - precomputed_denominator_ptr.reset(target_image_ptr->get_empty_copy()); - precompute_denominator_of_conditioner_without_penalty(); - } - 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); - } + 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") + { + 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); { - 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; - } + 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; + } + } } - } 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); + 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(); + 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(); #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())) + 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()); - + 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); - } + { + 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 ; - + *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())); + // 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); + { + // 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); } else { - // we have computed the denominator already + // 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); - + 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)); - + // 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); + 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())); - } - 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 bdb525a06..b6d6d7911 100644 --- a/src/iterative/POSMAPOSL/POSMAPOSL.cxx +++ b/src/iterative/POSMAPOSL/POSMAPOSL.cxx @@ -18,22 +18,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 373a4afb8..098b0938f 100644 --- a/src/iterative/POSSPS/POSSPS.cxx +++ b/src/iterative/POSSPS/POSSPS.cxx @@ -21,17 +21,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 bd508aa54..af05f3927 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 @@ -17,7 +17,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/listmode/CListRecord.h" #include "stir/ProjDataInfo.h" #include "stir/Bin.h" @@ -26,11 +25,10 @@ START_NAMESPACE_STIR -Succeeded -CListEvent:: -set_prompt(const bool) +Succeeded +CListEvent::set_prompt(const bool) { - return Succeeded::no; + return Succeeded::no; } END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/CListModeDataECAT.cxx b/src/listmode_buildblock/CListModeDataECAT.cxx index 799357367..299d51eef 100644 --- a/src/listmode_buildblock/CListModeDataECAT.cxx +++ b/src/listmode_buildblock/CListModeDataECAT.cxx @@ -9,13 +9,12 @@ */ /*! \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" @@ -24,9 +23,9 @@ #include "stir/error.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" using std::cerr; @@ -41,20 +40,19 @@ 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"; @@ -62,86 +60,95 @@ CListModeDataECAT(const std::string& listmode_filename_prefix) 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)); + 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 + // 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); + 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); + exam_info_sptr->start_time_in_secs_since_1970 = double(singles_main_header.scan_start_time); - switch(singles_main_header.patient_orientation) + switch (singles_main_header.patient_orientation) { case FeetFirstProne: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFP); break; + exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFP); + break; case HeadFirstProne: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFP); break; + exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFP); + break; case FeetFirstSupine: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFS); break; + exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFS); + break; case HeadFirstSupine: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFS); break; + exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFS); + break; case FeetFirstRight: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFDR); break; + exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFDR); + break; case HeadFirstRight: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFDR); break; + exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFDR); + break; case FeetFirstLeft: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFDL); break; + exam_info_sptr->patient_position = PatientPosition(PatientPosition::FFDL); + break; case HeadFirstLeft: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFDL); break; + exam_info_sptr->patient_position = PatientPosition(PatientPosition::HFDL); + break; case UnknownOrientation: default: - exam_info_sptr->patient_position = PatientPosition(PatientPosition::unknown_position); break; + 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 ((this->get_proj_data_info_sptr()->get_scanner_ptr()->get_type() == Scanner::E966 && typeid(CListRecordT) != typeid(CListRecordECAT966)) || - (this->get_proj_data_info_sptr()->get_scanner_ptr()->get_type() == Scanner::E962 && typeid(CListRecordT) != typeid(CListRecordECAT962))) + 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 ((this->get_proj_data_info_sptr()->get_scanner_ptr()->get_type() == Scanner::E966 + && typeid(CListRecordT) != typeid(CListRecordECAT966)) + || (this->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(), this->get_proj_data_info_sptr()->get_scanner_ptr()->get_name().c_str()); + error("Data in %s is from a %s scanner, but reading with wrong type of CListModeData", + listmode_filename_prefix.c_str(), + this->get_proj_data_info_sptr()->get_scanner_ptr()->get_name().c_str()); } - else if (this->get_proj_data_info_sptr()->get_scanner_ptr()->get_type() != Scanner::E966 && this->get_proj_data_info_sptr()->get_scanner_ptr()->get_type() != Scanner::E962) + else if (this->get_proj_data_info_sptr()->get_scanner_ptr()->get_type() != Scanner::E966 + && this->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; @@ -149,24 +156,22 @@ get_empty_record_sptr() const 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); + 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); + { + 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(); - } + 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; @@ -176,22 +181,20 @@ open_lm_file(unsigned int new_lm_file) const 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; - } + { + 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())); + 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 - set_saved_get_positions(saved_get_positions_for_each_lm_data[current_lm_file-1]); + 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; } @@ -199,40 +202,36 @@ open_lm_file(unsigned int new_lm_file) const 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 - { - // 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) - return current_lm_data_ptr->get_next_record(record); - else - return Succeeded::no; - } + { + // 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) + 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) + assert(current_lm_file > 0); + if (current_lm_file != 1) { return open_lm_file(1); } @@ -242,30 +241,26 @@ 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 @@ -326,7 +321,6 @@ get_num_records() const #endif - // instantiations template class CListModeDataECAT; template class CListModeDataECAT; diff --git a/src/listmode_buildblock/CListModeDataECAT8_32bit.cxx b/src/listmode_buildblock/CListModeDataECAT8_32bit.cxx index c44212379..a52bc6ff8 100644 --- a/src/listmode_buildblock/CListModeDataECAT8_32bit.cxx +++ b/src/listmode_buildblock/CListModeDataECAT8_32bit.cxx @@ -9,13 +9,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" @@ -24,108 +23,90 @@ #include "stir/error.h" #include - START_NAMESPACE_STIR -namespace ecat { +namespace ecat +{ -CListModeDataECAT8_32bit:: -CListModeDataECAT8_32bit(const std::string& listmode_filename) - : listmode_filename(listmode_filename) +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->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() +CListModeDataECAT8_32bit::open_lm_file() { - //const std::string filename = interfile_parser.data_file_name; - std::string filename = interfile_parser.data_file_name; + // 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); + 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); + 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())); + 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) +CListModeDataECAT8_32bit::set_get_position(const CListModeDataECAT8_32bit::SavedPosition& pos) { - return - current_lm_data_ptr->set_get_position(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 3ce84eccb..3cbb502aa 100644 --- a/src/listmode_buildblock/CListModeDataGEHDF5.cxx +++ b/src/listmode_buildblock/CListModeDataGEHDF5.cxx @@ -16,7 +16,6 @@ \author Palak Wadhwa */ - #include "stir/listmode/CListModeDataGEHDF5.h" #include "stir/Succeeded.h" #include "stir/ExamInfo.h" @@ -32,115 +31,95 @@ START_NAMESPACE_STIR -namespace GE { -namespace RDF_HDF5 { +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(), - 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) +CListModeDataGEHDF5::set_get_position(const CListModeDataGEHDF5::SavedPosition& pos) { - return - current_lm_data_ptr->set_get_position(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/CListModeDataPENN.cxx b/src/listmode_buildblock/CListModeDataPENN.cxx index 6e394d248..24fcc773c 100644 --- a/src/listmode_buildblock/CListModeDataPENN.cxx +++ b/src/listmode_buildblock/CListModeDataPENN.cxx @@ -14,7 +14,6 @@ \author Nikos Efthimiou */ - #include "stir/listmode/CListModeDataPENN.h" #include "stir/listmode/CListRecordPENN.h" #include "stir/FilePath.h" @@ -22,112 +21,100 @@ START_NAMESPACE_STIR -CListModeDataPENN:: -CListModeDataPENN(const std::string& listmode_filename) +CListModeDataPENN::CListModeDataPENN(const std::string& listmode_filename) : listmode_filename(listmode_filename) { - KeyParser parser; + KeyParser parser; - std::string originating_system; + std::string originating_system; - parser.add_start_key("PENN header"); - parser.add_stop_key("End PENN header"); - parser.add_key("originating system", &originating_system); - parser.add_parsing_key("FileType", &this->lm_data_sptr); + parser.add_start_key("PENN header"); + parser.add_stop_key("End PENN header"); + parser.add_key("originating system", &originating_system); + parser.add_parsing_key("FileType", &this->lm_data_sptr); - if(!parser.parse(listmode_filename.c_str())) - error("listmode_filename: error parsing '%s'", listmode_filename.c_str()); + if (!parser.parse(listmode_filename.c_str())) + error("listmode_filename: error parsing '%s'", listmode_filename.c_str()); - FilePath f(listmode_filename); + FilePath f(listmode_filename); - if (lm_data_sptr->set_up() == Succeeded::no) - error("CListModeDataPENN: Unable to set_up() from the input Header file (.hpenn)."); + if (lm_data_sptr->set_up() == Succeeded::no) + error("CListModeDataPENN: Unable to set_up() from the input Header file (.hpenn)."); - shared_ptr _exam_info_sptr(new ExamInfo); + shared_ptr _exam_info_sptr(new ExamInfo); - // Only PET scanners supported - _exam_info_sptr->imaging_modality = ImagingModality::PT; - _exam_info_sptr->originating_system = originating_system; - this->exam_info_sptr = _exam_info_sptr; + // Only PET scanners supported + _exam_info_sptr->imaging_modality = ImagingModality::PT; + _exam_info_sptr->originating_system = originating_system; + this->exam_info_sptr = _exam_info_sptr; - shared_ptr this_scanner_sptr(Scanner::get_scanner_from_name(originating_system)); - if (this_scanner_sptr->get_type() == Scanner::Unknown_scanner) - error(boost::format("CListModeDataPENN: Unknown value for originating_system keyword: '%s") % 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("CListModeDataPENN: Unknown value for originating_system keyword: '%s") % originating_system); - proj_data_info_sptr = 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 - #ifdef STIR_TOF - ,1 - #endif - ); + proj_data_info_sptr = 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 +#ifdef STIR_TOF + , + 1 +#endif + ); } std::string -CListModeDataPENN:: -get_name() const +CListModeDataPENN::get_name() const { - return listmode_filename; + return listmode_filename; } - -shared_ptr -CListModeDataPENN:: -get_empty_record_sptr() const +shared_ptr +CListModeDataPENN::get_empty_record_sptr() const { - shared_ptr sptr(new CListRecordT(this->get_proj_data_info_sptr()->get_scanner_sptr())); - return sptr; + shared_ptr sptr(new CListRecordT(this->get_proj_data_info_sptr()->get_scanner_sptr())); + return sptr; } Succeeded -CListModeDataPENN:: -get_next_record(CListRecord& record_of_general_type) const +CListModeDataPENN::get_next_record(CListRecord& record_of_general_type) const { - CListRecordT& record = static_cast(record_of_general_type); - return lm_data_sptr->get_next_record(record); + CListRecordT& record = static_cast(record_of_general_type); + return lm_data_sptr->get_next_record(record); } - Succeeded -CListModeDataPENN:: -reset() -{ - return lm_data_sptr->reset(); +CListModeDataPENN::reset() +{ + return lm_data_sptr->reset(); } - CListModeData::SavedPosition -CListModeDataPENN:: -save_get_position() +CListModeDataPENN::save_get_position() { - return static_cast(lm_data_sptr->save_get_position()); -} - + return static_cast(lm_data_sptr->save_get_position()); +} Succeeded -CListModeDataPENN:: -set_get_position(const CListModeDataPENN::SavedPosition& pos) +CListModeDataPENN::set_get_position(const CListModeDataPENN::SavedPosition& pos) { - return - lm_data_sptr->set_get_position(pos); + return lm_data_sptr->set_get_position(pos); } void CListModeDataPENN::set_event(const bool& is_delay, const short int& _dt, - const unsigned short int& _xa, const unsigned short int& _xb, - const unsigned short int& _za, const unsigned short int& _zb, - const unsigned short int& _ea, const unsigned short int& _eb) + const unsigned short int& _xa, + const unsigned short int& _xb, + const unsigned short int& _za, + const unsigned short int& _zb, + const unsigned short int& _ea, + const unsigned short int& _eb) { - lm_data_sptr->set_new_record(is_delay, _dt, - _xa, _xb, - _za, _zb, - _ea, _eb); + lm_data_sptr->set_new_record(is_delay, _dt, _xa, _xb, _za, _zb, _ea, _eb); } - END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/CListModeDataROOT.cxx b/src/listmode_buildblock/CListModeDataROOT.cxx index fa2279f26..11645f407 100644 --- a/src/listmode_buildblock/CListModeDataROOT.cxx +++ b/src/listmode_buildblock/CListModeDataROOT.cxx @@ -35,370 +35,350 @@ constexpr static char max_num_timing_bins_keyword[] = "Maximum number of (unmash constexpr static char size_timing_bin_keyword[] = "Size of unmashed TOF time bins (ps)"; constexpr static char timing_resolution_keyword[] = "TOF timing resolution (ps)"; -CListModeDataROOT:: -CListModeDataROOT(const std::string& hroot_filename) +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(max_num_timing_bins_keyword, - &max_num_timing_bins); + 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(max_num_timing_bins_keyword, &max_num_timing_bins); #if STIR_VERSION < 070000 - this->parser.add_alias_key(max_num_timing_bins_keyword, "Number of TOF time bins"); + this->parser.add_alias_key(max_num_timing_bins_keyword, "Number of TOF time bins"); #endif - this->parser.add_key(size_timing_bin_keyword, - &size_timing_bin); + this->parser.add_key(size_timing_bin_keyword, &size_timing_bin); #if STIR_VERSION < 070000 - this->parser.add_alias_key(size_timing_bin_keyword, "Size of timing bin (ps)"); + this->parser.add_alias_key(size_timing_bin_keyword, "Size of timing bin (ps)"); #endif - this->parser.add_key(timing_resolution_keyword, &this->timing_resolution); + this->parser.add_key(timing_resolution_keyword, &this->timing_resolution); #if STIR_VERSION < 070000 - this->parser.add_alias_key(timing_resolution_keyword, "timing resolution (ps)"); + this->parser.add_alias_key(timing_resolution_keyword, "timing resolution (ps)"); #endif - this->parser.add_key("TOF mashing factor", &this->tof_mash_factor); + this->parser.add_key("TOF mashing factor", &this->tof_mash_factor); #if STIR_VERSION < 070000 - this->parser.add_alias_key("TOF mashing factor", "%TOF mashing factor"); + this->parser.add_alias_key("TOF mashing factor", "%TOF mashing factor"); #endif - // + // - // 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()); + // 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)."); + 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); + // 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()); + // 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; + this->exam_info_sptr = _exam_info_sptr; - shared_ptr this_scanner_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") // + // 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) + 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; + 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."); + 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) + // 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."); + 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) + if (check_scanner_definition(error_str) == Succeeded::no) { - error(error_str.c_str()); + error(error_str.c_str()); } - if (default_num_arccorrected_bins == -1) + if (default_num_arccorrected_bins == -1) { - default_num_arccorrected_bins = max_num_non_arccorrected_bins; + 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, - 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)); + 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) + // 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()); + 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()); + 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 +CListModeDataROOT::get_name() const { - return hroot_filename; + return hroot_filename; } -shared_ptr -CListModeDataROOT:: -get_empty_record_sptr() const +shared_ptr +CListModeDataROOT::get_empty_record_sptr() const { - shared_ptr sptr(new CListRecordROOT(this->get_proj_data_info_sptr())); - return sptr; + shared_ptr sptr(new CListRecordROOT(this->get_proj_data_info_sptr())); + return sptr; } Succeeded -CListModeDataROOT:: -open_lm_file() +CListModeDataROOT::open_lm_file() { - info(boost::format("CListModeDataROOT: used ROOT file %s") % - this->root_file_sptr->get_ROOT_filename()); - return Succeeded::yes; + 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 +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); + CListRecordROOT& record = dynamic_cast(record_of_general_type); + return root_file_sptr->get_next_record(record); } Succeeded -CListModeDataROOT:: -reset() +CListModeDataROOT::reset() { - return root_file_sptr->reset(); + return root_file_sptr->reset(); } -unsigned long CListModeDataROOT::get_total_number_of_events() const +unsigned long +CListModeDataROOT::get_total_number_of_events() const { - return root_file_sptr->get_total_number_of_events(); + return root_file_sptr->get_total_number_of_events(); } CListModeData::SavedPosition -CListModeDataROOT:: -save_get_position() +CListModeDataROOT::save_get_position() { - return static_cast(root_file_sptr->save_get_position()); + return static_cast(root_file_sptr->save_get_position()); } Succeeded -CListModeDataROOT:: -set_get_position(const CListModeDataROOT::SavedPosition& pos) +CListModeDataROOT::set_get_position(const CListModeDataROOT::SavedPosition& pos) { - return root_file_sptr->set_get_position(pos); + return root_file_sptr->set_get_position(pos); } void -CListModeDataROOT:: -set_defaults() +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; - max_num_timing_bins = -1; - size_timing_bin = -1.F; - tof_mash_factor = 1; - reference_energy = 511.F; - energy_resolution = -1.F; + 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; + max_num_timing_bins = -1; + size_timing_bin = -1.F; + tof_mash_factor = 1; + reference_energy = 511.F; + energy_resolution = -1.F; } Succeeded -CListModeDataROOT:: -check_scanner_match_geometry(std::string& ret, const shared_ptr& scanner_sptr) +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; + 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()) + if (scanner_sptr->get_num_rings() != root_file_sptr->get_num_rings()) { - stream << "the number of rings, "; - ok = false; + stream << "the number of rings, "; + ok = false; } - if (scanner_sptr->get_num_detectors_per_ring() != root_file_sptr->get_num_dets_per_ring()) + 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; + 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()) + 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; + 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()) + 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; + 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()) + 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; + 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()) + 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; + 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()) + 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; + 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()) + 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; + stream << "the number of transaxial crystals per singles unit, "; + ok = false; } - if (!ok) + if (!ok) { - ret = stream.str(); - return Succeeded::no; + ret = stream.str(); + return Succeeded::no; } - return Succeeded::yes; + return Succeeded::yes; } Succeeded -CListModeDataROOT:: -check_scanner_definition(std::string& ret) +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 ) + 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"); + 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; } - if (max_num_timing_bins <= 0 || size_timing_bin <= 1.F || timing_resolution <= 0.F) - info(boost::format("CListModeDataROOT: TOF information is missing. Set relevant keywords if you need TOF:\n\t%s\n\t%s\n\t%s") - % max_num_timing_bins_keyword % size_timing_bin_keyword % timing_resolution_keyword); - + if (max_num_timing_bins <= 0 || size_timing_bin <= 1.F || timing_resolution <= 0.F) + info(boost::format("CListModeDataROOT: TOF information is missing. Set relevant keywords if you need TOF:\n\t%s\n\t%s\n\t%s") + % max_num_timing_bins_keyword % size_timing_bin_keyword % timing_resolution_keyword); - return Succeeded::yes; + return Succeeded::yes; } - END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/CListModeDataSAFIR.cxx b/src/listmode_buildblock/CListModeDataSAFIR.cxx index 840046ee7..96aa9a3cb 100644 --- a/src/listmode_buildblock/CListModeDataSAFIR.cxx +++ b/src/listmode_buildblock/CListModeDataSAFIR.cxx @@ -2,21 +2,21 @@ 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 Copyright 2021 University College London - 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. */ /*! @@ -97,16 +97,14 @@ CListModeDataSAFIR::CListModeDataSAFIR(const std::string& listmode template std::string -CListModeDataSAFIR:: -get_name() const +CListModeDataSAFIR::get_name() const { - return listmode_filename; + return listmode_filename; } template -shared_ptr -CListModeDataSAFIR:: -get_empty_record_sptr() const +shared_ptr +CListModeDataSAFIR::get_empty_record_sptr() const { shared_ptr sptr(new CListRecordT); sptr->event_SAFIR().set_scanner_sptr(this->get_proj_data_info_sptr()->get_scanner_sptr()); @@ -116,46 +114,41 @@ get_empty_record_sptr() const template Succeeded -CListModeDataSAFIR:: -get_next_record(CListRecord& record_of_general_type) const +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_sptr(map); - return status; - + 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_sptr(map); + return status; } template Succeeded -CListModeDataSAFIR:: -reset() +CListModeDataSAFIR::reset() { - return current_lm_data_ptr->reset(); + return current_lm_data_ptr->reset(); } template Succeeded -CListModeDataSAFIR:: -open_lm_file() const +CListModeDataSAFIR::open_lm_file() const { - shared_ptr stream_ptr(new fstream(listmode_filename.c_str(), ios::in | ios::binary )); - if(!(*stream_ptr)) - { - return Succeeded::no; - } - info("CListModeDataSAFIR: opening file \"" + listmode_filename + "\"", 2); - 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; + shared_ptr stream_ptr(new fstream(listmode_filename.c_str(), ios::in | ios::binary)); + if (!(*stream_ptr)) + { + return Succeeded::no; + } + info("CListModeDataSAFIR: opening file \"" + listmode_filename + "\"", 2); + 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>; template class CListModeDataSAFIR>; END_NAMESPACE_STIR - diff --git a/src/listmode_buildblock/CListRecordECAT8_32bit.cxx b/src/listmode_buildblock/CListRecordECAT8_32bit.cxx index 2a24be210..47552a79d 100644 --- a/src/listmode_buildblock/CListRecordECAT8_32bit.cxx +++ b/src/listmode_buildblock/CListRecordECAT8_32bit.cxx @@ -24,36 +24,35 @@ #include #include START_NAMESPACE_STIR -namespace ecat { +namespace ecat +{ -CListEventECAT8_32bit:: -CListEventECAT8_32bit(const shared_ptr& proj_data_info_sptr) : - CListEventCylindricalScannerWithDiscreteDetectors(proj_data_info_sptr) +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()); + 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("CListEventECAT8_32bit can only handle axial compression==1"); - 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->timing_poss_sequence = ecat::find_timing_poss_sequence(*proj_data_info_sptr); + 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->timing_poss_sequence = ecat::find_timing_poss_sequence(*proj_data_info_sptr); } 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->get_uncompressed_proj_data_info_sptr()->get_num_tangential_poss(); const int num_views = this->get_uncompressed_proj_data_info_sptr()->get_num_views(); const int num_non_tof_sinograms = this->get_uncompressed_proj_data_info_sptr()->get_num_non_tof_sinograms(); - 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); int rest = this->data.offset / num_tangential_poss; const int view_num = rest % num_views; rest = rest / num_views; @@ -61,9 +60,9 @@ get_detection_position(DetectionPositionPair<>& det_pos) const const int Siemens_TOF_bin = rest / num_non_tof_sinograms; int axial_pos_num = 0; int segment_num = 0; - for (std::size_t i=0; isegment_sequence.size();++i) + for (std::size_t i = 0; i < this->segment_sequence.size(); ++i) { - if (z< this->sizes[i]) + if (z < this->sizes[i]) { axial_pos_num = z; segment_num = this->segment_sequence[i]; @@ -76,19 +75,16 @@ get_detection_position(DetectionPositionPair<>& det_pos) const } const int timing_pos_num = this->timing_poss_sequence[Siemens_TOF_bin]; // 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), timing_pos_num); - 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), timing_pos_num); + 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 79c71c593..307218046 100644 --- a/src/listmode_buildblock/CListRecordECAT962.cxx +++ b/src/listmode_buildblock/CListRecordECAT962.cxx @@ -13,9 +13,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" @@ -27,16 +27,16 @@ 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; @@ -44,40 +44,37 @@ get_sinogram_and_ring_coordinates( 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 4a4b5efa2..ae8acb9df 100644 --- a/src/listmode_buildblock/CListRecordECAT966.cxx +++ b/src/listmode_buildblock/CListRecordECAT966.cxx @@ -11,11 +11,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" @@ -31,14 +31,15 @@ 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; @@ -46,32 +47,30 @@ get_sinogram_and_ring_coordinates( 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/CListRecordPENN.cxx b/src/listmode_buildblock/CListRecordPENN.cxx index 2c9708f64..173020119 100644 --- a/src/listmode_buildblock/CListRecordPENN.cxx +++ b/src/listmode_buildblock/CListRecordPENN.cxx @@ -10,7 +10,7 @@ \file \ingroup listmode \brief Implementation of classes CListEventPENN - + \author Nikos Efthimiou */ @@ -19,82 +19,73 @@ START_NAMESPACE_STIR -CListEventPENN:: -CListEventPENN(const shared_ptr &scanner_sptr) : - CListEventCylindricalScannerWithDiscreteDetectors(scanner_sptr) +CListEventPENN::CListEventPENN(const shared_ptr& scanner_sptr) + : CListEventCylindricalScannerWithDiscreteDetectors(scanner_sptr) { - quarter_of_detectors = static_cast(scanner_sptr->get_num_detectors_per_ring()/4.f)-4; + quarter_of_detectors = static_cast(scanner_sptr->get_num_detectors_per_ring() / 4.f) - 4; } void -CListEventPENN:: -get_detection_position(DetectionPositionPair<>& det_pos) const +CListEventPENN::get_detection_position(DetectionPositionPair<>& det_pos) const { - DetectionPosition<> det1(d1, z1, 0); - DetectionPosition<> det2(d2, z2, 0); - det_pos.pos1() = det1; - det_pos.pos2() = det2; + DetectionPosition<> det1(d1, z1, 0); + DetectionPosition<> det2(d2, z2, 0); + det_pos.pos1() = det1; + det_pos.pos2() = det2; #ifdef STIR_TOF - det_pos.timing_pos() = tof_bin; + det_pos.timing_pos() = tof_bin; #endif } void -CListEventPENN:: -set_detection_position(const DetectionPositionPair<>&) +CListEventPENN::set_detection_position(const DetectionPositionPair<>&) { error("CListEventPENN: cannot set events yet through this function."); } void -CListEventPENN::init_from_data(bool d, - int dt, - int xa, int xb, - int za, int zb, - int ea, int eb) +CListEventPENN::init_from_data(bool d, int dt, int xa, int xb, int za, int zb, int ea, int eb) { - delay = d; + delay = d; - //TODO: rotation - d1 = xa + static_cast(xa * 0.03125f) + 1; // /32 - d2 = xb + static_cast(xb * 0.03125f) + 1; // /32 + // TODO: rotation + d1 = xa + static_cast(xa * 0.03125f) + 1; // /32 + d2 = xb + static_cast(xb * 0.03125f) + 1; // /32 - // get ring 1 - int r = za * 0.025f; - // for each ring add 16 rings gap - z1 = za + 16*(r + 1); - // get ring 2 - r = zb * 0.025f; - z2 = zb + 16*(r + 1); + // get ring 1 + int r = za * 0.025f; + // for each ring add 16 rings gap + z1 = za + 16 * (r + 1); + // get ring 2 + r = zb * 0.025f; + z2 = zb + 16 * (r + 1); -// orig_z1 = static_cast(za); + // orig_z1 = static_cast(za); // orig_z2 = static_cast(zb); - //energy1 = ea;// * 0.511f; - //energy2 = eb;// * 0.511f; - - #ifdef STIR_TOF - orig_tof_bin = static_cast(dt); - tof_bin =orig_tof_bin; - if (tof_bin < 0) - tof_bin = 0; - #endif - - if (d1 < 0 ) - d1 = this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring() + d1; - else if ( d1 >= this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring()) - d1 = d1 - this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); + // energy1 = ea;// * 0.511f; + // energy2 = eb;// * 0.511f; - if (d2 < 0 ) - d2 = this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring() + d2; - else if ( d2 >= this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring()) - d2 = d2 - this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); +#ifdef STIR_TOF + orig_tof_bin = static_cast(dt); + tof_bin = orig_tof_bin; + if (tof_bin < 0) + tof_bin = 0; +#endif + if (d1 < 0) + d1 = this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring() + d1; + else if (d1 >= this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring()) + d1 = d1 - this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); -// energy1 = stoi(results[8]);// * 0.511f; -// energy2 = stoi(results[9]);// * 0.511f; + if (d2 < 0) + d2 = this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring() + d2; + else if (d2 >= this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring()) + d2 = d2 - this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); + // energy1 = stoi(results[8]);// * 0.511f; + // energy2 = stoi(results[9]);// * 0.511f; } END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/CListRecordROOT.cxx b/src/listmode_buildblock/CListRecordROOT.cxx index 5f1d73512..a50810802 100644 --- a/src/listmode_buildblock/CListRecordROOT.cxx +++ b/src/listmode_buildblock/CListRecordROOT.cxx @@ -23,13 +23,11 @@ START_NAMESPACE_STIR - -CListEventROOT:: -CListEventROOT(const shared_ptr &proj_data_info_sptr) : - CListEventCylindricalScannerWithDiscreteDetectors(proj_data_info_sptr) +CListEventROOT::CListEventROOT(const shared_ptr& proj_data_info_sptr) + : CListEventCylindricalScannerWithDiscreteDetectors(proj_data_info_sptr) { #ifdef STIR_ROOT_ROTATION_AS_V4 - quarter_of_detectors = static_cast(scanner_sptr->get_num_detectors_per_ring()/4.f); + quarter_of_detectors = static_cast(scanner_sptr->get_num_detectors_per_ring() / 4.f); #endif } @@ -37,58 +35,60 @@ CListEventROOT(const shared_ptr &proj_data_info_sptr) : //! \brief fill \c _det_pos from event //! \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.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); + _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<>&) +void +CListEventROOT::set_detection_position(const DetectionPositionPair<>&) { - error("Cannot set events in a ROOT file!"); + 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, - const double& _delta_time) +void +CListEventROOT::init_from_data( + const int& _ring1, const int& _ring2, const int& crystal1, const int& crystal2, const double& _delta_time) { -// 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; + // 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; #ifdef STIR_ROOT_ROTATION_AS_V4 - // STIR assumes that 0 is on y while GATE on the x axis - det1 = crystal1 + quarter_of_detectors; - det2 = crystal2 + quarter_of_detectors; + // STIR assumes that 0 is on y while GATE on the x axis + det1 = crystal1 + quarter_of_detectors; + det2 = crystal2 + quarter_of_detectors; #else - // STIR and GATE assume that 0 is on y axis by rotation of GATE geometries - det1 = crystal1; - det2 = crystal2; + // STIR and GATE assume that 0 is on y axis by rotation of GATE geometries + det1 = crystal1; + det2 = crystal2; #endif - if (det1 < 0 ) - det1 = this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring() + det1; - else if ( det1 >= this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring()) - det1 = det1 - this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); + if (det1 < 0) + det1 = this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring() + det1; + else if (det1 >= this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring()) + det1 = det1 - this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); - if (det2 < 0 ) - det2 = this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring() + det2; - else if ( det2 >= this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring()) - det2 = det2 - this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); + if (det2 < 0) + det2 = this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring() + det2; + else if (det2 >= this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring()) + det2 = det2 - this->get_uncompressed_proj_data_info_sptr()->get_scanner_ptr()->get_num_detectors_per_ring(); - ring1 = _ring1; - ring2 = _ring2; - delta_time = _delta_time; + ring1 = _ring1; + ring2 = _ring2; + delta_time = _delta_time; } END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/ListEvent.cxx b/src/listmode_buildblock/ListEvent.cxx index ff9315bdc..d8089b2c7 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 @@ -19,7 +19,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/listmode/ListRecord.h" #include "stir/ProjDataInfo.h" #include "stir/Bin.h" @@ -28,12 +27,10 @@ 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 b49a8214b..a5b75c339 100644 --- a/src/listmode_buildblock/ListModeData.cxx +++ b/src/listmode_buildblock/ListModeData.cxx @@ -24,38 +24,33 @@ START_NAMESPACE_STIR -ListModeData:: -ListModeData() -{ -} +ListModeData::ListModeData() +{} -ListModeData:: -~ListModeData() +ListModeData::~ListModeData() {} const Scanner& -ListModeData:: -get_scanner() const +ListModeData::get_scanner() const { auto pdi = get_proj_data_info_sptr(); - if(is_null_ptr(pdi)) + if (is_null_ptr(pdi)) error("ListModeData: ProjDataInfo has not been set."); return *pdi->get_scanner_ptr(); } void -ListModeData:: -set_proj_data_info_sptr(shared_ptr 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(); + 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; + 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 22dca9a99..edcce9519 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -1,9 +1,9 @@ /*! - \file + \file \ingroup listmode \brief Implementation of class stir::LmToProjData - + \author Nikos Efthimiou \author Kris Thielemans \author Sanida Mustafovic @@ -21,8 +21,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 @@ -34,7 +34,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 @@ -43,16 +43,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" @@ -63,13 +62,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" @@ -104,56 +103,53 @@ 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_sptr); - -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_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_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); + */ +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); /************************************************************** set/get **************************************************************/ -void LmToProjData::set_template_proj_data_info_sptr(shared_ptr t_sptr) +void +LmToProjData::set_template_proj_data_info_sptr(shared_ptr t_sptr) { this->_already_setup = false; template_proj_data_info_ptr = t_sptr->create_shared_clone(); } -shared_ptr LmToProjData::get_template_proj_data_info_sptr() +shared_ptr +LmToProjData::get_template_proj_data_info_sptr() { return template_proj_data_info_ptr; } -void LmToProjData::set_input_data(const shared_ptr& v) +void +LmToProjData::set_input_data(const shared_ptr& v) { this->_already_setup = false; this->lm_data_ptr = dynamic_pointer_cast(v); @@ -161,7 +157,8 @@ void LmToProjData::set_input_data(const shared_ptr& v) error("LmToProjData::set_input_data() called with non-listmode data or other error"); } -void LmToProjData::set_input_data(const std::string& filename) +void +LmToProjData::set_input_data(const std::string& filename) { shared_ptr lm(stir::read_from_file(filename)); this->set_input_data(lm); @@ -175,69 +172,81 @@ ListModeData& LmToProjData::get_input_data() } #endif - -void LmToProjData::set_output_filename_prefix(const std::string& v) +void +LmToProjData::set_output_filename_prefix(const std::string& v) { this->output_filename_prefix = v; } -std::string LmToProjData::get_output_filename_prefix() const +std::string +LmToProjData::get_output_filename_prefix() const { return output_filename_prefix; } -void LmToProjData::set_output_projdata_sptr(shared_ptr& arg) +void +LmToProjData::set_output_projdata_sptr(shared_ptr& arg) { - this->output_proj_data_sptr = arg; + this->output_proj_data_sptr = arg; } -void LmToProjData::set_store_prompts(bool v) +void +LmToProjData::set_store_prompts(bool v) { this->store_prompts = v; } -bool LmToProjData::get_store_prompts() const +bool +LmToProjData::get_store_prompts() const { return store_prompts; } -void LmToProjData::set_store_delayeds(bool v) +void +LmToProjData::set_store_delayeds(bool v) { this->store_delayeds = v; } -bool LmToProjData::get_store_delayeds() const +bool +LmToProjData::get_store_delayeds() const { return store_delayeds; } -void LmToProjData::set_num_segments_in_memory(int v) +void +LmToProjData::set_num_segments_in_memory(int v) { this->_already_setup = false; this->num_segments_in_memory = v; } -int LmToProjData::get_num_segments_in_memory() const +int +LmToProjData::get_num_segments_in_memory() const { return num_segments_in_memory; } -void LmToProjData::set_num_events_to_store(long int v) +void +LmToProjData::set_num_events_to_store(long int v) { this->num_events_to_store = v; } -long int LmToProjData::get_num_events_to_store() const +long int +LmToProjData::get_num_events_to_store() const { return num_events_to_store; } -void LmToProjData::set_time_frame_definitions(const TimeFrameDefinitions& v) +void +LmToProjData::set_time_frame_definitions(const TimeFrameDefinitions& v) { this->frame_defs = v; } -const TimeFrameDefinitions& LmToProjData::get_time_frame_definitions() const +const TimeFrameDefinitions& +LmToProjData::get_time_frame_definitions() const { return frame_defs; } @@ -245,60 +254,55 @@ const TimeFrameDefinitions& LmToProjData::get_time_frame_definitions() const /************************************************************** 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; } -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 - // 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... + // 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) + if (input_filename.size() == 0) { warning("You have to specify an input_filename\n"); return true; @@ -306,13 +310,12 @@ post_processing() set_input_data(input_filename); - if (template_proj_data_name.size()==0) + if (template_proj_data_name.size() == 0) { warning("You have to specify template_projdata\n"); return true; } - shared_ptr template_proj_data_sptr = - ProjData::read_from_file(template_proj_data_name); + shared_ptr template_proj_data_sptr = ProjData::read_from_file(template_proj_data_name); set_template_proj_data_info_sptr(template_proj_data_sptr->get_proj_data_info_sptr()); @@ -328,11 +331,12 @@ post_processing() return false; } -Succeeded LmToProjData::set_up() +Succeeded +LmToProjData::set_up() { _already_setup = true; - if (!interactive && output_filename_prefix.size()==0) + if (!interactive && output_filename_prefix.size() == 0) { error("You have to specify an output_filename_prefix"); } @@ -355,25 +359,19 @@ Succeeded LmToProjData::set_up() // 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(); + 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); + 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); + num_segments_in_memory = min(num_segments_in_memory, num_segments); if (num_segments == 0) { error("LmToProjData: num_segments_in_memory cannot be 0"); @@ -382,30 +380,29 @@ Succeeded LmToProjData::set_up() if (num_timing_poss_in_memory == -1 || interactive) num_timing_poss_in_memory = num_timing_poss; else - num_timing_poss_in_memory = - min(num_timing_poss_in_memory, num_timing_poss); + num_timing_poss_in_memory = min(num_timing_poss_in_memory, num_timing_poss); if (num_timing_poss == 0) { error("LmToProjData: num_timing_poss_in_memory cannot be 0"); } // handle store_prompts and store_delayeds - + if (store_prompts) { if (store_delayeds) - delayed_increment = -1; + delayed_increment = -1; else - delayed_increment = 0; + delayed_increment = 0; } else { if (store_delayeds) - delayed_increment = 1; + delayed_increment = 1; else - { - error("At least one of store_prompts or store_delayeds should be true"); - } + { + error("At least one of store_prompts or store_delayeds should be true"); + } } if (do_pre_normalisation) @@ -414,39 +411,38 @@ Succeeded LmToProjData::set_up() // 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_sptr->get_num_rings()-1, - scanner_sptr->get_num_detectors_per_ring()/2, - scanner_sptr->get_max_num_non_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"); + 1, + scanner_sptr->get_num_rings() - 1, + scanner_sptr->get_num_detectors_per_ring() / 2, + scanner_sptr->get_max_num_non_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 { auto all_frames_exam_info_sptr = std::make_shared(lm_data_ptr->get_exam_info()); all_frames_exam_info_sptr->set_time_frame_definitions(frame_defs); - 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 (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 (frame_definition_filename.size()!=0) - { - frame_defs = TimeFrameDefinitions(frame_definition_filename); + if (num_events_to_store == 0 && frame_definition_filename.size() == 0) do_time_frame = true; - } + + 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)); + vector> frame_times(1, pair(0, 0)); frame_defs = TimeFrameDefinitions(frame_times); } @@ -457,20 +453,18 @@ Succeeded LmToProjData::set_up() Constructors ***************************************************************/ -LmToProjData:: -LmToProjData() +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 (par_filename != 0) { - if (parse(par_filename)==false) - error("Exiting\n"); + if (parse(par_filename) == false) + error("Exiting\n"); } else ask_parameters(); @@ -482,127 +476,119 @@ LmToProjData(const char * const par_filename) this function is complicated because of the normalisation stuff. sorry ***************************************************************/ void -LmToProjData:: -get_bin_from_event(Bin& bin, const ListEvent& event) const -{ +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 -//#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); -//#endif - - const float bin_efficiency = - normalisation_ptr->get_bin_efficiency(uncompressed_bin); + { + 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 + //#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); + //#endif + + const float bin_efficiency = normalisation_ptr->get_bin_efficiency(uncompressed_bin); // 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.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); - } + { + 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.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); } - -} +} /************************************************************** - Here follows the post_normalisation related stuff. + Here follows the post_normalisation related stuff. ***************************************************************/ -void -LmToProjData:: -do_post_normalisation(Bin& bin) const +void +LmToProjData::do_post_normalisation(Bin& bin) const { - if (bin.get_bin_value()>0) + if (bin.get_bin_value() > 0) { if (do_pre_normalisation) - { - bin.set_bin_value(bin.get_bin_value()/get_compression_count(bin)); - } + { + 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; -//#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); -//#endif - const float bin_efficiency = post_normalisation_ptr->get_bin_efficiency(bin); - // 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); - } - } + { + //#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); + //#endif + const float bin_efficiency = post_normalisation_ptr->get_bin_efficiency(bin); + // 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) {} /************************************************************** @@ -612,8 +598,7 @@ start_new_time_frame(const unsigned int) to store only part of the segments in memory. ***************************************************************/ void -LmToProjData:: -process_data() +LmToProjData::process_data() { if (!_already_setup) error("LmToProjData: you need to call set_up() first"); @@ -624,33 +609,30 @@ process_data() bool writing_to_file = false; // 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()); // a few more checks, now that we have the lm_data_ptr { - 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()) { error("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().get_name().c_str(), - scanner_ptr->get_name().c_str(), - lm_data_ptr->get_scanner().parameter_info().c_str(), - scanner_ptr->parameter_info().c_str()); + "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().get_name().c_str(), + scanner_ptr->get_name().c_str(), + lm_data_ptr->get_scanner().parameter_info().c_str(), + scanner_ptr->parameter_info().c_str()); } - if (lm_data_ptr->has_delayeds()==false && store_delayeds==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=false; + store_delayeds = false; } } // assume list mode data starts at time 0 @@ -660,23 +642,18 @@ 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."); - /* 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); @@ -690,15 +667,14 @@ process_data() // *********** open output file shared_ptr output; if (!output_proj_data_sptr) - { - writing_to_file = true; - char rest[50]; - sprintf(rest, "_f%dg1d0b0", current_frame_num); - const string output_filename = output_filename_prefix + rest; - - output_proj_data_sptr = - construct_proj_data(output, output_filename, this_frame_exam_info, template_proj_data_info_ptr); - } + { + writing_to_file = true; + char rest[50]; + sprintf(rest, "_f%dg1d0b0", current_frame_num); + const string output_filename = output_filename_prefix + rest; + + output_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; @@ -706,39 +682,39 @@ process_data() const double start_time = frame_defs.get_start_time(current_frame_num); const double end_time = frame_defs.get_end_time(current_frame_num); - VectorWithOffset > - 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) + VectorWithOffset> 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(), + 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 = output_proj_data_sptr->get_min_tof_pos_num(); start_timing_pos_index <= output_proj_data_sptr->get_max_tof_pos_num(); start_timing_pos_index += num_timing_poss_in_memory) { - const int end_timing_pos_index = - min( output_proj_data_sptr->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. - */ + const int end_timing_pos_index + = min(output_proj_data_sptr->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 = output_proj_data_sptr->get_min_segment_num(); start_segment_index <= output_proj_data_sptr->get_max_segment_num(); start_segment_index += num_segments_in_memory) { - const int end_segment_index = - min( output_proj_data_sptr->get_max_segment_num()+1, start_segment_index + num_segments_in_memory) - 1; + const int end_segment_index + = min(output_proj_data_sptr->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, + start_timing_pos_index, + end_timing_pos_index, + start_segment_index, + end_segment_index, output_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 @@ -746,13 +722,13 @@ process_data() // ('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; + unsigned long int more_events = do_time_frame ? 1 : num_events_to_store; - if (start_segment_index != output_proj_data_sptr->get_min_segment_num() || start_timing_pos_index > output_proj_data_sptr->get_min_tof_pos_num()) + if (start_segment_index != output_proj_data_sptr->get_min_segment_num() + || start_timing_pos_index > output_proj_data_sptr->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"; + 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; @@ -765,15 +741,13 @@ process_data() // 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) + 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(); + frame_start_positions[current_frame_num] = lm_data_ptr->save_get_position(); } { // loop over all events in the listmode file @@ -782,14 +756,14 @@ process_data() if (lm_data_ptr->get_next_record(record) == Succeeded::no) { // no more events in file for some reason - break; //get out of while loop + 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); + assert(current_time >= start_time); process_new_time_event(record.time()); } // note: could do "else if" here if we would be sure that @@ -804,46 +778,47 @@ process_data() bin.set_bin_value(1.f); bin.time_frame_num() = current_frame_num; - try { - get_bin_from_event(bin, record.event()); - } - catch (...) { - 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++) - delete segments[timing_pos_num][seg]; - error("Something wrong with geometry."); - } + try + { + get_bin_from_event(bin, record.event()); + } + catch (...) + { + 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++) + delete segments[timing_pos_num][seg]; + error("Something wrong with geometry."); + } // check if it's inside the range we want to store - if (bin.get_bin_value()>0 - && bin.tangential_pos_num()>= output_proj_data_sptr->get_min_tangential_pos_num() - && bin.tangential_pos_num()<= output_proj_data_sptr->get_max_tangential_pos_num() - && bin.axial_pos_num()>=output_proj_data_sptr->get_min_axial_pos_num(bin.segment_num()) - && bin.axial_pos_num()<=output_proj_data_sptr->get_max_axial_pos_num(bin.segment_num()) - && bin.timing_pos_num()>=output_proj_data_sptr->get_min_tof_pos_num() - && bin.timing_pos_num()<=output_proj_data_sptr->get_max_tof_pos_num() - ) + if (bin.get_bin_value() > 0 + && bin.tangential_pos_num() >= output_proj_data_sptr->get_min_tangential_pos_num() + && bin.tangential_pos_num() <= output_proj_data_sptr->get_max_tangential_pos_num() + && bin.axial_pos_num() >= output_proj_data_sptr->get_min_axial_pos_num(bin.segment_num()) + && bin.axial_pos_num() <= output_proj_data_sptr->get_max_axial_pos_num(bin.segment_num()) + && bin.timing_pos_num() >= output_proj_data_sptr->get_min_tof_pos_num() + && bin.timing_pos_num() <= output_proj_data_sptr->get_max_tof_pos_num()) { - assert(bin.view_num()>=output_proj_data_sptr->get_min_view_num()); - assert(bin.view_num()<=output_proj_data_sptr->get_max_view_num()); + assert(bin.view_num() >= output_proj_data_sptr->get_min_view_num()); + assert(bin.view_num() <= output_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 + 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) + 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) + 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) + if (bin.segment_num() >= start_segment_index && bin.segment_num() <= end_segment_index) { do_post_normalisation(bin); @@ -853,45 +828,56 @@ process_data() else ++num_delayeds_in_frame; - if (num_stored_events%500000L==0) cout << "\r" << num_stored_events << " events stored" << flush; + 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); + 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; + (*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 + 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); + 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 + } // end of while loop over all events - time_of_last_stored_event = - max(time_of_last_stored_event,current_time); + 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, + save_and_delete_segments(output, + segments, + start_timing_pos_index, + end_timing_pos_index, + start_segment_index, + end_segment_index, *output_proj_data_sptr); } // 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'; + 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'; // if we used the member variable for writing to file, reset it to null again if (writing_to_file) @@ -900,25 +886,25 @@ process_data() } } // end of loop over frames - timer.stop(); + 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_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; + cerr << "\nThis took " << timer.value() << "s CPU time." << endl; } #if 0 void LmToProjData::run_tof_test_function() { -#if 1 +# if 1 error("TOF test function disabled"); -#else +# else VectorWithOffset > segments (template_proj_data_info_ptr->get_min_tof_pos_num(), @@ -992,68 +978,65 @@ LmToProjData::run_tof_test_function() } // end of for loop for segment range } // end of for loop for timing positions -#endif +# endif } #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) +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++) - { + 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 - segments[timing_pos_num][seg] = new SegmentByView( - proj_data_info_sptr->get_empty_segment_by_view (seg, false, timing_pos_num)); + segments[timing_pos_num][seg] + = new SegmentByView(proj_data_info_sptr->get_empty_segment_by_view(seg, false, timing_pos_num)); #else - 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)); + 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 - } + } } -void +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) + 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++) + 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]); + proj_data.set_segment(*segments[timing_pos_num][seg]); #else - (*segments[timing_pos_num][seg]).write_data(*output); + (*segments[timing_pos_num][seg]).write_data(*output); #endif - delete segments[timing_pos_num][seg]; + delete segments[timing_pos_num][seg]; } } - - -static -shared_ptr +static shared_ptr construct_proj_data(shared_ptr& output, - const string& output_filename, - const ExamInfo& exam_info, + const string& output_filename, + const ExamInfo& exam_info, const shared_ptr& proj_data_info_ptr) { shared_ptr exam_info_sptr(new ExamInfo(exam_info)); @@ -1061,41 +1044,43 @@ construct_proj_data(shared_ptr& output, shared_ptr proj_data_sptr; // don't need output stream in this case 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)); + 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)); + 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 952f816bc..b011a0bdb 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 */ /* @@ -19,5 +19,4 @@ START_NAMESPACE_STIR - END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/LmToProjDataBootstrap.cxx b/src/listmode_buildblock/LmToProjDataBootstrap.cxx index df5469398..bb0d5042e 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 @@ -37,12 +37,10 @@ using std::endl; #include #include - - START_NAMESPACE_STIR template -void +void LmToProjDataBootstrap::set_defaults() { LmToProjData::set_defaults(); @@ -50,43 +48,43 @@ LmToProjDataBootstrap::set_defaults() } template -void +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) + 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; - } + { + 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 this->ask_parameters(); @@ -94,16 +92,16 @@ LmToProjDataBootstrap(const char * const par_filename, const unsigned int seed_v template bool -LmToProjDataBootstrap:: -post_processing() +LmToProjDataBootstrap::post_processing() { return LmToProjDataT::post_processing(); } template -Succeeded LmToProjDataBootstrap::set_up() +Succeeded +LmToProjDataBootstrap::set_up() { - if (LmToProjDataT::set_up() == Succeeded::no) + if (LmToProjDataT::set_up() == Succeeded::no) return Succeeded::no; if (this->seed == 0) @@ -113,10 +111,9 @@ Succeeded LmToProjDataBootstrap::set_up() return Succeeded::yes; } -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); @@ -126,117 +123,105 @@ 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 (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; - } + { + 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 + { + ++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) + + 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); - + 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) @@ -249,10 +234,7 @@ get_bin_from_event(Bin& bin, const ListEvent& event) const ++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 63720a02b..821966cfd 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 @@ -29,12 +29,10 @@ #include #include - - START_NAMESPACE_STIR template -void +void LmToProjDataWithRandomRejection::set_defaults() { LmToProjData::set_defaults(); @@ -43,44 +41,45 @@ LmToProjDataWithRandomRejection::set_defaults() } template -void +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) + 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; - } + { + 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 this->ask_parameters(); @@ -88,65 +87,60 @@ LmToProjDataWithRandomRejection(const char * const par_filename, const unsigned template bool -LmToProjDataWithRandomRejection:: -post_processing() +LmToProjDataWithRandomRejection::post_processing() { return LmToProjDataT::post_processing(); } template -Succeeded LmToProjDataWithRandomRejection::set_up() +Succeeded +LmToProjDataWithRandomRejection::set_up() { - if (LmToProjDataT::set_up() == Succeeded::no) + if (LmToProjDataT::set_up() == Succeeded::no) return Succeeded::no; if (this->seed == 0) { - error("Seed needs to be non-zero"); return Succeeded::no; + error("Seed needs to be non-zero"); + return Succeeded::no; } - if (this->reject_if_above<0.F || this->reject_if_above>1.F) + if (this->reject_if_above < 0.F || this->reject_if_above > 1.F) { - error("reject_if_above needs to be between 0 and 1"); return Succeeded::no; + error("reject_if_above needs to be between 0 and 1"); + return Succeeded::no; } return Succeeded::yes; - } -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'; + const double randnum = random01(); + // std::cout << randnum << '\n'; if (randnum <= this->reject_if_above) { base_type::get_bin_from_event(bin, event); @@ -155,10 +149,7 @@ get_bin_from_event(Bin& bin, const ListEvent& event) const 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 a388ec6e8..73e865130 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 */ /* @@ -20,41 +20,52 @@ 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 +void +LmToProjDataNiftyPET::check_input() const { - if (_listmode_binary_file.empty()) - throw std::runtime_error("LmToProjDataNiftyPET::process_data: listmode binary file not set."); + 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() +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); + // 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); } 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 7db41aaaa..69be95a8e 100644 --- a/src/listmode_utilities/add_ecat7_header_to_sgl.cxx +++ b/src/listmode_utilities/add_ecat7_header_to_sgl.cxx @@ -9,7 +9,7 @@ See STIR/LICENSE.txt for more details. */ -/*! +/*! \file \ingroup utilities \ingroup ECAT @@ -18,7 +18,6 @@ \author Nacer Kerrouche */ - #include "stir/IO/stir_ecat7.h" #include "stir/warning.h" #include "stir/error.h" @@ -31,114 +30,108 @@ 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]; + 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; - } + { + is_3d_scan = false; + --argc; + ++argv; + } else if (strcmp(argv[1], "--3d") == 0) - { - is_3d_scan = true; - --argc; ++argv; - } + { + is_3d_scan = true; + --argc; + ++argv; + } else - print_usage_and_exit(program_name); + print_usage_and_exit(program_name); } - if(argc!=4) + 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) { - 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); + 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); + } - 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 + 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)) + char buffer[512]; + int success = EXIT_SUCCESS; + while (!feof(sgl_fptr)) { - size_t num_read = - fread(buffer, 1, 512, 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; - } + { + 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 a35c64123..f929fe586 --- a/src/listmode_utilities/conv_NiftyPET_stir.cxx +++ b/src/listmode_utilities/conv_NiftyPET_stir.cxx @@ -26,191 +26,216 @@ USING_NAMESPACE_STIR -static void print_usage_and_exit( const char * const program_name, const int 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); + 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) +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 + ")."); + 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); + output_file_format_sptr->write_to_file(filename, out_im_stir); } -static shared_ptr > read_disc_density(const std::string &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 + "."); + // 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) +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(); + 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) +static std::vector +read_binary_file(const std::string& data_path) { - std::ifstream file(data_path, std::ios::in | std::ios::binary); + 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); + // 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); + std::vector contents(num_elements); + file.read(reinterpret_cast(contents.data()), file_size); - return contents; + return contents; } int -main(int argc, char **argv) +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; + // 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 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); + else + { + std::cerr << "Unknown option '" << argv[0] << "'\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); + // 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); + // 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); + // 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); + // 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); } } } - // If there was an error - catch(const std::exception &error) { - std::cerr << "\nError encountered:\n\t" << error.what() << "\n\n"; - return 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; } - catch(...) { - std::cerr << "\nError encountered.\n\n"; - return EXIT_FAILURE; + catch (...) + { + std::cerr << "\nError encountered.\n\n"; + return EXIT_FAILURE; } - return(EXIT_SUCCESS); + return (EXIT_SUCCESS); } diff --git a/src/listmode_utilities/list_lm_countrates.cxx b/src/listmode_utilities/list_lm_countrates.cxx index 0beaa9aba..c1468a921 100644 --- a/src/listmode_utilities/list_lm_countrates.cxx +++ b/src/listmode_utilities/list_lm_countrates.cxx @@ -32,20 +32,20 @@ #include #include - USING_NAMESPACE_STIR -int main(int argc, char * argv[]) +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"; - exit(EXIT_FAILURE); - } - shared_ptr lm_data_ptr - (read_from_file(argv[2])); + 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"; + exit(EXIT_FAILURE); + } + 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) @@ -54,52 +54,48 @@ int main(int argc, char * argv[]) 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; - } - } + { + 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 0930bc2f7..c104cdecf 100644 --- a/src/listmode_utilities/list_lm_events.cxx +++ b/src/listmode_utilities/list_lm_events.cxx @@ -10,16 +10,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" @@ -39,70 +38,71 @@ using std::cout; using std::endl; using std::vector; - - USING_NAMESPACE_STIR -int main(int argc, char *argv[]) +int +main(int argc, char* argv[]) { - const char * const program_name = argv[0]; + const char* const program_name = argv[0]; // skip program name --argc; ++argv; - bool list_time=true; - bool list_coincidence=false; - bool list_event_LOR=false; - bool list_event_bin=false; - bool list_gating=true; - bool list_unknown=false; + bool list_time = true; + bool list_coincidence = false; + bool list_event_LOR = false; + bool list_event_bin = false; + bool list_gating = true; + bool list_unknown = false; unsigned long num_events_to_list = 0; - while (argc>1 && argv[0][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) + 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; + list_time = atoi(argv[1]) != 0; } - else if (strcmp(argv[0], "--gating")==0) + else if (strcmp(argv[0], "--gating") == 0) { - list_gating = atoi(argv[1])!=0; + list_gating = atoi(argv[1]) != 0; } - else if (strcmp(argv[0], "--coincidence")==0) + else if (strcmp(argv[0], "--coincidence") == 0) { - list_coincidence = atoi(argv[1])!=0; + list_coincidence = atoi(argv[1]) != 0; } - else if (strcmp(argv[0], "--event-LOR")==0 || strcmp(argv[0], "--SPECT-event")==0) + else if (strcmp(argv[0], "--event-LOR") == 0 || strcmp(argv[0], "--SPECT-event") == 0) { - list_event_LOR = atoi(argv[1])!=0; + list_event_LOR = atoi(argv[1]) != 0; } - else if (strcmp(argv[0], "--event-bin")==0) + else if (strcmp(argv[0], "--event-bin") == 0) { - list_event_bin = atoi(argv[1])!=0; + list_event_bin = atoi(argv[1]) != 0; } - else if (strcmp(argv[0], "--unknown")==0) + else if (strcmp(argv[0], "--unknown") == 0) { - list_unknown = atoi(argv[1])!=0; + list_unknown = atoi(argv[1]) != 0; } else - { + { cerr << "Unrecognised option\n"; return EXIT_FAILURE; } - argc-=2; argv+=2; + argc -= 2; + argv += 2; } - if (argc!=1) + 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 0|1): list coincidence event info or not (default: 0)\n" - << "--event-LOR 0|1 : (identical to --SPECT-event) list LOR end-points if coincidence/gamma event, or not (default: 0)\n" + << "--event-LOR 0|1 : (identical to --SPECT-event) list LOR end-points if coincidence/gamma event, or not (default: " + "0)\n" << "--event-bin 0|1 : bin coordinates if coincidence/gamma event, 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" @@ -114,7 +114,7 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - if ( list_event_LOR) + if (list_event_LOR) cout << "LORs will be listed as 2 points (z1,y1,x1)-(z2,y2,x2).\n"; shared_ptr lm_data_ptr(read_from_file(argv[0])); @@ -125,111 +125,97 @@ int main(int argc, char *argv[]) cout << "Scanner: " << scanner.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) + 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; + // 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; + listed = true; } - } + } { - ListRecordWithGatingInput * record_ptr = dynamic_cast(&record); - if (record_ptr!=0 && record_ptr->is_gating_input()) + ListRecordWithGatingInput* record_ptr = dynamic_cast(&record); + if (record_ptr != 0 && record_ptr->is_gating_input()) { - recognised=true; + recognised = true; if (list_gating) { cout << "Gating " << std::hex << record_ptr->gating_input().get_gating() << std::dec; - listed = true; + listed = true; } } } if (record.is_event()) - { - recognised=true; - Bin bin; - record.event().get_bin(bin, *proj_data_info_sptr); + { + recognised = true; + Bin bin; + record.event().get_bin(bin, *proj_data_info_sptr); - if (list_coincidence) - { - - if (auto event_ptr = - dynamic_cast(&record.event())) - { - cout << "Coincidence " << (event_ptr->is_prompt() ? "p " : "d "); - } - if (auto event_ptr = - dynamic_cast(&record.event())) - { - DetectionPositionPair<> det_pos; - event_ptr->get_detection_position(det_pos); - cout << "(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() - << ")\t"; - if (list_TOF_info) - cout << " TOF-bin: " << det_pos.timing_pos(); - listed = true; - } - } - if (list_event_LOR) - { - const auto lor = record.event().get_LOR(); - cout << " LOR " - << "(" << lor.p1().z() - << "," << lor.p1().y() - << "," << lor.p1().x() - << ")-" - << "(" << lor.p2().z() - << "," << lor.p2().y() - << "," << lor.p2().x() - << ")"; - if (list_TOF_info) - cout << " k: " << proj_data_info_sptr->get_k(bin); - listed = true; - } - if (list_event_bin) - { - cout << " bin " << bin; - listed = true; - } - } + if (list_coincidence) + { + + if (auto event_ptr = dynamic_cast(&record.event())) + { + cout << "Coincidence " << (event_ptr->is_prompt() ? "p " : "d "); + } + if (auto event_ptr = dynamic_cast(&record.event())) + { + DetectionPositionPair<> det_pos; + event_ptr->get_detection_position(det_pos); + cout << "(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() << ")\t"; + if (list_TOF_info) + cout << " TOF-bin: " << det_pos.timing_pos(); + listed = true; + } + } + if (list_event_LOR) + { + const auto lor = record.event().get_LOR(); + cout << " LOR " + << "(" << lor.p1().z() << "," << lor.p1().y() << "," << lor.p1().x() << ")-" + << "(" << lor.p2().z() << "," << lor.p2().y() << "," << lor.p2().x() << ")"; + if (list_TOF_info) + cout << " k: " << proj_data_info_sptr->get_k(bin); + listed = true; + } + if (list_event_bin) + { + cout << " bin " << bin; + listed = true; + } + } if (!recognised && list_unknown) - { - cout << "Unknown type"; - listed = true; - } + { + cout << "Unknown type"; + listed = true; + } if (listed) { - ++num_listed_events; + ++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 c82dda6ca..02a178e1e 100644 --- a/src/listmode_utilities/list_lm_info.cxx +++ b/src/listmode_utilities/list_lm_info.cxx @@ -29,22 +29,24 @@ #include "stir/is_null_ptr.h" #include "stir/IO/read_from_file.h" #include "stir/warning.h" -#include +#include #include USING_NAMESPACE_STIR -void print_usage_and_exit(const std::string& program_name) +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"; + 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; @@ -55,34 +57,37 @@ 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) + 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; - } + 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); + print_usage_and_exit(program_name); } if (no_options) print_exam = true; - if(argc!=1) - { - print_usage_and_exit(program_name); - } + if (argc != 1) + { + print_usage_and_exit(program_name); + } // set filename to last remaining argument const std::string filename(argv[0]); diff --git a/src/listmode_utilities/lm_fansums.cxx b/src/listmode_utilities/lm_fansums.cxx index 60371a7a3..340a000e4 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 $ */ /* @@ -19,7 +19,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/utilities.h" #include "stir/shared_ptr.h" #include "stir/ParsingObject.h" @@ -53,12 +52,10 @@ using std::vector; START_NAMESPACE_STIR - 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; @@ -66,8 +63,8 @@ class LmFansums : public ParsingObject TimeFrameDefinitions frame_defs; void compute(); -private: +private: void set_defaults() override; void initialise_keymap() override; bool post_processing() override; @@ -79,193 +76,165 @@ 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() +LmFansums::post_processing() { - lm_data_ptr = - read_from_file(input_filename); + lm_data_ptr = read_from_file(input_filename); - const int num_rings = - lm_data_ptr->get_scanner().get_num_rings(); - if (max_segment_num_to_process==-1) - max_segment_num_to_process = num_rings-1; + const int num_rings = lm_data_ptr->get_scanner().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().get_max_num_non_arccorrected_bins(); - if (fan_size==-1) + const int max_fan_size = lm_data_ptr->get_scanner().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().get_num_rings(); - const int num_detectors_per_ring = - lm_data_ptr->get_scanner().get_num_detectors_per_ring(); - + const int num_rings = lm_data_ptr->get_scanner().get_num_rings(); + const int num_detectors_per_ring = lm_data_ptr->get_scanner().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 - } + 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 + 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; } - 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) + if (first_event && dynamic_cast(&record.event()) == 0) error("Currently only works for scanners with discrete detectors."); - first_event=false; + 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) + 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); + 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); + 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); } - 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; @@ -274,12 +243,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); @@ -292,28 +258,21 @@ 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) { - cerr << "Usage: " << argv[0] << " [par_file]\n"; - exit(EXIT_FAILURE); - } - LmFansums lm_fansums(argc==2 ? argv[1] : 0); + + if (argc != 1 && argc != 2) + { + cerr << "Usage: " << argv[0] << " [par_file]\n"; + exit(EXIT_FAILURE); + } + 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 f7bdd9ec4..d818250ae 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 @@ -29,27 +29,25 @@ using std::endl; USING_NAMESPACE_STIR - - -int main(int argc, char * argv[]) +int +main(int argc, char* argv[]) { - if (argc>1) + 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); - } + 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); + } // 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); - } + { + cerr << endl << "Supported input file formats:\n"; + InputFileFormatRegistry::default_sptr()->list_registered_names(cerr); + exit(EXIT_SUCCESS); + } #if 0 if (strcmp(argv[1], "--test_timing_positions") == 0) { @@ -64,10 +62,9 @@ int main(int argc, char * argv[]) } #endif } - LmToProjData application(argc==2 ? argv[1] : 0); + LmToProjData application(argc == 2 ? argv[1] : 0); std::cerr << application.parameter_info(); 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 fa8565f83..71f7f3d6c 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 @@ -21,121 +21,151 @@ USING_NAMESPACE_STIR -static void print_usage_and_exit( const char * const program_name, const int 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); + 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[]) +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; + 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], "-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], "-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_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], "-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], "--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 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); + 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 (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 (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); + 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 (!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 (!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); + if (!n_filename.empty()) + { + std::cout << "\n saving norm sinogram to " << n_filename << "\n"; + lmNP.get_norm_sptr()->write_to_file(n_filename); } } - // If there was an error - catch(const std::exception &error) { - std::cerr << "\nError encountered:\n\t" << error.what() << "\n\n"; - return 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; } - catch(...) { - std::cerr << "\nError encountered.\n\n"; - return EXIT_FAILURE; + catch (...) + { + std::cerr << "\nError encountered.\n\n"; + return EXIT_FAILURE; } - return(EXIT_SUCCESS); + return (EXIT_SUCCESS); } diff --git a/src/listmode_utilities/lm_to_projdata_bootstrap.cxx b/src/listmode_utilities/lm_to_projdata_bootstrap.cxx index 3ce38f9cc..0865880e2 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 $ */ /* @@ -23,30 +23,26 @@ USING_NAMESPACE_STIR - - -int main(int argc, char * argv[]) +int +main(int argc, char* argv[]) { - - if (argc<1 && argc>3) { - std::cerr << "Usage: " << argv[0] << " [par_file [seed]]\n"; - exit(EXIT_FAILURE); - } + + 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) + if (argc == 3) { - LmToProjDataBootstrap - application(argc>=2 ? argv[1] : 0, - atoi(argv[2])); + LmToProjDataBootstrap application(argc >= 2 ? argv[1] : 0, atoi(argv[2])); application.process_data(); } else { - LmToProjDataBootstrap - application(argc==2 ? argv[1] : 0); + 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 61fdde5e8..c24d38a9b 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 @@ -22,19 +23,18 @@ USING_NAMESPACE_STIR +int +main(int argc, char* argv[]) +{ + if ((argc < 1) || (argc > 3)) + { + std::cerr << "Usage: " << argv[0] << " [par_file fraction_of_counts_to_keep]]\n"; + exit(EXIT_FAILURE); + } -int main(int argc, char * argv[]) -{ - - 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 626140bb1..a7df878f7 100644 --- a/src/listmode_utilities/print_sgl_values.cxx +++ b/src/listmode_utilities/print_sgl_values.cxx @@ -16,16 +16,13 @@ \author Tim Borgeaud */ - #include "stir/data/SinglesRatesFromSglFile.h" - #include #include #include #include - using std::cout; using std::cerr; using std::endl; @@ -35,31 +32,29 @@ 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"; - cerr << "Usage: " << argv[0] << " sgl_filename [bin_index ...]\n\n"; - cerr << "If no bin index values are supplied, all bins are output.\n\n"; - exit(EXIT_FAILURE); - } + if (argc < 2) + { + cerr << "Program to print out values from a singles file.\n\n"; + cerr << "Usage: " << argv[0] << " sgl_filename [bin_index ...]\n\n"; + cerr << "If no bin index values are supplied, all bins are output.\n\n"; + exit(EXIT_FAILURE); + } const string sgl_filename = argv[1]; - for (int arg = 2 ; arg < argc ; ++arg) { - columns.push_back(atoi(argv[arg])); - } - - + for (int arg = 2; arg < argc; ++arg) + { + columns.push_back(atoi(argv[arg])); + } + // Singles file object. ecat::ecat7::SinglesRatesFromSglFile singles_from_sgl; @@ -68,53 +63,51 @@ 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) { - cout << setw(9) << *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) { - - // 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 ) { - int val = singles_from_sgl.get_singles_rate(*col, time_slice); - - cout << setw(9) << val << " "; - } - } - - // Output the end of line. - cout << "\n"; + 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) + { + 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 6a1197590..b9f985b88 100644 --- a/src/listmode_utilities/rebin_sgl_file.cxx +++ b/src/listmode_utilities/rebin_sgl_file.cxx @@ -18,7 +18,6 @@ \author Tim Borgeaud */ - #include "stir/data/SinglesRatesFromSglFile.h" #include "stir/TimeFrameDefinitions.h" #include "stir/error.h" @@ -27,7 +26,6 @@ #include #include - using std::cerr; using std::endl; using std::string; @@ -35,130 +33,121 @@ 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 ) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - - + 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] == '-' ) { - // 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' ) { - cerr << "Unknown option " << argv[1][i] << endl; + 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') + { + 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) + { + + 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; + // 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; } - } - - 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) { - - 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; - // 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++) { - new_times[arg - 3] = atof(argv[arg]); } - - } + 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++) + { + 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. output.open(output_filename.c_str(), std::ios_base::out); - if (!output.good()) { - error("Error opening output file\n"); - } - + if (!output.good()) + { + 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 56c7db921..34907dbec 100644 --- a/src/listmode_utilities/scan_sgl_file.cxx +++ b/src/listmode_utilities/scan_sgl_file.cxx @@ -15,7 +15,6 @@ \author Tim Borgeaud */ - #include "stir/data/SinglesRatesFromSglFile.h" #include "stir/error.h" @@ -31,11 +30,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; @@ -48,128 +44,115 @@ 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 ) { - end_slice = num_slices - 1; - } - - return(calcMedian(singles_rates, singles_bin_index, start_slice, end_slice)); -} - + if (end_slice >= num_slices) + { + end_slice = num_slices - 1; + } + 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, - int transaxial_offset) { +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 ) { - transaxial += num_transaxial; - } - - + 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); - } - } else if ( compareAdjacentBin(value, slice, singles_bin_index, singles_rates, 1) && - compareAdjacentBin(value, slice, singles_bin_index, singles_rates, 2) ) { - return(true); - } - - return(false); -} - - +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); + } + return (false); +} // // Check that a value is either within a tolerance of the median @@ -177,228 +160,202 @@ 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, - int previous_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 ) { - // Value is good. - return(true); - } - +checkValue( + int value, int slice, int singles_bin_index, const ecat::ecat7::SinglesRatesFromSglFile& singles_rates, int previous_value) +{ - // Check against values from adjacent (transaxial) bins. - if ( checkAdjacentBins(value, slice, singles_bin_index, singles_rates) ) { - // Value is good. - return(true); + // 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) + { + // Value is good. + return (true); + } + + // Check against values from adjacent (transaxial) bins. + if (checkAdjacentBins(value, slice, singles_bin_index, singles_rates)) + { + // Value is good. + 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) + { + + // 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) + { + // Value is good. + 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)) + { + // Value is good. + 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 ) { - - // 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 ) { - // Value is good. - 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) ) { - // Value is good. - 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) + { + previous = singles_rates.get_singles_rate(singles_bin_index, slice - 1); + } - 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 ) { - next_value = singles_rates.get_singles_rate(singles_bin_index, next_slice); - - if ( checkValue(next_value, next_slice, singles_bin_index, singles_rates, previous) ) { - break; - } - } - - 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); - - singles_rates.set_singles_rate(singles_bin_index, slice, value); - } - - // Value was bad so return true. - return(true); - -} + 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)) + { + break; + } + } + 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); + singles_rates.set_singles_rate(singles_bin_index, slice, value); + } + + // Value was bad so 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) { - - // Loop over each time 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) ) { - - 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 - << "\n"; - } - - } - - } - - return(changed); - -} + 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) + { + int value = singles_rates.get_singles_rate(singles_bin, slice); + 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 << "\n"; + } + } + } + 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) { + if (argc > 3 || argc < 2) + { 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 ) { - write_file = true; - output_filename = argv[2]; - } - - + 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() ) { - - output.open(output_filename.c_str(), std::ios_base::out); - - if (!output.good()) - error("Error opening output file\n"); - } - - - - if ( correctAllValues(singles_from_sgl, cout) && write_file ) { - // Write data to output file. - singles_from_sgl.write(output); - } - - + if (output_filename.length()) + { + + output.open(output_filename.c_str(), std::ios_base::out); + + if (!output.good()) + error("Error opening output file\n"); + } + + 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 6dbbd3311..72dbd684b 100644 --- a/src/modelling_buildblock/KineticModel.cxx +++ b/src/modelling_buildblock/KineticModel.cxx @@ -14,22 +14,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 63ad82782..e9d484bdd 100644 --- a/src/modelling_buildblock/ParametricDiscretisedDensity.cxx +++ b/src/modelling_buildblock/ParametricDiscretisedDensity.cxx @@ -17,7 +17,7 @@ \author Kris Thielemans \author Richard Brown - + */ #include "stir/modelling/ParametricDiscretisedDensity.h" @@ -38,8 +38,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; @@ -48,23 +47,19 @@ get_num_params() } TEMPLATE -ParamDiscDensity:: -ParametricDiscretisedDensity(const DynamicDiscretisedDensity& dyn_im) +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()) + 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()); + 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()) +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()); + this->set_exam_info(im.get_exam_info()); } #if 0 @@ -88,11 +83,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]); @@ -107,7 +102,7 @@ ParametricDiscretisedDensity(const VectorWithOffsetget_num_params()); + 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) - { + 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; - } + ++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()) + ParamDiscDensity* res = this->clone(); + typename ParamDiscDensity::iterator parametric_density_iter = res->begin(); + while (parametric_density_iter != res->end()) { assign(*parametric_density_iter++, 0); } @@ -189,58 +177,47 @@ get_empty_copy() const } 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 +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); + 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 @@ -248,7 +225,7 @@ 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. +#if 0 //!< Implementation of non-const functions - which should be able to update a single parameter of a parametric image. TEMPLATE template void @@ -299,16 +276,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 68f48ee34..59b8b0efc 100644 --- a/src/modelling_buildblock/PatlakPlot.cxx +++ b/src/modelling_buildblock/PatlakPlot.cxx @@ -17,7 +17,6 @@ */ - #include "stir/modelling/PatlakPlot.h" #include "stir/linear_regression.h" #include "stir/warning.h" @@ -26,288 +25,297 @@ 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; +{ + 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) +//! Simply set model matrix +void +PatlakPlot::set_model_matrix(ModelMatrix<2> model_matrix) { - this->_model_matrix=model_matrix; - this->_matrix_is_stored=true; + 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) +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.; + // 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 ) + // 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))); - } - } - 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()); + 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.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; + this->_matrix_is_stored = true; } - else + else warning("ModelMatrix has been already created"); } -Succeeded +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 +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()); +#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 +#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) + 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 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) + 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 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) - { + 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]; + // 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, + 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; + 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 +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()); +#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 +#endif // NDEBUG } - this->_model_matrix.multiply_dynamic_image_with_model(par_image,dyn_image); + 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 +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()); +#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 +#endif // NDEBUG } - this->_model_matrix.multiply_dynamic_image_with_model_and_add_to_input(par_image,dyn_image); + 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 +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()); +#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 +#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; } @@ -318,16 +326,14 @@ PatlakPlot::get_ending_frame() const return this->get_time_frame_definitions().get_num_frames(); } -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"); @@ -337,44 +343,43 @@ 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") + 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); + 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; + 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 59cb2e522..f2b022db3 100644 --- a/src/modelling_buildblock/modelling_registries.cxx +++ b/src/modelling_buildblock/modelling_registries.cxx @@ -14,7 +14,7 @@ \brief File that registers all stir::RegisterObject children in modelling \author Charalampos Tsoumpas - + */ #include "stir/modelling/PatlakPlot.h" @@ -23,4 +23,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 bf989e39d..3be199900 100644 --- a/src/modelling_utilities/apply_patlak_to_images.cxx +++ b/src/modelling_utilities/apply_patlak_to_images.cxx @@ -16,20 +16,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. @@ -48,51 +49,52 @@ #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 (argc == 4) { if (indirect_patlak.parse(argv[3]) == false) - return EXIT_FAILURE; + return EXIT_FAILURE; } - if (argc!=3 && argc!=4) + 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) + if (argc == 3) indirect_patlak.ask_parameters(); CPUTimer timer; timer.start(); - if (indirect_patlak.set_up()==Succeeded::no) - 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; + 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); + // 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 ; + 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 d6e0b07f6..13b450559 100644 --- a/src/modelling_utilities/extract_single_images_from_parametric_image.cxx +++ b/src/modelling_utilities/extract_single_images_from_parametric_image.cxx @@ -17,14 +17,14 @@ \author Kris Thielemans \par Usage: - \code + \code extract_single_images_from_parametric_image output_filename_pattern input_header_filename output_format_parameter_file \endcode The output filename should look something like this: `param_im_%d_output.file_extension`, so that we can use boost format. In this fashion, you can can specify the output file extension should you wish. - + An example of an output parameter file is as follows: \code OutputFileFormat Parameters:= @@ -49,79 +49,91 @@ #include "stir/Succeeded.h" #include "stir/error.h" -int main(int argc, char *argv[]) +int +main(int argc, char* argv[]) { - USING_NAMESPACE_STIR + 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; + 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]) + ")."); + 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); + // 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 { - // 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); + current_filename = boost::str(boost::format(argv[1]) % 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; + 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."); + // 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; + // 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/modelling_utilities/get_dynamic_images_from_parametric_images.cxx b/src/modelling_utilities/get_dynamic_images_from_parametric_images.cxx index 6dcb3403b..f36a8e498 100644 --- a/src/modelling_utilities/get_dynamic_images_from_parametric_images.cxx +++ b/src/modelling_utilities/get_dynamic_images_from_parametric_images.cxx @@ -14,21 +14,21 @@ \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_dynamic_image input_parametric_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: - - \code + + \code output file format parameters := output file format type := Interfile interfile Output File Format Parameters:= @@ -58,110 +58,109 @@ USING_NAMESPACE_STIR -shared_ptr > set_up_output_format(int argc, char *argv[]) +shared_ptr> +set_up_output_format(int argc, char* argv[]) { - shared_ptr > output = - OutputFileFormat::default_sptr(); + 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 (argc >= 4) { if (patlak_plot.parse(argv[3]) == false) - return EXIT_FAILURE; + return EXIT_FAILURE; } - if (argc!=3 && argc!=4 && argc!=5) + 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) + if (argc == 3) patlak_plot.ask_parameters(); - if (patlak_plot.set_up()==Succeeded::no) - return EXIT_FAILURE ; + if (patlak_plot.set_up() == Succeeded::no) + return EXIT_FAILURE; else - { - shared_ptr - par_image_sptr(ParametricVoxelsOnCartesianGrid::read_from_file(argv[2])); + { + 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"; + { + 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); + // 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); #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"; - 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; + 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()); + 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); - } + 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 6d6964d13..1acc6f18b 100644 --- a/src/modelling_utilities/make_parametric_image_from_components.cxx +++ b/src/modelling_utilities/make_parametric_image_from_components.cxx @@ -16,7 +16,7 @@ \author Richard Brown \par Usage: - \code + \code make_parametric_image_from_components output_parametric_image slope intercept \endcode @@ -35,73 +35,83 @@ #include "stir/ProjDataInfo.h" -int main(int argc, char *argv[]) +int +main(int argc, char* argv[]) { - USING_NAMESPACE_STIR + 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; + 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 { + try + { - std::vector > params; + std::vector> params; - // Loop over all parameters - for (int i=2; i > im(read_from_file >(argv[i])); - // Check - if (is_null_ptr(im)) throw std::runtime_error("Failed to read file: " + std::string(argv[i]) + "."); + // 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]) + "."); - // Convert to VoxelsOnCartesianGrid - if (is_null_ptr(dynamic_cast*>(im.get()))) - throw std::runtime_error("Failed to convert parameter to VoxelsOnCartesianGrid."); + // Convert to VoxelsOnCartesianGrid + if (is_null_ptr(dynamic_cast*>(im.get()))) + throw std::runtime_error("Failed to convert parameter to VoxelsOnCartesianGrid."); - VoxelsOnCartesianGrid *param = dynamic_cast*>(im.get()); + VoxelsOnCartesianGrid* param = dynamic_cast*>(im.get()); - params.push_back(*param); + params.push_back(*param); - // 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) + ")."); + // 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."); + // 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; + 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; + // 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/modelling_utilities/mult_image_parameters.cxx b/src/modelling_utilities/mult_image_parameters.cxx index 263ca3ac3..b36e1ecab 100644 --- a/src/modelling_utilities/mult_image_parameters.cxx +++ b/src/modelling_utilities/mult_image_parameters.cxx @@ -17,14 +17,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" @@ -35,74 +35,70 @@ #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) - { - case 'i': - input_filename = optarg; - break; - case 'o': - output_filename = 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:p")) != -1) + switch (c) + { + case 'i': + input_filename = optarg; + break; + case 'o': + output_filename = 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) + if (output_filename == 0 || input_filename == 0) { - std::cerr << usage; - return EXIT_FAILURE; + 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) + for (int k = min_k_index; k <= max_k_index; ++k) { - const int min_j_index = output_image[k].get_min_index(); + 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 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; -} + 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/modelling_utilities/mult_model_with_dyn_images.cxx b/src/modelling_utilities/mult_model_with_dyn_images.cxx index 183c2cc57..caf6d4e42 100644 --- a/src/modelling_utilities/mult_model_with_dyn_images.cxx +++ b/src/modelling_utilities/mult_model_with_dyn_images.cxx @@ -16,14 +16,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. @@ -40,52 +40,52 @@ #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 (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; - } + { + 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 ; + if (patlak_plot.set_up() == Succeeded::no) + return EXIT_FAILURE; else - { - shared_ptr - par_image_sptr(ParametricVoxelsOnCartesianGrid::read_from_file(argv[1])); + { + 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; + 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); + // 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); + // 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 (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 58a0469f5..3d502613c 100644 --- a/src/modelling_utilities/write_patlak_matrix.cxx +++ b/src/modelling_utilities/write_patlak_matrix.cxx @@ -17,8 +17,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 @@ -32,37 +32,38 @@ #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 (argc == 2) { if (patlak_plot.parse(argv[1]) == false) - return EXIT_FAILURE; + return EXIT_FAILURE; } else patlak_plot.ask_parameters(); - if (patlak_plot.set_up()==Succeeded::no) + if (patlak_plot.set_up() == Succeeded::no) { std::cerr << "Usage:" << argv[0] << " [par_file] \n"; - return EXIT_FAILURE ; + 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")); + { + // 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 da3f136d0..a0e6ec7a8 100644 --- a/src/numerics_buildblock/determinant.cxx +++ b/src/numerics_buildblock/determinant.cxx @@ -11,9 +11,9 @@ /*! \file \ingroup numerics - + \brief Implementation of stir::determinant() function for matrices - + \author Kris Thielemans */ @@ -28,46 +28,39 @@ START_NAMESPACE_STIR 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) @@ -76,8 +69,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; } @@ -85,8 +77,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 5dd50a3cc..7b27fc11a 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 @@ -21,36 +21,38 @@ #include "stir/error.h" START_NAMESPACE_STIR - template -static void bitreversal(VectorWithOffset& data) +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]); - } - int m=n; - while (m >= 2 && j > m) { - j -= m; - m >>= 1; + 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; + while (m >= 2 && j > m) + { + j -= m; + m >>= 1; + } + j += m; } - j += m; - } } - // internal function to create vector of size pow2k with exparray[i] = exp(sign*i*_PI/pow2k) -static VectorWithOffset> get_exparray(const int pow2k, const int sign) +static VectorWithOffset> +get_exparray(const int pow2k, const int sign) { VectorWithOffset> a(pow2k); - for (int i=0; i< pow2k; ++i) - a[i]= std::exp(std::complex(0, static_cast((sign*i*_PI)/pow2k))); + for (int i = 0; i < pow2k; ++i) + a[i] = std::exp(std::complex(0, static_cast((sign * i * _PI) / pow2k))); return a; } - /* 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 @@ -59,51 +61,54 @@ static VectorWithOffset> get_exparray(const int pow2k, const */ template -void fourier_1d(T& c, const int sign) +void +fourier_1d(T& c, const int sign) { - if (c.size()==0) return; - assert(c.get_min_index()==0); - assert(sign==1 || sign ==-1); + 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) + { + const auto cur_exparray = get_exparray(pow2k, sign); + 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[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. + */ + c2 *= cur_exparray[i]; + c1 += c2; + c2 *= -1; + c2 += t1; + } + } } -namespace detail { +namespace detail +{ /* A class that does the recursion for multi-dimensional arrays. @@ -113,14 +118,11 @@ namespace detail { template struct fourier_auxiliary { - static void - do_fourier(VectorWithOffset& c, const int sign) + 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); } }; @@ -128,26 +130,21 @@ struct fourier_auxiliary // specialisation for the one-dimensional case template -struct fourier_auxiliary > +struct fourier_auxiliary> { - static void - do_fourier(VectorWithOffset >& c, const int sign) - { - fourier_1d(c, sign); - } + static void do_fourier(VectorWithOffset>& c, const int sign) { fourier_1d(c, sign); } }; } // end of namespace detail // now the fourier function is easy to define in terms of the class above template -void +void fourier(T& c, const int sign) { - detail::fourier_auxiliary::do_fourier(c,sign); + detail::fourier_auxiliary::do_fourier(c, sign); } - /****************************************************************** DFT of real data *****************************************************************/ @@ -155,72 +152,70 @@ fourier(T& c, const int sign) // specialisation for the one-dimensional case 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])); + 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[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). @@ -228,51 +223,47 @@ 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) + // 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])); + 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])); + 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[n - i] = std::conj(t1 - t2); } { - c[0]=complex_t((c[0].real() + c[n].real()), - (c[0].real() - c[n].real()) - ); + 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; + 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, T> +inverse_fourier_1d_for_real_data(const Array<1, std::complex>& c, const int sign) { - Array<1,std::complex > tmp(c); + Array<1, std::complex> tmp(c); return inverse_fourier_1d_for_real_data_corrupting_input(tmp, sign); } - // multi-dimensional case -namespace detail { +namespace detail +{ /* A class that does the recursion for multi-dimensional arrays. This is done with a class because partial template specialisation is @@ -281,158 +272,129 @@ namespace detail { template struct fourier_for_real_data_auxiliary { - static Array > - do_fourier_for_real_data(const Array& c, const int sign) + 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; } }; template -struct fourier_for_real_data_auxiliary<1,elemT> +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) + 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); + 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) + 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); + return inverse_fourier_1d_for_real_data_corrupting_input(c, sign); } }; } // 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) +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); + 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) +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); + 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 +inverse_fourier_for_real_data(const Array>& c, const int sign) { - Array > tmp(c); + 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; + 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)); + if (index[num_dimensions] > 0) + { + const BasicCoordinate related_index = modulo(sizes - index, sizes); + result[related_index] = std::conj(c[index]); + } + } 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 c12570cd0..1e759d643 100644 --- a/src/recon_buildblock/AnalyticReconstruction.cxx +++ b/src/recon_buildblock/AnalyticReconstruction.cxx @@ -1,25 +1,25 @@ /* 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 part of STIR. + SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license - + 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" @@ -34,35 +34,31 @@ START_NAMESPACE_STIR - - // parameters -void +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 +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 @@ -84,7 +80,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 @@ -95,7 +91,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", ""); @@ -104,42 +100,39 @@ void AnalyticReconstruction::ask_parameters() } #endif // ask_parameters disabled - -bool AnalyticReconstruction::post_processing() +bool +AnalyticReconstruction::post_processing() { - if (base_type::post_processing()) - return true; + 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 + { + 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 +DiscretisedDensity<3, float>* +AnalyticReconstruction::construct_target_image_ptr() const { - return - this->target_parameter_parser.create(this->get_input_data()); + 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()); @@ -153,17 +146,14 @@ reconstruct() 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); - } + { + 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 @@ -174,30 +164,29 @@ reconstruct(shared_ptr const& target_image_sptr) 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 (!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"); @@ -206,69 +195,68 @@ 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 579e72d80..7ea66e332 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 @@ -22,7 +22,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" @@ -34,34 +33,31 @@ #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) + : _already_set_up(false) { - set_defaults(); + set_defaults(); } 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"); @@ -69,54 +65,51 @@ initialise_keymap() } 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 +BackProjectorByBin::check(const ProjDataInfo& proj_data_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%") + 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()); } 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 { this->check(proj_data_info); - if (! this->_density_sptr->has_same_characteristics(density_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); @@ -124,37 +117,39 @@ const ProjData& proj_data, int subset_num, int num_subsets) } #ifdef STIR_PROJECTORS_AS_V3 void -BackProjectorByBin::back_project( DiscretisedDensity<3,float>& image, - const RelatedViewgrams& viewgrams) +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()); + 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) +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()); + 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) +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) + if (viewgrams.get_num_viewgrams() == 0) return; check(*viewgrams.get_proj_data_info_sptr(), density); @@ -163,32 +158,26 @@ 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) + 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); - // TODOTOF find_basic_view_segment_numbers doesn't fill in timing_pos_num - vs.timing_pos_num() = basic_vs.timing_pos_num(); - if (vs != basic_vs) - error("BackProjectorByBin::back_project called with incorrect related_viewgrams. Problem with symmetries!\n"); - } + ViewSegmentNumbers vs(iter->get_view_num(), iter->get_segment_num()); + get_symmetries_used()->find_basic_view_segment_numbers(vs); + // TODOTOF find_basic_view_segment_numbers doesn't fill in timing_pos_num + vs.timing_pos_num() = basic_vs.timing_pos_num(); + 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); } #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) @@ -198,76 +187,77 @@ BackProjectorByBin::back_project(const ProjData& proj_data, int subset_num, int 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 - #if _OPENMP <201107 - #pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(dynamic) - #else - // OpenMP loop over both vs_nums_to_process and tof_pos_num - #pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(dynamic) collapse(2) - #endif +# if _OPENMP < 201107 +# pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(dynamic) +# else +// OpenMP loop over both vs_nums_to_process and tof_pos_num +# pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(dynamic) collapse(2) +# endif #endif - // note: older versions of openmp need an int as loop - for (int i=0; i(vs_nums_to_process.size()); ++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) + // note: older versions of openmp need an int as loop + for (int i = 0; i < static_cast(vs_nums_to_process.size()); ++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) { - const ViewSegmentNumbers vs=vs_nums_to_process[i]; + const ViewSegmentNumbers vs = vs_nums_to_process[i]; #ifdef STIR_OPENMP - RelatedViewgrams viewgrams; -#pragma omp critical (BACKPROJECTORBYBIN_GETVIEWGRAMS) - viewgrams = proj_data.get_related_viewgrams(vs, symmetries_sptr, false, k); - info(boost::format("Processing view %1% of segment %2%, TOF bin %3%") % vs.view_num() % vs.segment_num() % k, 3); + RelatedViewgrams viewgrams; +# pragma omp critical(BACKPROJECTORBYBIN_GETVIEWGRAMS) + viewgrams = proj_data.get_related_viewgrams(vs, symmetries_sptr, false, k); + info(boost::format("Processing view %1% of segment %2%, TOF bin %3%") % vs.view_num() % vs.segment_num() % k, 3); #else - const RelatedViewgrams viewgrams = - proj_data.get_related_viewgrams(vs, symmetries_sptr, false, k); - info(boost::format("Processing view %1% of segment %2%, TOF bin %3%") % vs.view_num() % vs.segment_num() % k, 3); + const RelatedViewgrams viewgrams = proj_data.get_related_viewgrams(vs, symmetries_sptr, false, k); + info(boost::format("Processing view %1% of segment %2%, TOF bin %3%") % vs.view_num() % vs.segment_num() % k, 3); #endif - back_project(viewgrams); - } - } + back_project(viewgrams); + } + } } - 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()); + 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) +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()); + 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) +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) + if (viewgrams.get_num_viewgrams() == 0) return; if (!_density_sptr) @@ -276,8 +266,8 @@ back_project(const RelatedViewgrams& viewgrams, check(*viewgrams.get_proj_data_info_sptr()); #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 @@ -285,43 +275,34 @@ 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) + 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); - // TODOTOF find_basic_view_segment_numbers doesn't fill in timing_pos_num - vs.timing_pos_num() = basic_vs.timing_pos_num(); - if (vs != basic_vs) - error("BackProjectorByBin::back_project called with incorrect related_viewgrams. Problem with symmetries!\n"); - } + ViewSegmentNumbers vs(iter->get_view_num(), iter->get_segment_num()); + get_symmetries_used()->find_basic_view_segment_numbers(vs); + // TODOTOF find_basic_view_segment_numbers doesn't fill in timing_pos_num + vs.timing_pos_num() = basic_vs.timing_pos_num(); + 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); } void -BackProjectorByBin:: -start_accumulating_in_new_target() +BackProjectorByBin::start_accumulating_in_new_target() { - if (!this->_already_set_up) - error("BackProjectorByBin method called without calling set_up first."); + if (!this->_already_set_up) + error("BackProjectorByBin method called without calling set_up first."); #ifdef STIR_OPENMP - if (omp_get_num_threads()!=1) - error("BackProjectorByBin::start_accumulating_in_new_target cannot be called inside a thread"); + 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 + 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"); @@ -329,71 +310,68 @@ start_accumulating_in_new_target() } #endif - _density_sptr->fill(0.); + _density_sptr->fill(0.); } void -BackProjectorByBin:: -get_output(DiscretisedDensity<3,float> &density) const +BackProjectorByBin::get_output(DiscretisedDensity<3, float>& density) const { - if (!density.has_same_characteristics(*_density_sptr)) - error("Images should have similar characteristics."); + 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) +BackProjectorByBin::set_post_data_processor(shared_ptr>> post_data_processor_sptr) { - _post_data_processor_sptr = 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) +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."); + 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) +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; + 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 400fb7f40..005e9a134 100644 --- a/src/recon_buildblock/BackProjectorByBinUsingInterpolation.cxx +++ b/src/recon_buildblock/BackProjectorByBinUsingInterpolation.cxx @@ -19,7 +19,7 @@ \author Kris Thielemans \author Claire Labbe \author PARAPET project - + */ #include "stir/VoxelsOnCartesianGrid.h" @@ -42,25 +42,19 @@ 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; @@ -73,17 +67,15 @@ 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); @@ -94,28 +86,27 @@ 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; @@ -125,25 +116,25 @@ 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); - if (fabs(proj_data_info_ptr->get_phi(Bin(0,0,0,0)))>1.E-4F) + if (fabs(proj_data_info_ptr->get_phi(Bin(0, 0, 0, 0))) > 1.E-4F) error("BackProjectorByBinUsingInterpolation cannot handle non-zero view-offset. Sorry"); - 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"); @@ -151,107 +142,94 @@ 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 " "separation (%g)\n", - image_info_ptr->get_origin().z(), voxel_size.z()); + 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(); + 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); - } - - + { + 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); + } } 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 +BackProjectorByBinUsingInterpolation::clone() const { - return new BackProjectorByBinUsingInterpolation(*this); + 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()); - + const shared_ptr proj_data_info_cyl_sptr + = dynamic_pointer_cast(viewgrams.get_proj_data_info_sptr()); if (is_null_ptr(proj_data_info_cyl_sptr)) - { - error("\nBackProjectorByBinUsingInterpolation:\n" - "can only handle arc-corrected data (cast to ProjDataInfoCylindricalArcCorr)!\n"); - } + { + error("\nBackProjectorByBinUsingInterpolation:\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) + 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)); + 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); + 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 + 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; } @@ -261,199 +239,238 @@ actual_back_project(DiscretisedDensity<3,float>& density, 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(); + 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); - } + { + 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); - } - } + { + 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 if (zoomed_viewgrams_ptr->get_num_viewgrams() == 1) - error("BackProjectorByBinUsingInterpolation: back_project called with RelatedViewgrams with unexpect number of related viewgrams"); + error("BackProjectorByBinUsingInterpolation: back_project called with RelatedViewgrams with unexpect number of related " + "viewgrams"); - const Viewgram & pos_view = *r_viewgrams_iter;//0 + const Viewgram& pos_view = *r_viewgrams_iter; // 0 r_viewgrams_iter++; - const Viewgram & neg_view = *r_viewgrams_iter;//1 + 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); - } + { + 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); - - } + { + 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); + } } - } - void -BackProjectorByBinUsingInterpolation:: -actual_back_project(DiscretisedDensity<3,float>&, - const Bin&) +BackProjectorByBinUsingInterpolation::actual_back_project(DiscretisedDensity<3, float>&, const Bin&) { - error("BackProjectorByBinUsingInterpolation is not supported for list-mode reconstruction. Abort."); + error("BackProjectorByBinUsingInterpolation is not supported for list-mode reconstruction. Abort."); } - #if 0 /****************************************************************************** 2D @@ -571,266 +588,252 @@ 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 -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) +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) { - const shared_ptr proj_data_info_cyl_sptr = - dynamic_pointer_cast (pos_view.get_proj_data_info_sptr()); - + const shared_ptr proj_data_info_cyl_sptr + = dynamic_pointer_cast(pos_view.get_proj_data_info_sptr()); if (is_null_ptr(proj_data_info_cyl_sptr)) - { - error("\nBackProjectorByBinUsingInterpolation:\n\ + { + 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) + 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); 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,pos_view.get_timing_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++) + 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; + 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); - } + 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); + } } } /* 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()); + const shared_ptr proj_data_info_cyl_sptr + = dynamic_pointer_cast(pos_view.get_proj_data_info_sptr()); if (is_null_ptr(proj_data_info_cyl_sptr)) { @@ -838,171 +841,160 @@ back_project_view_plus_90_and_delta( 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); - - const int num_views = pos_view.get_proj_data_info_sptr()->get_num_views(); + 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() 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); 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,pos_view.get_timing_pos_num()); + 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++) + 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; - + 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); - } + 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); + } } } - END_NAMESPACE_STIR diff --git a/src/recon_buildblock/BackProjectorByBinUsingInterpolation_3DCho.cxx b/src/recon_buildblock/BackProjectorByBinUsingInterpolation_3DCho.cxx index e8be11b87..eb534183b 100644 --- a/src/recon_buildblock/BackProjectorByBinUsingInterpolation_3DCho.cxx +++ b/src/recon_buildblock/BackProjectorByBinUsingInterpolation_3DCho.cxx @@ -17,7 +17,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). @@ -32,16 +32,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'. @@ -51,10 +51,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' @@ -69,7 +69,6 @@ delta->-delta changes dz->1-dz, ds->ds */ - #include "stir/ProjDataInfo.h" #include "stir/VoxelsOnCartesianGrid.h" #include "stir/ProjDataInfoCylindricalArcCorr.h" @@ -88,62 +87,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. */ @@ -152,8 +151,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. @@ -165,51 +164,63 @@ 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 + 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) + 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) + 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); + 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 +#endif // BPINT_CHECK } /**************************************************************************** @@ -219,392 +230,400 @@ 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); + 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(); - + // 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) + 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 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 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 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 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 @@ -617,20 +636,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) @@ -641,428 +657,460 @@ 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 + do { assert(ds >= 0); assert(ds <= 1); assert(dz >= 0); - assert(dz <= ring_unit+epsilon); + 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 + // 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; - + const int Zplus = Z + 1; + const int Qmin = Q - 1; + #if PIECEWISE_INTERPOLATION - //KT&MJ 07/08/98 new + // 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; + 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 +# 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; + 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; - - // 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; - +# else // ALTERNATIVE + double TMP1, TMP2; + + // 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 + 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= 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 @@ -1073,47 +1121,56 @@ 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) + 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; @@ -1121,500 +1178,493 @@ Recompile %s with ALTERNATIVE not #defined", __FILE__); // 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 @@ -1627,20 +1677,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) @@ -1651,693 +1698,715 @@ 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 + do { assert(ds >= 0); assert(ds <= 1); assert(dz >= 0); - assert(dz <= ring_unit+epsilon); + 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; + // 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; - } - } - 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 (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; - } - } + 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 (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; + } + } #else // !PIECEWISE_INTERPOLATION -#ifdef ALTERNATIVE - const double dsdz=ds*dz; - const double dsdz2=ds*(dz+0.5); +# 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 (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; - } - } - #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; + 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 (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; + } + } +# 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 + 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= 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)); + A0a0 += DA0a0; + A1a0 += DA1a0; + A2a0 += DA2a0; + A3a0 += DA3a0; + A0na0 += DA0na0; + A1na0 += DA1na0; + A2na0 += DA2na0; + A3na0 += DA3na0; + P0a0 += DP0a0; + P1a0 += DP1a0; + P2a0 += DP2a0; + P3a0 += DP3a0; + P0na0 += DP0na0; + P1na0 += DP1na0; + P2na0 += DP2na0; + P3na0 += DP3na0; + + A0a1 += DA0a1; + A1a1 += DA1a1; + A2a1 += DA2a1; + A3a1 += DA3a1; + A0na1 += DA0na1; + A1na1 += DA1na1; + A2na1 += DA2na1; + A3na1 += DA3na1; + P0a1 += DP0a1; + P1a1 += DP1a1; + P2a1 += DP2a1; + P3a1 += DP3a1; + P0na1 += DP0na1; + P1na1 += DP1na1; + P2na1 += DP2na1; + P3na1 += DP3na1; +#endif // PIECEWISE_INTERPOLATION + } + 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) + 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 - // First compute X1, Y1 - // KT 16/06/98 added const - const double t = s + 0.5; /* In a beam, not on a ray */ + + // 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 */ // 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) @@ -2349,15 +2418,16 @@ 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) { @@ -2368,53 +2438,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; - // TODO possible problem for negative Z1f, use floor() instead - Z1 = (int) floor(Z1f); - - //Z2 = (int) Z2f; + 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); + + // 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 - // 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 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; // 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 @@ -2423,39 +2495,38 @@ 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) - { - 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) + { + 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 < epsilon) + { + Z1++; + // z+=1/num_planes_per_axial_pos; + dz += 1. / num_planes_per_axial_pos; + } } - } // TODO we could do a test of either Z or its Q lies in the axial FOV - // if not, go along the beam. This could save us some updates of the + // if not, go along the beam. This could save us some updates of the // incremental quantities. // KT&CL 22/12/99 changed ring_unit - dzvert=-delta*cphi/root/num_planes_per_axial_pos; /* Only valid if d_xy = d_p */ - dzhor=-delta*sphi/root/num_planes_per_axial_pos; + dzvert = -delta * cphi / root / num_planes_per_axial_pos; /* Only valid if d_xy = d_p */ + dzhor = -delta * sphi / root / num_planes_per_axial_pos; } return Succeeded::yes; diff --git a/src/recon_buildblock/BackProjectorByBinUsingInterpolation_linear.cxx b/src/recon_buildblock/BackProjectorByBinUsingInterpolation_linear.cxx index 9061e5979..22a47f13f 100644 --- a/src/recon_buildblock/BackProjectorByBinUsingInterpolation_linear.cxx +++ b/src/recon_buildblock/BackProjectorByBinUsingInterpolation_linear.cxx @@ -6,7 +6,7 @@ \ingroup projection \brief This file defines two private static functions from - stir::BackProjectorByBinUsingInterpolation, for the case of piecewise + stir::BackProjectorByBinUsingInterpolation, for the case of piecewise linear interpolation. \warning This \c \#includes BackProjectorByBinUsingInterpolation_3DCho.cxx diff --git a/src/recon_buildblock/BackProjectorByBinUsingInterpolation_piecewise_linear.cxx b/src/recon_buildblock/BackProjectorByBinUsingInterpolation_piecewise_linear.cxx index aa5ed32f4..55c9de59a 100644 --- a/src/recon_buildblock/BackProjectorByBinUsingInterpolation_piecewise_linear.cxx +++ b/src/recon_buildblock/BackProjectorByBinUsingInterpolation_piecewise_linear.cxx @@ -6,7 +6,7 @@ \ingroup projection \brief This file defines two private static functions from - stir::BackProjectorByBinUsingInterpolation, for the case of piecewise + stir::BackProjectorByBinUsingInterpolation, for the case of piecewise linear interpolation. \warning This \c \#includes BackProjectorByBinUsingInterpolation_3DCho.cxx diff --git a/src/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.cxx b/src/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.cxx index 15f4d7cf5..3655277ff 100644 --- a/src/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.cxx +++ b/src/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.cxx @@ -7,11 +7,11 @@ \ingroup projection \brief non-inline implementations for stir::BackProjectorByBinUsingProjMatrixByBin - + \author Mustapha Sadki \author Kris Thielemans \author PARAPET project - + */ /* Copyright (C) 2000 PARAPET partners @@ -25,9 +25,9 @@ */ /* History: 20/09/2001 KT - - added registry and parsing + - added registry and parsing 22/01/2002 KT - - used new implementation for actual_backproject that takes + - used new implementation for actual_backproject that takes symmetries into account for faster performance. Essentially copied from ForwardProjectorByBinUsingProjMatrixByBin */ @@ -42,22 +42,17 @@ using std::vector; START_NAMESPACE_STIR -const char * const -BackProjectorByBinUsingProjMatrixByBin::registered_name = - "Matrix"; - +const char* const BackProjectorByBinUsingProjMatrixByBin::registered_name = "Matrix"; void -BackProjectorByBinUsingProjMatrixByBin:: -set_defaults() +BackProjectorByBinUsingProjMatrixByBin::set_defaults() { this->proj_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"); @@ -65,31 +60,25 @@ initialise_keymap() BackProjectorByBin::initialise_keymap(); } - bool -BackProjectorByBinUsingProjMatrixByBin:: -post_processing() +BackProjectorByBinUsingProjMatrixByBin::post_processing() { - //if (BackProjectorByBin::post_processing() == true) - // return true; + // if (BackProjectorByBin::post_processing() == true) + // return true; if (is_null_ptr(proj_matrix_ptr)) - { - warning("BackProjectorByBinUsingProjMatrixByBin: matrix not set.\n"); - return true; - } + { + warning("BackProjectorByBinUsingProjMatrixByBin: matrix not set.\n"); + return true; + } return false; } -BackProjectorByBinUsingProjMatrixByBin:: -BackProjectorByBinUsingProjMatrixByBin() +BackProjectorByBinUsingProjMatrixByBin::BackProjectorByBinUsingProjMatrixByBin() { set_defaults(); } -BackProjectorByBinUsingProjMatrixByBin:: -BackProjectorByBinUsingProjMatrixByBin( - const shared_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)) @@ -97,16 +86,15 @@ BackProjectorByBinUsingProjMatrixByBin( } 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) { proj_matrix_ptr->set_up(proj_data_info_ptr, image_info_ptr); BackProjectorByBin::set_up(proj_data_info_ptr, image_info_ptr); } -const DataSymmetriesForViewSegmentNumbers * +const DataSymmetriesForViewSegmentNumbers* BackProjectorByBinUsingProjMatrixByBin::get_symmetries_used() const { if (!this->_already_set_up) @@ -114,134 +102,127 @@ BackProjectorByBinUsingProjMatrixByBin::get_symmetries_used() const 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 + // 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; - } - } + + 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(); + 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)); + 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 ( - auto 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))); - } + 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 (auto 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) +BackProjectorByBinUsingProjMatrixByBin::actual_back_project(DiscretisedDensity<3, float>& image, const Bin& bin) { ProjMatrixElemsForOneBin proj_matrix_row; proj_matrix_ptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, bin); @@ -249,12 +230,11 @@ actual_back_project(DiscretisedDensity<3,float>& image, } BackProjectorByBinUsingProjMatrixByBin* -BackProjectorByBinUsingProjMatrixByBin:: -clone() const +BackProjectorByBinUsingProjMatrixByBin::clone() const { - BackProjectorByBinUsingProjMatrixByBin* sptr(new BackProjectorByBinUsingProjMatrixByBin(*this)); - sptr->proj_matrix_ptr.reset(this->proj_matrix_ptr->clone()); - return sptr; + 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 91f79b37d..590b50722 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 @@ -22,7 +22,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/BackProjectorByBinUsingSquareProjMatrixByBin.h" #include "stir/Viewgram.h" #include "stir/RelatedViewgrams.h" @@ -33,30 +32,22 @@ 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 - ) +BackProjectorByBinUsingSquareProjMatrixByBin::BackProjectorByBinUsingSquareProjMatrixByBin( + const shared_ptr& proj_matrix_ptr) : proj_matrix_ptr(proj_matrix_ptr) - { - assert(!is_null_ptr(proj_matrix_ptr)); - - } +{ + assert(!is_null_ptr(proj_matrix_ptr)); +} -const DataSymmetriesForViewSegmentNumbers * +const DataSymmetriesForViewSegmentNumbers* BackProjectorByBinUsingSquareProjMatrixByBin::get_symmetries_used() const { if (!this->_already_set_up) @@ -64,77 +55,69 @@ BackProjectorByBinUsingSquareProjMatrixByBin::get_symmetries_used() const 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()) - { - 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_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; - } + 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_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; + } } void -BackProjectorByBinUsingSquareProjMatrixByBin:: -actual_back_project(DiscretisedDensity<3, float> &image, - const Bin& bin) +BackProjectorByBinUsingSquareProjMatrixByBin::actual_back_project(DiscretisedDensity<3, float>& image, const Bin& bin) { - error("BackProjectorByBinUsingSquareProjMatrixByBin is not supported for list-mode reconstruction. Abort."); + 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() +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 3f6919b9c..6d1f1de82 100644 --- a/src/recon_buildblock/BinNormalisation.cxx +++ b/src/recon_buildblock/BinNormalisation.cxx @@ -18,7 +18,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" @@ -32,204 +31,193 @@ START_NAMESPACE_STIR -BinNormalisation:: -BinNormalisation() - : _already_set_up(false) -{ -} +BinNormalisation::BinNormalisation() + : _already_set_up(false) +{} -void BinNormalisation::set_defaults() +void +BinNormalisation::set_defaults() { this->_already_set_up = false; } -BinNormalisation:: -~BinNormalisation() +BinNormalisation::~BinNormalisation() {} -void BinNormalisation:: -set_exam_info_sptr(const shared_ptr _exam_info_sptr) +void +BinNormalisation::set_exam_info_sptr(const shared_ptr _exam_info_sptr) { - this->exam_info_sptr=_exam_info_sptr; + this->exam_info_sptr = _exam_info_sptr; } -shared_ptr BinNormalisation:: -get_exam_info_sptr() const +shared_ptr +BinNormalisation::get_exam_info_sptr() const { - return this->exam_info_sptr; + return this->exam_info_sptr; } Succeeded -BinNormalisation:: -set_up(const shared_ptr& exam_info_sptr_v, const shared_ptr& proj_data_info_sptr_v ) +BinNormalisation::set_up(const shared_ptr& exam_info_sptr_v, + const shared_ptr& proj_data_info_sptr_v) { _already_set_up = true; this->proj_data_info_sptr = proj_data_info_sptr_v; this->exam_info_sptr = exam_info_sptr_v; - return Succeeded::yes; + 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%") + 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 +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()); + 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 +void +BinNormalisation::apply(RelatedViewgrams& viewgrams) 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,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)); - } + { + 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)); + } } -void -BinNormalisation:: -undo(RelatedViewgrams& viewgrams) const +void +BinNormalisation::undo(RelatedViewgrams& viewgrams) 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,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); - } - + { + 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); + } } -void -BinNormalisation:: -apply(ProjData& proj_data, - shared_ptr symmetries_sptr) const +void +BinNormalisation::apply(ProjData& proj_data, shared_ptr symmetries_sptr) const { 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(dynamic) +# pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(dynamic) #endif - // note: older versions of openmp need an int as loop - for (int i=0; i(vs_nums_to_process.size()); ++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; + 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) + // 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) #endif - { - viewgrams = - proj_data.get_related_viewgrams(vs, symmetries_sptr, false, k); - } + { + viewgrams = proj_data.get_related_viewgrams(vs, symmetries_sptr, false, k); + } - this->apply(viewgrams); + this->apply(viewgrams); #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, - shared_ptr symmetries_sptr) const +void +BinNormalisation::undo(ProjData& proj_data, shared_ptr symmetries_sptr) const { 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(dynamic) +# pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(dynamic) #endif - // note: older versions of openmp need an int as loop - for (int i=0; i(vs_nums_to_process.size()); ++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; + 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,false,k); - } + { + viewgrams = proj_data.get_related_viewgrams(vs, symmetries_sptr, false, k); + } - this->undo(viewgrams); + this->undo(viewgrams); #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 c98f414fd..b3354315c 100644 --- a/src/recon_buildblock/BinNormalisationFromAttenuationImage.cxx +++ b/src/recon_buildblock/BinNormalisationFromAttenuationImage.cxx @@ -31,12 +31,9 @@ START_NAMESPACE_STIR -const char * const -BinNormalisationFromAttenuationImage::registered_name = - "From Attenuation Image"; +const char* const BinNormalisationFromAttenuationImage::registered_name = "From Attenuation Image"; - -void +void BinNormalisationFromAttenuationImage::set_defaults() { base_type::set_defaults(); @@ -45,9 +42,8 @@ BinNormalisationFromAttenuationImage::set_defaults() attenuation_image_filename = ""; } -void -BinNormalisationFromAttenuationImage:: -initialise_keymap() +void +BinNormalisationFromAttenuationImage::initialise_keymap() { base_type::initialise_keymap(); parser.add_start_key("Bin Normalisation From Attenuation Image"); @@ -56,82 +52,77 @@ initialise_keymap() 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); + 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; - } + { + 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 base_type::post_processing(); } - -BinNormalisationFromAttenuationImage:: -BinNormalisationFromAttenuationImage() +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) { base_type::set_up(exam_info_sptr, proj_data_info_ptr); forward_projector_ptr->set_up(proj_data_info_ptr, attenuation_image_ptr); @@ -139,52 +130,46 @@ set_up(const shared_ptr &exam_info_sptr, const shared_ptr& viewgrams) const +void +BinNormalisationFromAttenuationImage::apply(RelatedViewgrams& viewgrams) 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(); + for (RelatedViewgrams::iterator viewgrams_iter = attenuation_viewgrams.begin(); viewgrams_iter != attenuation_viewgrams.end(); ++viewgrams_iter) - { - in_place_exp(*viewgrams_iter); - } + { + in_place_exp(*viewgrams_iter); + } viewgrams *= attenuation_viewgrams; } -void -BinNormalisationFromAttenuationImage:: -undo(RelatedViewgrams& viewgrams) const +void +BinNormalisationFromAttenuationImage::undo(RelatedViewgrams& viewgrams) 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(); + for (RelatedViewgrams::iterator viewgrams_iter = attenuation_viewgrams.begin(); viewgrams_iter != attenuation_viewgrams.end(); ++viewgrams_iter) - { - in_place_exp(*viewgrams_iter); - } + { + in_place_exp(*viewgrams_iter); + } viewgrams /= attenuation_viewgrams; } -float +float BinNormalisationFromAttenuationImage::get_bin_efficiency(const Bin& bin) const { - //TODO + // 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 b6f1321cb..9d1a91538 100644 --- a/src/recon_buildblock/BinNormalisationFromECAT7.cxx +++ b/src/recon_buildblock/BinNormalisationFromECAT7.cxx @@ -53,11 +53,7 @@ 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 { @@ -66,100 +62,82 @@ namespace detail // helper functions used in this class. // -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 ) ); +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)); } - - - -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 +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(), - uncomp_bin.tangential_pos_num()); + 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(), 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); - } - - assert((ring1_plus_ring2 + ring_diff)%2 == 0); - assert((ring1_plus_ring2 - ring_diff)%2 == 0); - + 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); + 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 +void BinNormalisationFromECAT7::set_defaults() { base_type::set_defaults(); @@ -167,12 +145,11 @@ BinNormalisationFromECAT7::set_defaults() 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() { base_type::initialise_keymap(); this->parser.add_start_key("Bin Normalisation From ECAT7"); @@ -187,9 +164,8 @@ initialise_keymap() this->parser.add_stop_key("End Bin Normalisation From ECAT7"); } -bool -BinNormalisationFromECAT7:: -post_processing() +bool +BinNormalisationFromECAT7::post_processing() { if (base_type::post_processing()) return true; @@ -198,188 +174,157 @@ post_processing() return false; } - -BinNormalisationFromECAT7:: -BinNormalisationFromECAT7() +BinNormalisationFromECAT7::BinNormalisationFromECAT7() { set_defaults(); } -BinNormalisationFromECAT7:: -BinNormalisationFromECAT7(const std::string& 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) { base_type::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) - { - warning("BinNormalisationFromECAT7 can only be used on non-arccorrected data\n"); - return Succeeded::no; - } - 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"); - return Succeeded::no; - } + 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) + { + warning("BinNormalisationFromECAT7: scanner object from proj data is different from the one " + "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) +BinNormalisationFromECAT7::read_norm_data(const std::string& filename) { - - MatrixFile* mptr = matrix_open(filename.c_str(), MAT_READ_ONLY, Norm3d); + + 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)); - 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 - efficiency_factors = - Array<2,float>(IndexRange2D(0,scanner_ptr->get_num_rings()-1, - 0, scanner_ptr->get_num_detectors_per_ring()-1)); - + 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 + efficiency_factors + = 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 */ @@ -389,7 +334,6 @@ read_norm_data(const std::string& filename) *iter++ = *trans_t1++; #endif - free_matrix_data(matrix); matrix_close(mptr); #if 0 @@ -443,41 +387,37 @@ read_norm_data(const std::string& filename) warning("BinNormalisationFromECAT7: dead-time code might give wrong results"); } -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_uncalibrated_bin_efficiency(const Bin& bin) const { - - const float start_time=get_exam_info_sptr()->get_time_frame_definitions().get_start_time(); - const float end_time=get_exam_info_sptr()->get_time_frame_definitions().get_end_time(); +float +BinNormalisationFromECAT7::get_uncalibrated_bin_efficiency(const Bin& bin) const +{ + + const float start_time = get_exam_info_sptr()->get_time_frame_definitions().get_start_time(); + const float end_time = get_exam_info_sptr()->get_time_frame_definitions().get_end_time(); // TODO disable when not HR+ or HR++ /* @@ -493,175 +433,153 @@ get_uncalibrated_bin_efficiency(const Bin& bin) const { */ 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); - - - - 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 - (which easily follows by plugging in ring1+ring2 and ring1-ring2). - 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 ) { - - - 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 - 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(check_bin == bin); -#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) * - get_dead_time_efficiency(pos2); - } - 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; + 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 + (which easily follows by plugging in ring1+ring2 and ring1-ring2). + 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) + { + + 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 + 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(check_bin == bin); +# 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) * get_dead_time_efficiency(pos2); + } + 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; + } + + 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_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 + /* 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; + total_efficiency += view_efficiency; } } return total_efficiency; } #endif - -float -BinNormalisationFromECAT7::get_dead_time_efficiency (const DetectionPosition<>& det_pos) const +float +BinNormalisationFromECAT7::get_dead_time_efficiency(const DetectionPosition<>& det_pos) const { - const float start_time=get_exam_info_sptr()->get_time_frame_definitions().get_start_time(); - const float end_time=get_exam_info_sptr()->get_time_frame_definitions().get_end_time(); - - if (is_null_ptr(singles_rates_ptr)) { - return 1; - } + const float start_time = get_exam_info_sptr()->get_time_frame_definitions().get_start_time(); + const float end_time = get_exam_info_sptr()->get_time_frame_definitions().get_end_time(); + + 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; + const float rate = singles_rates_ptr->get_singles_rate(det_pos, start_time, end_time) / num_blocks_per_singles_unit; // TODO KT is not sure if the rate (currently returned in s^-1) has the appropriate units for the equation below - 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 ); - + 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 0d3dd9eb3..fdf848f2c 100644 --- a/src/recon_buildblock/BinNormalisationFromECAT8.cxx +++ b/src/recon_buildblock/BinNormalisationFromECAT8.cxx @@ -26,7 +26,6 @@ \author Daniel Deidda */ - #include "stir/recon_buildblock/BinNormalisationFromECAT8.h" #include "stir/DetectionPosition.h" #include "stir/DetectionPositionPair.h" @@ -55,11 +54,7 @@ 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 { @@ -68,91 +63,75 @@ 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 +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(), - uncomp_bin.tangential_pos_num()); + 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(), 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); - } - - assert((ring1_plus_ring2 + ring_diff)%2 == 0); - assert((ring1_plus_ring2 - ring_diff)%2 == 0); - + 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); + 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 +void BinNormalisationFromECAT8::set_defaults() { base_type::set_defaults(); @@ -166,9 +145,8 @@ BinNormalisationFromECAT8::set_defaults() this->_write_components_to_file = false; } -void -BinNormalisationFromECAT8:: -initialise_keymap() +void +BinNormalisationFromECAT8::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Bin Normalisation From ECAT8"); @@ -178,7 +156,7 @@ 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_key("use_axial_effects_factors", &this->_use_axial_effects_factors); @@ -186,114 +164,101 @@ initialise_keymap() this->parser.add_stop_key("End Bin Normalisation From ECAT8"); } -bool -BinNormalisationFromECAT8:: -post_processing() +bool +BinNormalisationFromECAT8::post_processing() { if (base_type::post_processing()) return true; 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() +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) { base_type::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) - { - warning("BinNormalisationFromECAT8 can only be used on non-arccorrected data\n"); - return Succeeded::no; - } - 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"); - return Succeeded::no; - } + 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) + { + warning("BinNormalisationFromECAT8: scanner object from proj data is different from the one " + "from the normalisation file\n"); + return Succeeded::no; + } if (this->use_axial_effects_factors()) { - const int data_max_ring_diff = - proj_data_info_cyl_ptr->get_max_ring_difference(proj_data_info_cyl_ptr->get_max_segment_num()); - auto norm_proj_data_info_no_arccorr_ptr = - dynamic_cast(norm_proj_data_info_sptr.get()); - const int norm_max_ring_diff = - norm_proj_data_info_no_arccorr_ptr->get_max_ring_difference(norm_proj_data_info_no_arccorr_ptr->get_max_segment_num()); + const int data_max_ring_diff + = proj_data_info_cyl_ptr->get_max_ring_difference(proj_data_info_cyl_ptr->get_max_segment_num()); + auto norm_proj_data_info_no_arccorr_ptr + = dynamic_cast(norm_proj_data_info_sptr.get()); + const int norm_max_ring_diff = norm_proj_data_info_no_arccorr_ptr->get_max_ring_difference( + norm_proj_data_info_no_arccorr_ptr->get_max_segment_num()); if (data_max_ring_diff > norm_max_ring_diff) warning("ECAT8 norm axial effects given only for ring diff up to " + std::to_string(norm_max_ring_diff) + ". I will use 1 for larger ring difference."); } - this->mash = scanner_ptr->get_num_detectors_per_ring()/2/proj_data_info_ptr->get_num_views(); + this->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) { - + InterfileNormHeaderSiemens norm_parser; norm_parser.parse(filename.c_str()); - this->norm_proj_data_info_sptr = norm_parser.data_info_ptr; + this->norm_proj_data_info_sptr = norm_parser.data_info_ptr; this->scanner_ptr = norm_parser.data_info_ptr->get_scanner_sptr(); - 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, norm_parser.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, norm_parser.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 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; - + 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) @@ -305,47 +270,45 @@ read_norm_data(const string& filename) "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))); this->construct_sino_lookup_table(); /* 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)); - 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 - efficiency_factors = - Array<2,float>(IndexRange2D(0,scanner_ptr->get_num_rings()-1, - 0, scanner_ptr->get_num_detectors_per_ring()-1)); + 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 + efficiency_factors + = Array<2, float>(IndexRange2D(0, scanner_ptr->get_num_rings() - 1, 0, scanner_ptr->get_num_detectors_per_ring() - 1)); - axial_effects = - Array<1,float>(num_Siemens_sinograms); + axial_effects = Array<1, float>(num_Siemens_sinograms); std::ifstream binary_data; open_read_binary(binary_data, full_data_file_name); @@ -365,50 +328,50 @@ read_norm_data(const string& filename) error("failed reading axial_effects_factors from '%s'", full_data_file_name); 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 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; 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) + 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) + 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; + efficiency_factors[r][c + inc] = 0.F; } } - if (scanner_ptr->get_num_virtual_axial_crystals_per_block()>0) + 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) + 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); + efficiency_factors[r + inc].fill(0.F); } } } - // TODO mvoe dead-time stuff to a separate function + // TODO mvoe dead-time stuff to a separate function #if 0 /* Set up equation parameters for dead_time correction */ float *axial_t1 = nrm_subheader_ptr->ring_dtcor1 ; /* 'Paralyzing dead_times' for each axial Xstal */ @@ -428,61 +391,58 @@ read_norm_data(const string& filename) 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 (this->_write_components_to_file) { // to test pipe the obtained values into file - ofstream out_geom, out_axial; - 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); - out_axial.open("axial_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; - } + ofstream out_geom, out_axial; + 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); + out_axial.open("axial_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 = 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 = 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 = axial_effects.get_min_index(); i<=axial_effects.get_max_index();i++) - { - out_axial << axial_effects[i] << " " << 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 = axial_effects.get_min_index(); i <= axial_effects.get_max_index(); i++) + { + out_axial << axial_effects[i] << " " << std::endl; + } } #if 0 @@ -492,215 +452,193 @@ read_norm_data(const string& filename) #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_axial_effects_factors() const +BinNormalisationFromECAT8::use_axial_effects_factors() const { return this->_use_axial_effects_factors; } -bool -BinNormalisationFromECAT8:: -use_crystal_interference_factors() const +bool +BinNormalisationFromECAT8::use_crystal_interference_factors() const { return this->_use_crystal_interference_factors; } -float -BinNormalisationFromECAT8:: -get_uncalibrated_bin_efficiency(const Bin& bin) const { - - float total_efficiency = 0 ; - +float +BinNormalisationFromECAT8::get_uncalibrated_bin_efficiency(const Bin& bin) const +{ + + 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); - - - //const DetectionPosition<>& pos1 = detection_position_pair.pos1(); - //const DetectionPosition<>& pos2 = detection_position_pair.pos2(); - 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 - (which easily follows by plugging in ring1+ring2 and ring1-ring2). - 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 ) { - - - 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; - } + detail::set_detection_tangential_coords(proj_data_info_cyl_uncompressed_ptr, uncompressed_bin, detection_position_pair); + + // const DetectionPosition<>& pos1 = detection_position_pair.pos1(); + // const DetectionPosition<>& pos2 = detection_position_pair.pos2(); + 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 + (which easily follows by plugging in ring1+ring2 and ring1-ring2). + 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) + { + 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 - 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(check_bin == bin); + 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(check_bin == bin); #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()) - { - if (get_exam_info_sptr()->get_time_frame_definitions().get_num_time_frames() == 0) - error("BinNormalisationFromECAT8: projection_data needs to have timing information to compute dead-time"); - const float start_time=get_exam_info_sptr()->get_time_frame_definitions().get_start_time(); - const float end_time=get_exam_info_sptr()->get_time_frame_definitions().get_end_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 *= - geometric_factors[geo_plane_num][uncompressed_bin.tangential_pos_num()]; - } - if (this->use_axial_effects_factors()) + + 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()) + { + if (get_exam_info_sptr()->get_time_frame_definitions().get_num_time_frames() == 0) + error("BinNormalisationFromECAT8: projection_data needs to have timing information to compute dead-time"); + const float start_time = get_exam_info_sptr()->get_time_frame_definitions().get_start_time(); + const float end_time = get_exam_info_sptr()->get_time_frame_definitions().get_end_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 *= geometric_factors[geo_plane_num][uncompressed_bin.tangential_pos_num()]; + } + if (this->use_axial_effects_factors()) + { + // Need to divide here + lor_efficiency_this_pair /= find_axial_effects(pos1.axial_coord(), pos2.axial_coord()); + } + lor_efficiency += lor_efficiency_this_pair; + } + + if (this->use_crystal_interference_factors()) { - // Need to divide here - lor_efficiency_this_pair /= - find_axial_effects(pos1.axial_coord(), pos2.axial_coord()); + 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; } - 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; - } - - total_efficiency += view_efficiency; - } + total_efficiency += view_efficiency; + } } return total_efficiency; } void -BinNormalisationFromECAT8:: -construct_sino_lookup_table() +BinNormalisationFromECAT8::construct_sino_lookup_table() { const int num_rings = this->scanner_ptr->get_num_rings(); - this->sino_index=Array<2,int>(IndexRange2D(0, num_rings-1, - 0, num_rings-1)); + this->sino_index = Array<2, int>(IndexRange2D(0, num_rings - 1, 0, num_rings - 1)); // fill with invalid index such that we can detect out-of-range // see find_axial_effects this->sino_index.fill(-1); - auto proj_data_info_no_arccorr_ptr = - dynamic_cast(norm_proj_data_info_sptr.get()); + auto proj_data_info_no_arccorr_ptr = dynamic_cast(norm_proj_data_info_sptr.get()); if (!proj_data_info_no_arccorr_ptr) error("BinNormalisationFromECAT8: internal error. Data should be of type ProjDataInfoCylindricalNoArcCorr"); this->num_Siemens_sinograms = proj_data_info_no_arccorr_ptr->get_num_non_tof_sinograms(); - + const auto segment_sequence = ecat::find_segment_sequence(*proj_data_info_no_arccorr_ptr); Bin bin; - bin.tangential_pos_num()=0; - bin.view_num()=0; - std::vector > det_pos_pairs; - for (int Siemens_sino_index=0; Siemens_sino_index< this->num_Siemens_sinograms; ++Siemens_sino_index) + bin.tangential_pos_num() = 0; + bin.view_num() = 0; + std::vector> det_pos_pairs; + for (int Siemens_sino_index = 0; Siemens_sino_index < this->num_Siemens_sinograms; ++Siemens_sino_index) { - int z=Siemens_sino_index; + int z = Siemens_sino_index; - for (std::size_t i=0; iget_num_axial_poss(bin.segment_num()); - if (z< num_ax_poss) + if (z < num_ax_poss) { bin.axial_pos_num() = z; proj_data_info_no_arccorr_ptr->get_all_det_pos_pairs_for_bin(det_pos_pairs, bin); - for (auto iter=det_pos_pairs.begin();iter!=det_pos_pairs.end(); ++iter) + for (auto iter = det_pos_pairs.begin(); iter != det_pos_pairs.end(); ++iter) { sino_index[iter->pos1().axial_coord()][iter->pos2().axial_coord()] = Siemens_sino_index; - //sino_index[iter->pos2().axial_coord()][iter->pos1().axial_coord()] = Siemens_sino_index; + // sino_index[iter->pos2().axial_coord()][iter->pos1().axial_coord()] = Siemens_sino_index; } break; } @@ -713,40 +651,33 @@ construct_sino_lookup_table() } float -BinNormalisationFromECAT8:: -find_axial_effects(int ring1, int ring2) const +BinNormalisationFromECAT8::find_axial_effects(int ring1, int ring2) const { const int Siemens_sino_index = sino_index[ring1][ring2]; - if (Siemens_sino_index<0) + if (Siemens_sino_index < 0) return 1.F; else return axial_effects[Siemens_sino_index]; } - -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; - } + 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 429768db2..e8f38850c 100644 --- a/src/recon_buildblock/BinNormalisationFromGEHDF5.cxx +++ b/src/recon_buildblock/BinNormalisationFromGEHDF5.cxx @@ -25,7 +25,6 @@ \author Palak Wadhwa */ - #include "stir/recon_buildblock/BinNormalisationFromGEHDF5.h" #include "stir/DetectionPosition.h" #include "stir/DetectionPositionPair.h" @@ -54,14 +53,12 @@ using std::fstream; using std::ios; START_NAMESPACE_STIR -namespace GE { -namespace RDF_HDF5 { - - - -const char * const -BinNormalisationFromGEHDF5::registered_name = "From GE HDF5"; +namespace GE +{ +namespace RDF_HDF5 +{ +const char* const BinNormalisationFromGEHDF5::registered_name = "From GE HDF5"; namespace detail { @@ -70,106 +67,94 @@ 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 +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(), - uncomp_bin.tangential_pos_num()); + 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(), 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); - } - - assert((ring1_plus_ring2 + ring_diff)%2 == 0); - assert((ring1_plus_ring2 - ring_diff)%2 == 0); - + 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); + 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 +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 +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 +// 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; @@ -180,240 +165,231 @@ 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]; + { + 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; + 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 +void BinNormalisationFromGEHDF5::set_defaults() { base_type::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() { base_type::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() { if (base_type::post_processing()) return true; 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() +BinNormalisationFromGEHDF5::BinNormalisationFromGEHDF5() { set_defaults(); } -BinNormalisationFromGEHDF5:: -BinNormalisationFromGEHDF5(const string& 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) { base_type::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) - { - warning("BinNormalisationFromGEHDF5 can only be used on non-arccorrected data\n"); - return Succeeded::no; - } - 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"); - return Succeeded::no; - } - - mash = scanner_ptr->get_num_detectors_per_ring()/2/proj_data_info_ptr->get_num_views(); + 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) + { + warning("BinNormalisationFromGEHDF5: scanner object from proj data is different from the one " + "from the normalisation file\n"); + return Succeeded::no; + } + + 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()) - { - // 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. - 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); - 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;} ); - } + 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. + 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); + 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; }); + } // // 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 bounds 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, - /* tof_mash_factor */ 0 - ); - 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) + if (this->use_geometric_factors()) { - 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 (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. + // Construct a proper ProjDataInfo to initialize geometry factors array and use it to know the bounds 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, + /* tof_mash_factor */ 0); + 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 (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)); @@ -423,42 +399,38 @@ 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 -{ - - const float start_time=get_exam_info_sptr()->get_time_frame_definitions().get_start_time(); - const float end_time=get_exam_info_sptr()->get_time_frame_definitions().get_end_time(); - float total_efficiency = 0 ; +float +BinNormalisationFromGEHDF5::get_uncalibrated_bin_efficiency(const Bin& bin) const +{ + + const float start_time = get_exam_info_sptr()->get_time_frame_definitions().get_start_time(); + const float end_time = get_exam_info_sptr()->get_time_frame_definitions().get_end_time(); + 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,123 +439,117 @@ get_uncalibrated_bin_efficiency(const Bin& bin) const ... } */ - + /* 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.; - - /* - 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 - (which easily follows by plugging in ring1+ring2 and ring1-ring2). - - 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 ) + for (uncompressed_bin.view_num() = start_view; uncompressed_bin.view_num() < end_view; ++uncompressed_bin.view_num()) { - // 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. - float lor_efficiency_this_pair = 1.F; - if (this->use_detector_efficiencies()) - { - lor_efficiency_this_pair *= get_efficiency_factors(detection_position_pair); - } - 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()) - { - lor_efficiency_this_pair *= get_geometric_efficiency_factors(detection_position_pair); - } - lor_efficiency += lor_efficiency_this_pair; - }//endfor - - view_efficiency += lor_efficiency; - total_efficiency += view_efficiency; - } + 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 + (which easily follows by plugging in ring1+ring2 and ring1-ring2). + + 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) + { + // Ring numbers out of range. + continue; + } + + // 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()) + { + lor_efficiency_this_pair *= get_efficiency_factors(detection_position_pair); + } + 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()) + { + lor_efficiency_this_pair *= get_geometric_efficiency_factors(detection_position_pair); + } + lor_efficiency += lor_efficiency_this_pair; + } // endfor + + view_efficiency += lor_efficiency; + total_efficiency += view_efficiency; + } 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; - } + 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 +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()]); + 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()]); } -} // namespace -} +} // namespace RDF_HDF5 +} // namespace GE END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/BinNormalisationFromProjData.cxx b/src/recon_buildblock/BinNormalisationFromProjData.cxx index bb5dd985b..30e9f57cc 100644 --- a/src/recon_buildblock/BinNormalisationFromProjData.cxx +++ b/src/recon_buildblock/BinNormalisationFromProjData.cxx @@ -30,20 +30,17 @@ START_NAMESPACE_STIR -const char * const -BinNormalisationFromProjData::registered_name = "From ProjData"; +const char* const BinNormalisationFromProjData::registered_name = "From ProjData"; - -void +void BinNormalisationFromProjData::set_defaults() { base_type::set_defaults(); normalisation_projdata_filename = ""; } -void -BinNormalisationFromProjData:: -initialise_keymap() +void +BinNormalisationFromProjData::initialise_keymap() { base_type::initialise_keymap(); parser.add_start_key("Bin Normalisation From ProjData"); @@ -51,9 +48,8 @@ initialise_keymap() parser.add_stop_key("End Bin Normalisation From ProjData"); } -bool -BinNormalisationFromProjData:: -post_processing() +bool +BinNormalisationFromProjData::post_processing() { if (base_type::post_processing()) return true; @@ -61,25 +57,22 @@ post_processing() return false; } -BinNormalisationFromProjData:: -BinNormalisationFromProjData() +BinNormalisationFromProjData::BinNormalisationFromProjData() { set_defaults(); } -BinNormalisationFromProjData:: -BinNormalisationFromProjData(const std::string& 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) +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_sptr) +Succeeded +BinNormalisationFromProjData::set_up(const shared_ptr& exam_info_sptr, + const shared_ptr& proj_data_info_sptr) { if (!base_type::set_up(exam_info_sptr, proj_data_info_sptr).succeeded()) return Succeeded::no; @@ -95,72 +88,64 @@ set_up(const shared_ptr& exam_info_sptr, const shared_ptr= 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); - } - if (ok) - return Succeeded::yes; - else - { - warning(boost::format("BinNormalisationFromProjData: incompatible projection data:\nNorm projdata info:\n%s\nEmission projdata info (made non-TOF if norm is non-TOF):\n%s\n--- (end of incompatible projection data info)---\n") - % norm_proj.parameter_info() - % proj.parameter_info()); - return Succeeded::no; - } - } + { + // Check if the emission data is "smaller" than the norm data (e.g. fewer segments) + // We will require equal tangential_pos ranges as `apply()` currently needs that. + 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); + } + if (ok) + return Succeeded::yes; + else + { + warning(boost::format( + "BinNormalisationFromProjData: incompatible projection data:\nNorm projdata info:\n%s\nEmission projdata " + "info (made non-TOF if norm is non-TOF):\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 +bool +BinNormalisationFromProjData::is_trivial() const { return false; } -void -BinNormalisationFromProjData::apply(RelatedViewgrams& viewgrams) 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 - { - 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 +void +BinNormalisationFromProjData::apply(RelatedViewgrams& viewgrams) 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 +{ + 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 { - //TODO + // TODO error("BinNormalisationFromProjData::get_bin_efficiency is not implemented"); return 1; - } shared_ptr @@ -168,5 +153,5 @@ BinNormalisationFromProjData::get_norm_proj_data_sptr() const { return this->norm_proj_data_ptr; } - + END_NAMESPACE_STIR diff --git a/src/recon_buildblock/BinNormalisationPETFromComponents.cxx b/src/recon_buildblock/BinNormalisationPETFromComponents.cxx index 7159272c2..f07d50552 100644 --- a/src/recon_buildblock/BinNormalisationPETFromComponents.cxx +++ b/src/recon_buildblock/BinNormalisationPETFromComponents.cxx @@ -43,7 +43,10 @@ BinNormalisationPETFromComponents::set_defaults() this->block_data = BlockData3D(); } -BinNormalisationPETFromComponents::BinNormalisationPETFromComponents() { set_defaults(); } +BinNormalisationPETFromComponents::BinNormalisationPETFromComponents() +{ + set_defaults(); +} bool BinNormalisationPETFromComponents::has_crystal_efficiencies() const @@ -94,11 +97,11 @@ BinNormalisationPETFromComponents::set_up(const shared_ptr& exam } } - this->_is_trivial = - (!has_crystal_efficiencies() - || (fabs(efficiencies.find_min() - 1) <= .0001 && fabs(efficiencies.find_max() - 1) <= .0001)) - && (!has_geometric_factors() || (fabs(geo_data.find_min() - 1) <= .0001 && fabs(geo_data.find_max() - 1) <= .0001)) - && (!has_block_factors() || (fabs(block_data.find_min() - 1) <= .0001 && fabs(block_data.find_max() - 1) <= .0001)); + this->_is_trivial + = (!has_crystal_efficiencies() + || (fabs(efficiencies.find_min() - 1) <= .0001 && fabs(efficiencies.find_max() - 1) <= .0001)) + && (!has_geometric_factors() || (fabs(geo_data.find_min() - 1) <= .0001 && fabs(geo_data.find_max() - 1) <= .0001)) + && (!has_block_factors() || (fabs(block_data.find_min() - 1) <= .0001 && fabs(block_data.find_max() - 1) <= .0001)); this->create_proj_data(); return Succeeded::yes; @@ -113,8 +116,8 @@ BinNormalisationPETFromComponents::is_trivial() const } void -BinNormalisationPETFromComponents::allocate(shared_ptr pdi_sptr, bool do_eff, bool do_geo, bool do_block, - bool do_symmetry_per_block) +BinNormalisationPETFromComponents::allocate( + shared_ptr pdi_sptr, bool do_eff, bool do_geo, bool do_block, bool do_symmetry_per_block) { this->proj_data_info_sptr = pdi_sptr; @@ -150,8 +153,10 @@ BinNormalisationPETFromComponents::allocate(shared_ptr pdi_s } if (do_geo) - this->geo_data = GeoData3D(num_physical_axial_crystals_per_basic_unit, num_physical_transaxial_crystals_per_basic_unit / 2, - num_physical_rings, num_physical_detectors_per_ring); + this->geo_data = GeoData3D(num_physical_axial_crystals_per_basic_unit, + num_physical_transaxial_crystals_per_basic_unit / 2, + num_physical_rings, + num_physical_detectors_per_ring); else this->geo_data.recycle(); diff --git a/src/recon_buildblock/BinNormalisationSPECT.cxx b/src/recon_buildblock/BinNormalisationSPECT.cxx index 2fd171393..43971d715 100644 --- a/src/recon_buildblock/BinNormalisationSPECT.cxx +++ b/src/recon_buildblock/BinNormalisationSPECT.cxx @@ -43,17 +43,13 @@ 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 +void BinNormalisationSPECT::set_defaults() { base_type::set_defaults(); @@ -62,15 +58,13 @@ BinNormalisationSPECT::set_defaults() this->_use_dead_time = false; this->_use_uniformity_factors = false; this->num_detector_heads = 3; - this->half_life = -1; //seconds - this->resampled=0; - this->measured_calibration_factor=-1.F; - + this->half_life = -1; // seconds + this->resampled = 0; + this->measured_calibration_factor = -1.F; } -void -BinNormalisationSPECT:: -initialise_keymap() +void +BinNormalisationSPECT::initialise_keymap() { base_type::initialise_keymap(); this->parser.add_start_key("Bin Normalisation SPECT"); @@ -78,7 +72,7 @@ initialise_keymap() 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("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("num detector heads", &this->num_detector_heads); this->parser.add_key("projdata filename", &this->projdata_filename); this->parser.add_key("use decay correction", &this->_use_decay_correction); @@ -87,313 +81,312 @@ initialise_keymap() this->parser.add_stop_key("End Bin Normalisation SPECT"); } -bool -BinNormalisationSPECT:: -post_processing() +bool +BinNormalisationSPECT::post_processing() { if (base_type::post_processing()) return true; - 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); - set_exam_info_sptr(norm_proj_data_info_ptr->get_exam_info_sptr()); - max_tang=norm_proj_data_info_ptr->get_max_tangential_pos_num(); - - if (this->get_exam_info_sptr()->get_time_frame_definitions().get_num_frames()>1) - error("BinNormalisationSPECT: Multiple time frames not yet supported"); - - if (this->get_exam_info_sptr()->get_time_frame_definitions().get_num_frames()==0) - error("BinNormalisationSPECT: At least one time frame should be defined"); - -// 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()); - - if (use_decay_correction_factors() && get_exam_info_sptr()->get_radionuclide().get_half_life()>0){ - half_life=get_exam_info_sptr()->get_radionuclide().get_half_life(); - info("BinNormalisationSPECT: half life = "+ std::to_string(half_life)); - } - + 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); + set_exam_info_sptr(norm_proj_data_info_ptr->get_exam_info_sptr()); + max_tang = norm_proj_data_info_ptr->get_max_tangential_pos_num(); + + if (this->get_exam_info_sptr()->get_time_frame_definitions().get_num_frames() > 1) + error("BinNormalisationSPECT: Multiple time frames not yet supported"); + + if (this->get_exam_info_sptr()->get_time_frame_definitions().get_num_frames() == 0) + error("BinNormalisationSPECT: At least one time frame should be defined"); + + // 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()); + + if (use_decay_correction_factors() && get_exam_info_sptr()->get_radionuclide().get_half_life() > 0) + { + half_life = get_exam_info_sptr()->get_radionuclide().get_half_life(); + info("BinNormalisationSPECT: half life = " + std::to_string(half_life)); + } + return false; } - -BinNormalisationSPECT:: -BinNormalisationSPECT() +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) { - - set_num_views(norm_proj_data_info_ptr->get_num_views()); - - this->view_time_interval=get_exam_info_sptr()->get_time_frame_definitions().get_duration(1)/num_views*num_detector_heads; - + + set_num_views(norm_proj_data_info_ptr->get_num_views()); + + this->view_time_interval = get_exam_info_sptr()->get_time_frame_definitions().get_duration(1) / num_views * num_detector_heads; + return base_type::set_up(exam_info_sptr, proj_data_info_ptr_v); } -BinNormalisationSPECT:: -BinNormalisationSPECT(const std::string& 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 { - int zoom=1024/(2*(max_tang+1)); - double normalisation=1; +float +BinNormalisationSPECT::get_uncalibrated_bin_efficiency(const Bin& bin) 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(uniformity, - max_tang, - zoom); + resample_uniformity(uniformity, max_tang, zoom); } - 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 #########################################*/ + 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)); - if (use_decay_correction_factors()){ - normalisation= - normalisation/decay_correction_factor(half_life, rel_time); - } - -return normalisation; + /*#################################################################################################### + *#################################### 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); + } + + return normalisation; } -void BinNormalisationSPECT::apply(RelatedViewgrams& viewgrams) const{ +void +BinNormalisationSPECT::apply(RelatedViewgrams& viewgrams) const +{ - -// const float start_time=get_exam_info_sptr()->get_time_frame_definitions().get_start_time(); - 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; + // const float start_time=get_exam_info_sptr()->get_time_frame_definitions().get_start_time(); + 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(uniformity, - max_tang, - zoom); + resample_uniformity(uniformity, max_tang, zoom); } - int head_num=(int)view_num/(num_views/num_detector_heads); + 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)); + 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) + 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()){ + 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]; - } + 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))* - normalisation); - normalisation=1; - } + 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)) * normalisation); + normalisation = 1; + } } } -void BinNormalisationSPECT::undo(RelatedViewgrams& viewgrams) const{ +void +BinNormalisationSPECT::undo(RelatedViewgrams& viewgrams) 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(uniformity, - max_tang, - zoom); -} + resample_uniformity(uniformity, max_tang, zoom); + } - int head_num=(int)view_num/(num_views/num_detector_heads); + 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)); + 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) + 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()){ - if(half_life<0) - error("BinNormalisationSPECT: decay correction cannot be applied as halflife was not set," - " or radionuclide is missing from radionuclideDB.json."); - normalisation= - normalisation/decay_correction_factor(half_life, rel_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()) + { + + /*#################################################################################################### + *#################################### 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 #########################################*/ - (*iter)[bin.axial_pos_num()][bin.tangential_pos_num()]*= - (this->get_uncalibrated_bin_efficiency(bin)*normalisation); - normalisation=1; + if (use_decay_correction_factors()) + { + if (half_life < 0) + error("BinNormalisationSPECT: decay correction cannot be applied as halflife was not set," + " or radionuclide is missing from radionuclideDB.json."); + normalisation = normalisation / decay_correction_factor(half_life, rel_time); + } - } + (*iter)[bin.axial_pos_num()][bin.tangential_pos_num()] + *= (this->get_uncalibrated_bin_efficiency(bin) * normalisation); + normalisation = 1; + } } } void -BinNormalisationSPECT:: -read_uniformity_table(Array<3,float>& uniformity) const +BinNormalisationSPECT::read_uniformity_table(Array<3, float>& uniformity) const { - 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]; - } - } + 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]; + } + } } void -BinNormalisationSPECT:: -resample_uniformity(Array<3,float> uniformity, - const int max_tang, - const int zoom) const +BinNormalisationSPECT::resample_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); + 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); + } } } } } -} -resampled=1; -//set_uniformity(down_sampled_uniformity); + resampled = 1; + // set_uniformity(down_sampled_uniformity); } -bool -BinNormalisationSPECT:: -use_detector_efficiencies() const +bool +BinNormalisationSPECT::use_detector_efficiencies() const { return this->_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 7e9163ae1..b1cd03c78 100644 --- a/src/recon_buildblock/BinNormalisationWithCalibration.cxx +++ b/src/recon_buildblock/BinNormalisationWithCalibration.cxx @@ -19,7 +19,6 @@ \author Kris Thielemans */ - #include "stir/recon_buildblock/BinNormalisationWithCalibration.h" #include "stir/Succeeded.h" #include "stir/warning.h" @@ -27,33 +26,29 @@ START_NAMESPACE_STIR -void +void BinNormalisationWithCalibration::set_defaults() { base_type::set_defaults(); - + this->calibration_factor = 1; } -void -BinNormalisationWithCalibration:: -initialise_keymap() +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);*/ + 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() +BinNormalisationWithCalibration::BinNormalisationWithCalibration() { set_defaults(); } @@ -65,14 +60,12 @@ BinNormalisationWithCalibration::set_up(const shared_ptr& exam_i if (this->calibration_factor == 1.F) warning("BinNormalisationWithCalibration:: calibration factor not set. I will use 1, but your data will not be calibrated."); - this->_calib_decay_branching_ratio = this->calibration_factor* this->get_branching_ratio(); //TODO: multiply by decay + this->_calib_decay_branching_ratio = this->calibration_factor * this->get_branching_ratio(); // TODO: multiply by decay return base_type::set_up(exam_info_sptr, proj_data_info_sptr); } - -float -BinNormalisationWithCalibration:: -get_calib_decay_branching_ratio_factor(const Bin&) const +float +BinNormalisationWithCalibration::get_calib_decay_branching_ratio_factor(const Bin&) const { if (!this->_already_set_up) error("BinNormalisationWithCalibration needs to be set-up first"); @@ -80,38 +73,34 @@ get_calib_decay_branching_ratio_factor(const Bin&) const } 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) +BinNormalisationWithCalibration::set_calibration_factor(const float calib) { this->_already_set_up = false; - this->calibration_factor=calib; + this->calibration_factor = calib; } float -BinNormalisationWithCalibration:: -get_branching_ratio() const +BinNormalisationWithCalibration::get_branching_ratio() const { float branching_ratio = this->radionuclide.get_branching_ratio(false); // get value without check - if (branching_ratio <=0) + if (branching_ratio <= 0) { warning("BinNormalisationWithCalibration: radionuclide branching_ratio not known. I will use 1."); return 1.F; } - return branching_ratio; + return branching_ratio; } - void -BinNormalisationWithCalibration:: -set_radionuclide(const Radionuclide &rnuclide){ - this->radionuclide=rnuclide; +BinNormalisationWithCalibration::set_radionuclide(const Radionuclide& rnuclide) +{ + this->radionuclide = rnuclide; } - END_NAMESPACE_STIR diff --git a/src/recon_buildblock/ChainedBinNormalisation.cxx b/src/recon_buildblock/ChainedBinNormalisation.cxx index d078bfd7a..cff71e743 100644 --- a/src/recon_buildblock/ChainedBinNormalisation.cxx +++ b/src/recon_buildblock/ChainedBinNormalisation.cxx @@ -17,7 +17,6 @@ \author Kris Thielemans */ - #include "stir/recon_buildblock/ChainedBinNormalisation.h" #include "stir/is_null_ptr.h" #include "stir/Succeeded.h" @@ -25,10 +24,9 @@ START_NAMESPACE_STIR -const char * const -ChainedBinNormalisation::registered_name = "Chained"; +const char* const ChainedBinNormalisation::registered_name = "Chained"; -void +void ChainedBinNormalisation::set_defaults() { base_type::set_defaults(); @@ -36,58 +34,53 @@ ChainedBinNormalisation::set_defaults() apply_second.reset(); } -void -ChainedBinNormalisation:: -initialise_keymap() +void +ChainedBinNormalisation::initialise_keymap() { base_type::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() +bool +ChainedBinNormalisation::post_processing() { - if ((apply_first->get_calibration_factor()>0.F) && (apply_second->get_calibration_factor()>0.F)) + 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 base_type::post_processing(); } - -ChainedBinNormalisation:: -ChainedBinNormalisation() +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) +ChainedBinNormalisation::set_up(const shared_ptr& exam_info_sptr, + const shared_ptr& proj_data_info_ptr) { - base_type::set_up( exam_info_sptr,proj_data_info_ptr); + base_type::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 +void +ChainedBinNormalisation::apply(RelatedViewgrams& viewgrams) const { if (!is_null_ptr(apply_first)) apply_first->apply(viewgrams); @@ -132,9 +125,8 @@ ChainedBinNormalisation::apply_only_second(ProjData& proj_data) const apply_second->apply(proj_data); } -void -ChainedBinNormalisation:: -undo(RelatedViewgrams& viewgrams) const +void +ChainedBinNormalisation::undo(RelatedViewgrams& viewgrams) const { if (!is_null_ptr(apply_first)) apply_first->undo(viewgrams); @@ -155,81 +147,70 @@ undo(ProjData& proj_data) const #endif void -ChainedBinNormalisation:: -undo_only_first(RelatedViewgrams& viewgrams) const +ChainedBinNormalisation::undo_only_first(RelatedViewgrams& viewgrams) const { if (!is_null_ptr(apply_first)) apply_first->undo(viewgrams); } void -ChainedBinNormalisation:: -undo_only_first(ProjData& proj_data) const +ChainedBinNormalisation::undo_only_first(ProjData& proj_data) const { if (!is_null_ptr(apply_first)) apply_first->undo(proj_data); } void -ChainedBinNormalisation:: -undo_only_second(RelatedViewgrams& viewgrams) const +ChainedBinNormalisation::undo_only_second(RelatedViewgrams& viewgrams) const { if (!is_null_ptr(apply_second)) apply_second->undo(viewgrams); } void -ChainedBinNormalisation:: -undo_only_second(ProjData& proj_data) const +ChainedBinNormalisation::undo_only_second(ProjData& proj_data) const { if (!is_null_ptr(apply_second)) apply_second->undo(proj_data); } float -ChainedBinNormalisation:: get_bin_efficiency(const Bin& bin) const -{ - return - (!is_null_ptr(apply_first) - ? apply_first->get_bin_efficiency(bin) - : 1) - * - (!is_null_ptr(apply_second) - ? apply_second->get_bin_efficiency(bin) - : 1); -} - +ChainedBinNormalisation::get_bin_efficiency(const Bin& bin) const +{ + return (!is_null_ptr(apply_first) ? apply_first->get_bin_efficiency(bin) : 1) + * (!is_null_ptr(apply_second) ? apply_second->get_bin_efficiency(bin) : 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(); + 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(); + 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; + 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; + 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 f27f89eef..f99395a5e 100644 --- a/src/recon_buildblock/DataSymmetriesForBins.cxx +++ b/src/recon_buildblock/DataSymmetriesForBins.cxx @@ -31,28 +31,22 @@ 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 @@ -63,17 +57,15 @@ DataSymmetriesForBins::num_related_bins(const Bin& b) const } /*! default implementation in terms of find_symmetry_operation_from_basic_bin */ -bool DataSymmetriesForBins::find_basic_bin(Bin& b) const +bool +DataSymmetriesForBins::find_basic_bin(Bin& b) const { - unique_ptr sym_op = - find_symmetry_operation_from_basic_bin(b); + 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); @@ -81,11 +73,14 @@ is_basic(const Bin& b) const /*! 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 int min_timing_pos_num, const int max_timing_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; @@ -95,9 +90,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())); @@ -106,42 +100,42 @@ 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) - { - for ( + 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) - { - for (int k=min_timing_pos_num;k<=max_timing_pos_num;++k) + 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],k)); + 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 +DataSymmetriesForBins::find_symmetry_operation_from_basic_view_segment_numbers(ViewSegmentNumbers& vs) const { - Bin bin(vs.segment_num(), vs.view_num(),0,0); + 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 827231954..4a919a989 100644 --- a/src/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.cxx +++ b/src/recon_buildblock/DataSymmetriesForBins_PET_CartesianGrid.cxx @@ -45,16 +45,16 @@ 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 +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(); @@ -63,59 +63,57 @@ 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; - - 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) + + 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); - - } - - 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; - } + } + + 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; + } } #if 0 // disabled as currently the same as ProjDataInfoGeneric @@ -231,322 +229,281 @@ find_relation_between_coordinate_systems(int& num_planes_per_scanner_ring, } #endif -/*! 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) +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) { - auto subset_proj_data_info_ptr = dynamic_cast(proj_data_info_ptr.get()); - if(!is_null_ptr(subset_proj_data_info_ptr)) + auto subset_proj_data_info_ptr = dynamic_cast(proj_data_info_ptr.get()); + if (!is_null_ptr(subset_proj_data_info_ptr)) { // special handling of subset case // will for now just switch view syms off - if(is_null_ptr(dynamic_cast(subset_proj_data_info_ptr->get_original_proj_data_info_sptr().get()))) + if (is_null_ptr( + dynamic_cast(subset_proj_data_info_ptr->get_original_proj_data_info_sptr().get()))) error("DataSymmetriesForBins_PET_CartesianGrid constructed with wrong type of original (non-subset) ProjDataInfo: %s\n" "(can only handle projection data corresponding to a cylinder)\n", typeid(*subset_proj_data_info_ptr->get_original_proj_data_info_sptr()).name()); - - if (do_symmetry_90degrees_min_phi || do_symmetry_180degrees_min_phi) { - warning("Turning off 90 and 180 degrees minus phi symmetries for subsets."); - } + + if (do_symmetry_90degrees_min_phi || do_symmetry_180degrees_min_phi) + { + warning("Turning off 90 and 180 degrees minus phi symmetries for subsets."); + } do_symmetry_90degrees_min_phi = false; - do_symmetry_180degrees_min_phi = false; + do_symmetry_180degrees_min_phi = false; } - auto pdi_cyl_ptr = dynamic_cast(subset_proj_data_info_ptr ? - subset_proj_data_info_ptr->get_original_proj_data_info_sptr().get() : - proj_data_info_ptr.get()); + auto pdi_cyl_ptr = dynamic_cast( + subset_proj_data_info_ptr ? subset_proj_data_info_ptr->get_original_proj_data_info_sptr().get() : proj_data_info_ptr.get()); initialise_deltas(pdi_cyl_ptr); - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="Cylindrical") + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "Cylindrical") { - if(dynamic_cast(pdi_cyl_ptr) == NULL) + if (dynamic_cast(pdi_cyl_ptr) == NULL) error("DataSymmetriesForBins_PET_CartesianGrid constructed with wrong type of ProjDataInfo: %s\n" "(can only handle projection data corresponding to a cylinder)\n", typeid(*pdi_cyl_ptr).name()); - 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()); - - // 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]; - // 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 " - "z-direction of the origin (which is %g) should be a multiple of the plane " - "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) - do_symmetry_90degrees_min_phi = false; - - num_views= proj_data_info_ptr->get_num_views(); - - if (num_views%4!=0) - do_symmetry_90degrees_min_phi = false; - - 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) - 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) - 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"); - - //PW Disabling some symmetries due to phi offset. - if (fabs(proj_data_info_ptr->get_phi(Bin(0,0,0,0)))>1.E-4F && - (this->do_symmetry_90degrees_min_phi|| this->do_symmetry_180degrees_min_phi)) - { - warning("Disabling symmetries as image is rotated due to phi offset of the scanner."); - this->do_symmetry_90degrees_min_phi = false; - this->do_symmetry_180degrees_min_phi = false; - } - - //RT Disabling some symmetries due to tof data - if (proj_data_info_ptr->is_tof_data()) - { - if (this->do_symmetry_90degrees_min_phi|| this->do_symmetry_180degrees_min_phi){ - warning("Disabling rotational symmetries with TOF data as this is untested."); - this->do_symmetry_90degrees_min_phi = false; - this->do_symmetry_180degrees_min_phi = false; - } + const DiscretisedDensityOnCartesianGrid<3, float>* cartesian_grid_info_ptr + = dynamic_cast*>(image_info_ptr.get()); - if (this->do_symmetry_swap_segment){ - warning("Disabling segment swapping with TOF data as this is untested."); - this->do_symmetry_swap_segment = false; - } + 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()); - if (this->do_symmetry_swap_s){ - warning("Disabling swap s with TOF data as this is untested."); - this->do_symmetry_swap_s = false; + // 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]; + // 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 " + "z-direction of the origin (which is %g) should be a multiple of the plane " + "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) + do_symmetry_90degrees_min_phi = false; + + num_views = proj_data_info_ptr->get_num_views(); + + if (num_views % 4 != 0) + do_symmetry_90degrees_min_phi = false; + + 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) + 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) + 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"); + + // PW Disabling some symmetries due to phi offset. + if (fabs(proj_data_info_ptr->get_phi(Bin(0, 0, 0, 0))) > 1.E-4F + && (this->do_symmetry_90degrees_min_phi || this->do_symmetry_180degrees_min_phi)) + { + warning("Disabling symmetries as image is rotated due to phi offset of the scanner."); + this->do_symmetry_90degrees_min_phi = false; + this->do_symmetry_180degrees_min_phi = false; + } + + // RT Disabling some symmetries due to tof data + if (proj_data_info_ptr->is_tof_data()) + { + if (this->do_symmetry_90degrees_min_phi || this->do_symmetry_180degrees_min_phi) + { + warning("Disabling rotational symmetries with TOF data as this is untested."); + this->do_symmetry_90degrees_min_phi = false; + this->do_symmetry_180degrees_min_phi = false; + } + + if (this->do_symmetry_swap_segment) + { + warning("Disabling segment swapping with TOF data as this is untested."); + this->do_symmetry_swap_segment = false; + } + + if (this->do_symmetry_swap_s) + { + warning("Disabling swap s with TOF data as this is untested."); + this->do_symmetry_swap_s = false; + } + } + + 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, pdi_cyl_ptr, cartesian_grid_info_ptr); } - } - - if (fabs(image_info_ptr->get_origin().x())>.01F || fabs(image_info_ptr->get_origin().y())>.01F) + // Block implementation + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "BlocksOnCylindrical") { - // 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, - pdi_cyl_ptr, - cartesian_grid_info_ptr); - } - //Block implementation - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="BlocksOnCylindrical") - { - if (dynamic_cast(pdi_cyl_ptr) == NULL) - error("DataSymmetriesForBins_PET_CartesianGrid constructed with wrong type of ProjDataInfo: %s\n" - "(can only handle projection data corresponding to blocks on a cylinder)\n", - typeid(*pdi_cyl_ptr).name()); - - const DiscretisedDensityOnCartesianGrid<3,float> * - cartesian_grid_info_ptr = - dynamic_cast *> - (image_info_ptr.get()); - - if (cartesian_grid_info_ptr == NULL) - error("DataSymmetriesForBins_PET_CartesianGrid constructed with wrong type of image info: %s\n", - typeid(*image_info_ptr).name()); - - // WARNING get_grid_spacing()[1] == z - //note: origin by default is (0,0,0) - 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 " - "z-direction of the origin (which is %g) should be a multiple of the plane " - "separation (%g)\n", - image_info_ptr->get_origin().z(), cartesian_grid_info_ptr->get_grid_spacing()[1]); - - 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 all symmetries except for symmtery_z since they are not implemented in block geometry yet."); - this->do_symmetry_90degrees_min_phi = - this->do_symmetry_180degrees_min_phi = - this->do_symmetry_swap_segment = - this->do_symmetry_swap_s = - this->do_symmetry_shift_z=false; - } - if (!dynamic_cast(pdi_cyl_ptr)->axial_sampling_is_uniform()) - { - this->do_symmetry_shift_z = false; - this->do_symmetry_swap_segment = false; - } - - // TODOBLOCK. should probably not call next function for non-uniform sampling - find_relation_between_coordinate_systems( - num_planes_per_scanner_ring, - num_planes_per_axial_pos, - axial_pos_to_z_offset, - pdi_cyl_ptr, - cartesian_grid_info_ptr); - } - // generic implementation - if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry()=="Generic") - { - if (dynamic_cast(pdi_cyl_ptr) == NULL) + if (dynamic_cast(pdi_cyl_ptr) == NULL) error("DataSymmetriesForBins_PET_CartesianGrid constructed with wrong type of ProjDataInfo: %s\n" - "(can only handle projection data corresponding to a generig geometry)\n", - typeid(*pdi_cyl_ptr).name()); + "(can only handle projection data corresponding to blocks on a cylinder)\n", + typeid(*pdi_cyl_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) + if (cartesian_grid_info_ptr == NULL) 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]; - // z_origin_in_planes should be an integer - if (fabs(round(z_origin_in_planes) - z_origin_in_planes) > 1.E-3F) + // WARNING get_grid_spacing()[1] == z + // note: origin by default is (0,0,0) + 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 " - "z-direction of the origin (which is %g) should be a multiple of the plane " - "separation (%g)\n", - image_info_ptr->get_origin().z(), cartesian_grid_info_ptr->get_grid_spacing()[1]); - - if (this->do_symmetry_90degrees_min_phi|| - this->do_symmetry_180degrees_min_phi|| - this->do_symmetry_swap_segment|| - this->do_symmetry_swap_s|| - this->do_symmetry_shift_z) - { - warning("Disabling all symmetries since they are not implemented in generic geometry."); - this->do_symmetry_90degrees_min_phi = - this->do_symmetry_180degrees_min_phi = - this->do_symmetry_swap_segment = - this->do_symmetry_swap_s = - this->do_symmetry_shift_z = false; + "z-direction of the origin (which is %g) should be a multiple of the plane " + "separation (%g)\n", + image_info_ptr->get_origin().z(), + cartesian_grid_info_ptr->get_grid_spacing()[1]); + + 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 all symmetries except for symmtery_z since they are not implemented in block geometry yet."); + this->do_symmetry_90degrees_min_phi = this->do_symmetry_180degrees_min_phi = this->do_symmetry_swap_segment + = this->do_symmetry_swap_s = this->do_symmetry_shift_z = false; + } + if (!dynamic_cast(pdi_cyl_ptr)->axial_sampling_is_uniform()) + { + this->do_symmetry_shift_z = false; + this->do_symmetry_swap_segment = false; + } + + // TODOBLOCK. should probably not call next function for non-uniform sampling + find_relation_between_coordinate_systems( + num_planes_per_scanner_ring, num_planes_per_axial_pos, axial_pos_to_z_offset, pdi_cyl_ptr, cartesian_grid_info_ptr); } + // generic implementation + if (proj_data_info_ptr->get_scanner_ptr()->get_scanner_geometry() == "Generic") + { + if (dynamic_cast(pdi_cyl_ptr) == NULL) + error("DataSymmetriesForBins_PET_CartesianGrid constructed with wrong type of ProjDataInfo: %s\n" + "(can only handle projection data corresponding to a generig geometry)\n", + typeid(*pdi_cyl_ptr).name()); - if (!dynamic_cast(pdi_cyl_ptr)->axial_sampling_is_uniform()) - { - this->do_symmetry_shift_z = false; - this->do_symmetry_swap_segment = false; - } + const DiscretisedDensityOnCartesianGrid<3, float>* cartesian_grid_info_ptr + = dynamic_cast*>(image_info_ptr.get()); - // TODOBLOCK. should probably not call next function for non-uniform sampling - find_relation_between_coordinate_systems( - num_planes_per_scanner_ring, - num_planes_per_axial_pos, - axial_pos_to_z_offset, - pdi_cyl_ptr, - cartesian_grid_info_ptr); + if (cartesian_grid_info_ptr == NULL) + error("DataSymmetriesForBins_PET_CartesianGrid constructed with wrong type of image info: %s\n", + 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]; + // 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 " + "z-direction of the origin (which is %g) should be a multiple of the plane " + "separation (%g)\n", + image_info_ptr->get_origin().z(), + cartesian_grid_info_ptr->get_grid_spacing()[1]); + + if (this->do_symmetry_90degrees_min_phi || this->do_symmetry_180degrees_min_phi || this->do_symmetry_swap_segment + || this->do_symmetry_swap_s || this->do_symmetry_shift_z) + { + warning("Disabling all symmetries since they are not implemented in generic geometry."); + this->do_symmetry_90degrees_min_phi = this->do_symmetry_180degrees_min_phi = this->do_symmetry_swap_segment + = this->do_symmetry_swap_s = this->do_symmetry_shift_z = false; + } + + if (!dynamic_cast(pdi_cyl_ptr)->axial_sampling_is_uniform()) + { + this->do_symmetry_shift_z = false; + this->do_symmetry_swap_segment = false; + } + + // TODOBLOCK. should probably not call next function for non-uniform sampling + find_relation_between_coordinate_systems( + num_planes_per_scanner_ring, num_planes_per_axial_pos, axial_pos_to_z_offset, pdi_cyl_ptr, cartesian_grid_info_ptr); } } -void DataSymmetriesForBins_PET_CartesianGrid::initialise_deltas(const ProjDataInfoCylindrical * pdi_ptr) +void +DataSymmetriesForBins_PET_CartesianGrid::initialise_deltas(const ProjDataInfoCylindrical* pdi_ptr) { this->deltas.resize(pdi_ptr->get_min_segment_num(), pdi_ptr->get_max_segment_num()); - for (int segment_num=pdi_ptr->get_min_segment_num(); segment_num <= pdi_ptr->get_max_segment_num(); ++segment_num) + for (int segment_num = pdi_ptr->get_min_segment_num(); segment_num <= pdi_ptr->get_max_segment_num(); ++segment_num) { this->deltas[segment_num] = pdi_ptr->get_average_ring_difference(segment_num); } } #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 +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)); + 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 c0a5497ab..655172980 100644 --- a/src/recon_buildblock/DataSymmetriesForDensels.cxx +++ b/src/recon_buildblock/DataSymmetriesForDensels.cxx @@ -31,32 +31,26 @@ 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); } @@ -70,12 +64,11 @@ DataSymmetriesForDensels::num_related_densels(const Densel& b) const } /*! default implementation in terms of find_symmetry_operation_from_basic_densel */ -bool DataSymmetriesForDensels::find_basic_densel(Densel& b) const +bool +DataSymmetriesForDensels::find_basic_densel(Densel& b) const { - unique_ptr sym_op = - find_symmetry_operation_from_basic_densel(b); + 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 23ce8fbf5..b6b78cde3 100644 --- a/src/recon_buildblock/DistributedCachingInformation.cxx +++ b/src/recon_buildblock/DistributedCachingInformation.cxx @@ -15,11 +15,10 @@ \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" #include "stir/error.h" @@ -27,107 +26,117 @@ START_NAMESPACE_STIR DistributedCachingInformation::DistributedCachingInformation(const int num_workers_v) - : num_workers(num_workers_v) + : num_workers(num_workers_v) { initialise(); } - 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) +void +DistributedCachingInformation::initialise_new_subiteration(const std::vector& vs_nums_to_process_v) { - this->vs_nums_to_process= 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 +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()) + 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 +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()) + 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) +void +DistributedCachingInformation::set_processed(const ViewSegmentNumbers& vs_num) { - this->still_to_process[this->find_vs_num_position_in_list_to_process(vs_num)]=false; + 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 +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()) + 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) + 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)) + if (this->is_still_to_be_processed(*iter)) cnt++; } return cnt; } -bool DistributedCachingInformation::get_oldest_unprocessed_vs_num(ViewSegmentNumbers& vs, int proc) const +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)) + // 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; + 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) @@ -136,42 +145,43 @@ bool DistributedCachingInformation::get_unprocessed_vs_num(ViewSegmentNumbers& v // 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; +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++) + // find processor with most work left + for (int i = 0; i < this->num_workers; i++) { - if (i==proc) continue; + if (i == proc) + continue; const int cnt = this->get_num_remaining_cached_data_to_process(i); - if (cnt>max_work) + if (cnt > max_work) { - max_work=cnt; + max_work = cnt; proc_with_max_work = i; - } + } } ViewSegmentNumbers vs; - //get vs_number of the processor with most work left - if (max_work>0) + // 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 + // 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 139f8ce8e..9f45cc180 100644 --- a/src/recon_buildblock/DistributedWorker.cxx +++ b/src/recon_buildblock/DistributedWorker.cxx @@ -14,7 +14,7 @@ \brief Implementation of stir::DistributedWorker() - \author Tobias Beisel + \author Tobias Beisel \author Kris Thielemans \author Alexey Zverovich (idea of using main() function) */ @@ -40,59 +40,57 @@ #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 +#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*/ + // 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) + + 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 { - 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: + // create Slave Object + stir::DistributedWorker> worker; + + // start Slave Process: worker.start(); return_value = EXIT_SUCCESS; - } + } #endif - } catch (std::string& error_string) { @@ -111,113 +109,110 @@ int main(int argc, char **argv) return return_value; } - -namespace stir +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() - { - } - 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) - { +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; - } + { + return; + } - case task_setup_distributable_computation: - { - this->setup_distributable_computation(); - break; - } + 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_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; + */ + 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; - /* - 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; - #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 @@ -229,208 +224,217 @@ 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 { - 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); + this->log_likelihood_ptr = 0; } -#endif - - HighResWallClockTimer t; - + + // 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)) { - 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) + 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 { - // 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); - } + // 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); + } - //receive info if mult_viewgrams_ptr are NULL - const bool mult_viewgrams=distributed::receive_bool_value(BINWISE_MULT_TAG, 0); - if (mult_viewgrams) + // 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) { - distributed::receive_and_construct_related_viewgrams(mult_viewgrams_ptr, proj_data_info_sptr, symmetries_sptr, 0); + 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); } - // 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 (mult_viewgrams) { - 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); - } + 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 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; } - 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; + 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) - stir::info(boost::format("Slave %1% used %2% seconds for PRC-processing.") - % my_rank % distributed::total_rpc_time_2); - } + { + 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 76e53ebb8..140de1191 100644 --- a/src/recon_buildblock/FilterRootPrior.cxx +++ b/src/recon_buildblock/FilterRootPrior.cxx @@ -11,10 +11,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" @@ -33,82 +33,77 @@ 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 -bool FilterRootPrior:: -is_convex() const +bool +FilterRootPrior::is_convex() const { return false; } -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 +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;} +{ + 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); + 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) +FilterRootPrior::compute_value(const DataT& current_estimate) { - static bool first_time=true; + static bool first_time = true; if (first_time) { warning("FilterRootPrior:compute_value does not make sense. Just returning 0."); - first_time=false; + first_time = false; } return 0.; } template -void -FilterRootPrior:: -compute_gradient(DataT& prior_gradient, - const DataT ¤t_image_estimate) +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; - } + 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'. @@ -117,41 +112,35 @@ 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); - ++iter_through_prior_gradient; - ++iter_through_current_image_estimate; - } + 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 +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() @@ -162,7 +151,7 @@ FilterRootPrior::set_defaults() template Succeeded -FilterRootPrior::set_up (shared_ptr const& target_sptr) +FilterRootPrior::set_up(shared_ptr const& target_sptr) { base_type::set_up(target_sptr); @@ -170,26 +159,23 @@ FilterRootPrior::set_up (shared_ptr const& target_sptr) } 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 0d8f437f0..2482a5387 100644 --- a/src/recon_buildblock/ForwardProjectorByBin.cxx +++ b/src/recon_buildblock/ForwardProjectorByBin.cxx @@ -42,27 +42,23 @@ START_NAMESPACE_STIR - ForwardProjectorByBin::ForwardProjectorByBin() - : _already_set_up(false) + : _already_set_up(false) { set_defaults(); } 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"); @@ -70,9 +66,8 @@ initialise_keymap() } 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(); @@ -80,66 +75,66 @@ set_up(const shared_ptr& proj_data_info_sptr, } void -ForwardProjectorByBin:: -check(const ProjDataInfo& proj_data_info) const +ForwardProjectorByBin::check(const ProjDataInfo& proj_data_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%") + 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()); } 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 { this->check(proj_data_info); - if (! this->_density_sptr->has_same_characteristics(density_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) +ForwardProjectorByBin::forward_project(RelatedViewgrams& viewgrams, const DiscretisedDensity<3, float>& image) { - forward_project(viewgrams, 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()); + 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) +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()); + 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) +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) + if (viewgrams.get_num_viewgrams() == 0) return; check(*viewgrams.get_proj_data_info_sptr(), density); @@ -147,27 +142,22 @@ 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()) - error("ForwardProjectByBin: forward_project called with incorrect related_viewgrams (wrong number). Problem with symmetries!"); + if (get_symmetries_used()->num_related_view_segment_numbers(basic_vs) != viewgrams.get_num_viewgrams()) + error("ForwardProjectByBin: forward_project called with incorrect related_viewgrams (wrong number). Problem with " + "symmetries!"); - for (RelatedViewgrams::const_iterator iter = viewgrams.begin(); - iter != viewgrams.end(); - ++iter) + 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); - // TODOTOF find_basic_view_segment_numbers doesn't fill in timing_pos_num - vs.timing_pos_num() = basic_vs.timing_pos_num(); - if (vs != basic_vs) - error("ForwardProjectByBin: forward_project called with incorrect related_viewgrams. Problem with symmetries!\n"); - } + get_symmetries_used()->find_basic_view_segment_numbers(vs); + // TODOTOF find_basic_view_segment_numbers doesn't fill in timing_pos_num + vs.timing_pos_num() = basic_vs.timing_pos_num(); + 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 @@ -175,62 +165,60 @@ 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) +ForwardProjectorByBin::forward_project(ProjData& proj_data, int subset_num, int num_subsets, bool zero) { if (!_density_sptr) error("You need to call set_input() forward_project()"); - 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); + 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()); - - 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); + 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); #ifdef STIR_OPENMP - #if _OPENMP <201107 - #pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(dynamic) - #else - // OpenMP loop over both vs_nums_to_process and tof_pos_num - #pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(dynamic) collapse(2) - #endif +# if _OPENMP < 201107 +# pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(dynamic) +# else +// OpenMP loop over both vs_nums_to_process and tof_pos_num +# pragma omp parallel for shared(proj_data, symmetries_sptr) schedule(dynamic) collapse(2) +# endif #endif - // note: older versions of openmp need an int as loop - for (int i=0; i(vs_nums_to_process.size()); ++i) + // note: older versions of openmp need an int as loop + for (int i = 0; i < static_cast(vs_nums_to_process.size()); ++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) + 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) { - const ViewSegmentNumbers vs=vs_nums_to_process[i]; + const ViewSegmentNumbers vs = vs_nums_to_process[i]; 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, 3); - else + else info(boost::format("Processing view %1% of segment %2%") % vs.view_num() % vs.segment_num(), 3); - RelatedViewgrams viewgrams = - proj_data.get_empty_related_viewgrams(vs, symmetries_sptr, false, k); + 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)) @@ -238,7 +226,6 @@ ForwardProjectorByBin::forward_project(ProjData& proj_data, } } } - } void @@ -246,30 +233,31 @@ 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()); + 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) +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()); + 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) +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) + if (viewgrams.get_num_viewgrams() == 0) return; if (!_density_sptr) error("You need to call set_input() forward_project()"); @@ -280,70 +268,58 @@ 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) + 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); - // TODOTOF find_basic_view_segment_numbers doesn't fill in timing_pos_num - vs.timing_pos_num() = basic_vs.timing_pos_num(); - if (vs != basic_vs) - error("ForwardProjectByBin: forward_project called with incorrect related_viewgrams. Problem with symmetries!\n"); - } + ViewSegmentNumbers vs(iter->get_view_num(), iter->get_segment_num()); + get_symmetries_used()->find_basic_view_segment_numbers(vs); + // TODOTOF find_basic_view_segment_numbers doesn't fill in timing_pos_num + vs.timing_pos_num() = basic_vs.timing_pos_num(); + 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); } void -ForwardProjectorByBin:: -actual_forward_project(RelatedViewgrams&, - const DiscretisedDensity<3,float>&, - const int, const int, - const int, const int) +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."); + 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) +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); + 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) +ForwardProjectorByBin::set_input(const DiscretisedDensity<3, float>& density) { - _density_sptr.reset(density.clone()); + _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."); + // 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) +ForwardProjectorByBin::set_pre_data_processor(shared_ptr>> pre_data_processor_sptr) { - _pre_data_processor_sptr = 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 0769b7cfe..9c08f8940 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 @@ -21,7 +21,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" #include "stir/Viewgram.h" #include "stir/RelatedViewgrams.h" @@ -40,22 +39,17 @@ 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"); @@ -64,44 +58,39 @@ initialise_keymap() } bool -ForwardProjectorByBinUsingProjMatrixByBin:: -post_processing() +ForwardProjectorByBinUsingProjMatrixByBin::post_processing() { - //if (ForwardProjectorByBin::post_processing() == true) - // return true; + // if (ForwardProjectorByBin::post_processing() == true) + // return true; if (is_null_ptr(proj_matrix_ptr)) - { - warning("ForwardProjectorByBinUsingProjMatrixByBin: matrix not set.\n"); - return true; - } + { + warning("ForwardProjectorByBinUsingProjMatrixByBin: matrix not set.\n"); + return true; + } return false; } -ForwardProjectorByBinUsingProjMatrixByBin:: -ForwardProjectorByBinUsingProjMatrixByBin() +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) +{ proj_matrix_ptr->set_up(proj_data_info_ptr, image_info_ptr); ForwardProjectorByBin::set_up(proj_data_info_ptr, image_info_ptr); } -const DataSymmetriesForViewSegmentNumbers * +const DataSymmetriesForViewSegmentNumbers* ForwardProjectorByBinUsingProjMatrixByBin::get_symmetries_used() const { if (!this->_already_set_up) @@ -109,117 +98,112 @@ ForwardProjectorByBinUsingProjMatrixByBin::get_symmetries_used() const 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 - // symmetries - // would be slow if there's no caching at all, but is very fast if everything is cached + { + // 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; + ProjMatrixElemsForOneBin proj_matrix_row; - RelatedViewgrams::iterator r_viewgrams_iter = viewgrams.begin(); - - 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(); - 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); - viewgram[ax_pos][tang_pos] = bin.get_bin_value(); + RelatedViewgrams::iterator r_viewgrams_iter = viewgrams.begin(); + + 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(); + 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); + viewgram[ax_pos][tang_pos] = bin.get_bin_value(); + } + ++r_viewgrams_iter; } - ++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, - // 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) - { - 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); - - vector r_ax_poss; - 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 ( - auto 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)) - continue; - - already_processed[axial_pos_tmp][tang_pos_tmp] = 1; - - - for (RelatedViewgrams::iterator viewgram_iter = viewgrams.begin(); - viewgram_iter != viewgrams.end(); - ++viewgram_iter) + { + + // Complicated version which handles the symmetries explicitly. + // 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) { - 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, - 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); - - viewgram[axial_pos_tmp][tang_pos_tmp] = bin.get_bin_value(); + 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); + + vector r_ax_poss; + 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 (auto 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)) + continue; + + already_processed[axial_pos_tmp][tang_pos_tmp] = 1; + + 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, + 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); + + 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 diff --git a/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing.cxx b/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing.cxx index c60a5657c..b960634ae 100644 --- a/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing.cxx +++ b/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing.cxx @@ -22,9 +22,9 @@ See STIR/LICENSE.txt for details */ -/* +/* History: - * Matthias Egger: C version + * Matthias Egger: C version * PARAPET project : C++ version @@ -70,585 +70,608 @@ 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() +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) + + 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."); + error("The on-the-fly Ray tracing forward projector cannot handle data with odd number of views. Use another projector. " + "Sorry."); } - if (fabs(proj_data_info_sptr->get_phi(Bin(0,0,0,0)))>1.E-4F) + if (fabs(proj_data_info_sptr->get_phi(Bin(0, 0, 0, 0))) > 1.E-4F) { - error("The on-the-fly Ray tracing forward projector cannot handle data with non-zero view offset. Use another projector. Sorry."); + error("The on-the-fly Ray tracing forward projector cannot handle data with non-zero view offset. 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 " "separation (%g)\n", - image_info_ptr->get_origin().z(), voxel_size.z()); + 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(); + 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); - } - + { + 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); + } // 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 * +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); - - } - 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); - } + 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) + { + 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 - { - 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"); - 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); - + { + 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"); + 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); + } } - } 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"); - } + { + // segment symmetry + if (viewgrams.get_num_viewgrams() == 2) + { + Viewgram& pos_view = *(viewgrams.begin() + 0); + Viewgram& neg_view = *(viewgrams.begin() + 1); - } // oblique case + 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()); + const shared_ptr 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 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,pos_view.get_timing_pos_num()); + 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; - - 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); + const int min_tang_pos_num_in_loop = min_abs_tangential_pos_num == 0 ? 1 : min_abs_tangential_pos_num; - // 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. + 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); - // When the axial sampling is the same as the voxel size, we take just - // 1 LOR. - float offset_start = -.25F; - float offset_incr = .5F; + // 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. - int num_lors_per_virtual_ring = 2; - - if (num_planes_per_axial_pos == 1) + // 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; + offset_start = 0; + offset_incr = 1; + num_lors_per_virtual_ring = 1; } - - for (float offset = offset_start; offset < 0.3; offset += offset_incr) + 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 - < 2>( - 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 - <1>( - 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++) { + 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<2>(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; - 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]; - } - } + + 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<1>(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 - <4>( - 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 - <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]; - } - } - } - } + } + 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<4>(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]; + } + } - }// end of } else { - }// end of test for offset loop - -} + /* 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<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 +} /* 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); @@ -656,87 +679,88 @@ ForwardProjectorByBinUsingRayTracing:: 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 @@ -989,12 +1013,13 @@ 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); @@ -1003,375 +1028,421 @@ forward_project_view_2D(Viewgram & pos_view, 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); - + 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 { // 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()); + const shared_ptr 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 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,pos_view.get_timing_pos_num()); - - // 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) - { - 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 - <2>( - 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 - <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); - + { + num_lors_per_virtual_ring = 1; + } - { - if (proj_Siddon - <1>( - 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 (proj_Siddon - <1>( - 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 (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<2>(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<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); + + { + if (proj_Siddon<1>(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 (proj_Siddon<1>(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 { - if (min_abs_tangential_pos_num==0) - { - /* Here tang_pos_num==0 and phi!=k*45 */ - { - if (proj_Siddon - <4>( - 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 - <4>( - 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); - - { - if (proj_Siddon - <3>( - 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) + // general phi + for (D = 0; D < C; D++) { - if (proj_Siddon - <3>( - 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 - + if (min_abs_tangential_pos_num == 0) + { + /* Here tang_pos_num==0 and phi!=k*45 */ + { + if (proj_Siddon<4>(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<4>(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); + + { + if (proj_Siddon<3>(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<3>(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 } #if 0 // disabled as currently not used. needs to be written in the new style anyway diff --git a/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing_Siddon.cxx b/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing_Siddon.cxx index b929b9f3c..40f25747d 100644 --- a/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing_Siddon.cxx +++ b/src/recon_buildblock/ForwardProjectorByBinUsingRayTracing_Siddon.cxx @@ -57,15 +57,16 @@ using std::max; START_NAMESPACE_STIR template -static inline int sign(const T& t) +static inline int +sign(const T& t) { - return t<0 ? -1 : 1; + 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 @@ -74,31 +75,35 @@ 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 */ @@ -112,15 +117,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 @@ -133,112 +136,108 @@ 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 - max_a = sqrt(square(fovrad_in_mm) - square(s_in_mm)); - min_a = -max_a; - } // restrict_to_cylindrical_FOV - 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 - |X| <= fovrad_in_mm && |Y| <= fovrad_in_mm - */ - if (fabs(cphi) < 1.E-3 || fabs(sphi) < 1.E-3) { - if (fovrad_in_mm < fabs(s_in_mm)) + if (fabs(s_in_mm) >= fovrad_in_mm) return false; - max_a = fovrad_in_mm; - min_a = -fovrad_in_mm; - } - else + // 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 { - 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(); - 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); - - 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); + // 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 + |X| <= fovrad_in_mm && |Y| <= fovrad_in_mm + */ + 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()) + 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(); + 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); + + 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_? @@ -259,7 +258,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. @@ -268,37 +267,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--; - } - 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]; - } - - } - a = ay; ay += inc_y; - Y++; - } 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--; - } - - } /* Ende 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--; + } + 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]; + } + } + a = ay; + ay += inc_y; + Y++; + } + 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--; + } + + } /* 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 e65453e81..63f81a6eb 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 @@ -22,13 +22,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" @@ -53,47 +52,39 @@ using std::ios; using std::ofstream; - 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; @@ -101,583 +92,617 @@ set_defaults() fore_debug_level = 0; } -FourierRebinning:: -FourierRebinning() +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; - } + 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) + ; - 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); + // 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; - //CON Create the output (rebinned projection data) data structure and set the properties of the rebinned sinograms + 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 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++){ - - 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 - 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 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 + 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 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++) { - 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++) - real[i][j] = FT_rebinned_sinogram[i][j].real(); - 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++) - real[i][j] = FT_rebinned_sinogram[i][j].imag(); - 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; + + 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++) + real[i][j] = FT_rebinned_sinogram[i][j].real(); + 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++) + real[i][j] = FT_rebinned_sinogram[i][j].imag(); + 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 < 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 + + 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 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) + // 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; + 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++) + { -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); - - //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){ + 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); + + // 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) ); - } - + "Total rebinned SSRB: %3%") + % (count_rebinned.total - local_rebinned) % (count_rebinned.miss - local_miss) % (count_rebinned.ssrb - local_ssrb)); + } } +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); + if (fabs(static_cast(z_in_mm / half_distance_between_rings - z)) > .005F) + 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; -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 The continuous frequency "w" corresponds the radial coordinate "s" + // CON The integer Fourier index "k" corresponds to the azimuthal angle "view" - - //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); - if(fabs(static_cast(z_in_mm/half_distance_between_rings - z)) > .005F) - 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){ + // 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; + + 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; } - //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 - + 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()) { +} + +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'; + 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' +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 (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; +} -void -FourierRebinning:: -do_adjust_nb_views_to_pow2(SegmentBySinogram &segment) +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.))))); + // 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; -} - -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 (num_views_pow2 == segment.get_num_views()) + return; - if(deltamin<0) { - warning("FORE initialisation :: The deltamin parameter must be an integer value >= 0"); - 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); + 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); - 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; - } + 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) +{ - 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; - } + // 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(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 (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(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 (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; - } + 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; + return Succeeded::yes; } - END_NAMESPACE_STIR diff --git a/src/recon_buildblock/GeneralisedObjectiveFunction.cxx b/src/recon_buildblock/GeneralisedObjectiveFunction.cxx index 74c37e7d2..0e74d7617 100644 --- a/src/recon_buildblock/GeneralisedObjectiveFunction.cxx +++ b/src/recon_buildblock/GeneralisedObjectiveFunction.cxx @@ -35,8 +35,7 @@ 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. @@ -45,80 +44,69 @@ set_defaults() template void -GeneralisedObjectiveFunction:: -initialise_keymap() +GeneralisedObjectiveFunction::initialise_keymap() { this->parser.add_parsing_key("prior type", &prior_sptr); } template -GeneralisedObjectiveFunction:: -~GeneralisedObjectiveFunction() +GeneralisedObjectiveFunction::~GeneralisedObjectiveFunction() {} template -Succeeded -GeneralisedObjectiveFunction:: -set_up(shared_ptr const& target_data_ptr) +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); + warning("Number of subsets %d should be larger than 0.", this->num_subsets); return Succeeded::no; } - 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() +shared_ptr> +GeneralisedObjectiveFunction::get_prior_sptr() { - return this->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 +GeneralisedObjectiveFunction::prior_is_zero() const { - return - is_null_ptr(this->prior_sptr) || - this->prior_sptr->get_penalisation_factor() == 0; + 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.; @@ -128,217 +116,184 @@ compute_penalty(const TargetT& current_estimate) template double -GeneralisedObjectiveFunction:: -compute_penalty(const TargetT& current_estimate, - const int subset_num) +GeneralisedObjectiveFunction::compute_penalty(const TargetT& current_estimate, const int subset_num) { - return this->compute_penalty(current_estimate)/this->get_num_subsets(); + 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) { if (!this->already_set_up) error("Need to call set_up() for objective function first"); 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 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) +GeneralisedObjectiveFunction::compute_objective_function_without_penalty(const TargetT& current_estimate, + const int subset_num) { if (!this->already_set_up) error("Need to call set_up() for objective function first"); - if (subset_num<0 || subset_num>=this->get_num_subsets()) + 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) +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); + 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) +GeneralisedObjectiveFunction::compute_objective_function(const TargetT& current_estimate) { - return - this->compute_objective_function_without_penalty(current_estimate) - - this->compute_penalty(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 +Succeeded +GeneralisedObjectiveFunction::add_multiplication_with_approximate_sub_Hessian_without_penalty(TargetT& output, + const TargetT& input, + const int subset_num) const { if (!this->already_set_up) error("Need to call set_up() for objective function first"); - if (subset_num<0 || subset_num>=this->get_num_subsets()) + 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)) + 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; + 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 +Succeeded +GeneralisedObjectiveFunction::add_multiplication_with_approximate_sub_Hessian(TargetT& output, + const TargetT& input, + const int subset_num) const { if (!this->already_set_up) error("Need to call set_up() for objective function first"); - if (this->add_multiplication_with_approximate_sub_Hessian_without_penalty(output, input, subset_num) == - Succeeded::no) + 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()); + shared_ptr prior_output_sptr(output.get_empty_copy()); this->prior_sptr->add_multiplication_with_approximate_Hessian(*prior_output_sptr, output); - // (*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; - } - } + // (*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 +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) + 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; + 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 +Succeeded +GeneralisedObjectiveFunction::add_multiplication_with_approximate_Hessian(TargetT& output, const TargetT& input) const { - for (int subset_num=0; subset_numget_num_subsets(); ++subset_num) + 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; + 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; } @@ -346,152 +301,135 @@ 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 +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) - return Succeeded::no; - } + 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; } template Succeeded -GeneralisedObjectiveFunction:: -accumulate_Hessian_times_input_without_penalty(TargetT& output, - const TargetT& current_image_estimate, - const TargetT& input) const +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) - return Succeeded::no; - } + 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; } 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) + 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()) - { - // TODO used boost:scoped_ptr - shared_ptr prior_output_sptr(output.get_empty_copy()); - this->prior_sptr->accumulate_Hessian_times_input(*prior_output_sptr, current_image_estimate, output); - - 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; + // TODO used boost:scoped_ptr + shared_ptr prior_output_sptr(output.get_empty_copy()); + this->prior_sptr->accumulate_Hessian_times_input(*prior_output_sptr, current_image_estimate, output); + + 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:: -accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, - const TargetT& current_image_estimate, - const TargetT& input, - const int subset_num) const +GeneralisedObjectiveFunction::accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, + const TargetT& current_image_estimate, + const TargetT& input, + const int subset_num) const { if (!this->already_set_up) error("Need to call set_up() for objective function first"); - if (subset_num<0 || subset_num>=this->get_num_subsets()) + if (subset_num < 0 || subset_num >= this->get_num_subsets()) error("accumulate_sub_Hessian_times_input_without_penalty subset_num out-of-range error"); { string explanation; - if (!output.has_same_characteristics(input, explanation)) { - warning("GeneralisedObjectiveFunction:\n" - "input and output for accumulate_sub_Hessian_times_input_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 accumulate_sub_Hessian_times_input_without_penalty\n" + "should have the same characteristics.\n%s", + explanation.c_str()); + return Succeeded::no; + } - if (!output.has_same_characteristics(current_image_estimate, explanation)) { - warning("GeneralisedObjectiveFunction:\n" - "current_image_estimate and output for accumulate_sub_Hessian_times_input_without_penalty\n" - "should have the same characteristics.\n%s", - explanation.c_str()); - return Succeeded::no; - } + if (!output.has_same_characteristics(current_image_estimate, explanation)) + { + warning("GeneralisedObjectiveFunction:\n" + "current_image_estimate and output for accumulate_sub_Hessian_times_input_without_penalty\n" + "should have the same characteristics.\n%s", + explanation.c_str()); + return Succeeded::no; + } } - - 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) { std::ostringstream s; - 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 { #if 0 // TODO cannot do this yet, as this function is called in @@ -502,15 +440,12 @@ 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 83a5ef5df..f9b3cef7c 100644 --- a/src/recon_buildblock/GeneralisedPrior.cxx +++ b/src/recon_buildblock/GeneralisedPrior.cxx @@ -12,9 +12,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" @@ -26,27 +26,24 @@ START_NAMESPACE_STIR - template -void +void GeneralisedPrior::initialise_keymap() { - this->parser.add_key("penalisation factor", &this->penalisation_factor); + this->parser.add_key("penalisation factor", &this->penalisation_factor); } - template void 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; @@ -54,10 +51,9 @@ set_up(shared_ptr const&) template void -GeneralisedPrior:: -compute_Hessian(TargetT& output, - const BasicCoordinate<3,int>& coords, - const TargetT& current_image_estimate) const +GeneralisedPrior::compute_Hessian(TargetT& output, + const BasicCoordinate<3, int>& coords, + const TargetT& current_image_estimate) const { if (this->is_convex()) error("GeneralisedPrior:\n compute_Hessian implementation is not overloaded by your convex prior."); @@ -67,38 +63,36 @@ compute_Hessian(TargetT& output, template void -GeneralisedPrior:: -add_multiplication_with_approximate_Hessian(TargetT& output, - const TargetT& input) const +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."); } template void -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."); } -template -void GeneralisedPrior::check(TargetT const& current_estimate) const +template +void +GeneralisedPrior::check(TargetT const& current_estimate) const { - if (!_already_set_up) + 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 6e90bada6..6e227d02e 100644 --- a/src/recon_buildblock/IterativeReconstruction.cxx +++ b/src/recon_buildblock/IterativeReconstruction.cxx @@ -15,13 +15,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 @@ -47,12 +47,11 @@ using std::cerr; using std::endl; using std::string; - START_NAMESPACE_STIR //********* parameters **************** template -void +void IterativeReconstruction::set_defaults() { base_type::set_defaults(); @@ -60,105 +59,95 @@ IterativeReconstruction::set_defaults() 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 +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<::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); - - -} + 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 << 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); +} 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; } + { + 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; } + { + warning("You need to specify an initial estimate file"); + return true; + } return false; } @@ -166,187 +155,184 @@ 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() +shared_ptr> +IterativeReconstruction::get_inter_iteration_filter_sptr() { - return this->inter_iteration_filter_ptr; + 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) +IterativeReconstruction::set_objective_function_sptr(const shared_ptr>& arg) { - this->objective_function_sptr = arg; + this->objective_function_sptr = arg; } template void -IterativeReconstruction:: -set_max_num_full_iterations(const int arg) +IterativeReconstruction::set_max_num_full_iterations(const int arg) { - this->max_num_full_iterations = 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) +IterativeReconstruction::set_num_subiterations(const int arg) { - this->num_subiterations = arg; + this->num_subiterations = arg; } template void -IterativeReconstruction:: -set_start_subiteration_num(const int arg) +IterativeReconstruction::set_start_subiteration_num(const int arg) { - this->start_subiteration_num = arg; + this->start_subiteration_num = arg; } template void -IterativeReconstruction:: -set_start_subset_num(const int arg) +IterativeReconstruction::set_start_subset_num(const int arg) { - if (arg<0 || arg>= this->num_subsets) + 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) +IterativeReconstruction::set_save_interval(const int arg) { - this->save_interval = arg; + this->save_interval = arg; } template void -IterativeReconstruction:: -set_randomise_subset_order(const bool arg) +IterativeReconstruction::set_randomise_subset_order(const bool arg) { - this->randomise_subset_order = arg; + this->randomise_subset_order = arg; } template void -IterativeReconstruction:: -set_inter_iteration_filter_ptr(const shared_ptr >& arg) +IterativeReconstruction::set_inter_iteration_filter_ptr(const shared_ptr>& arg) { - this->inter_iteration_filter_ptr = arg; + this->inter_iteration_filter_ptr = arg; } template void -IterativeReconstruction:: -set_inter_iteration_filter_interval(const int arg) +IterativeReconstruction::set_inter_iteration_filter_interval(const int arg) { - this->inter_iteration_filter_interval = 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); @@ -355,31 +341,29 @@ make_filename_prefix_subiteration_num(const std::string& filename_prefix) const template std::string -IterativeReconstruction:: -make_filename_prefix_subiteration_num() const +IterativeReconstruction::make_filename_prefix_subiteration_num() const { - return - this->make_filename_prefix_subiteration_num(this->output_filename_prefix); + return this->make_filename_prefix_subiteration_num(this->output_filename_prefix); } template -TargetT * +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") - { - result = this->objective_function_sptr->construct_target_ptr(); - } - 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); - } + if (this->initial_data_filename == "0") + { + result = this->objective_function_sptr->construct_target_ptr(); + } + 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); @@ -387,7 +371,8 @@ IterativeReconstruction::get_initial_data_ptr() const } 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; } @@ -395,9 +380,8 @@ 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(); @@ -414,9 +398,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); @@ -428,11 +411,12 @@ reconstruct(shared_ptr const& target_data_sptr) } #endif - 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); - } + 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(); @@ -441,51 +425,66 @@ reconstruct(shared_ptr const& target_data_sptr) // 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 ) - { error("number of subsets should be positive"); return Succeeded::no; } + if (this->num_subsets < 1) + { + error("number of subsets should be positive"); + return Succeeded::no; + } if (is_null_ptr(this->objective_function_sptr)) - { error("You have to specify an objective function"); return Succeeded::no; } + { + error("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) + 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); + 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->num_subiterations<1) - { error("Range error in number of subiterations (has to be >= 1)"); return Succeeded::no; } - - if(this->start_subset_num<0 || this->start_subset_num>=this->num_subsets) - { error("Range error in starting subset (has to be between 0 and num_subsets-1)"); return Succeeded::no; } + if (this->num_subiterations < 1) + { + error("Range error in number of subiterations (has to be >= 1)"); + return Succeeded::no; + } + + if (this->start_subset_num < 0 || this->start_subset_num >= this->num_subsets) + { + error("Range error in starting subset (has to be between 0 and num_subsets-1)"); + return Succeeded::no; + } - if(this->save_interval<1 || this->save_interval>this->num_subiterations) - { error("Range error in iteration save interval (has to be between 1 and num_subiterations-1)"); return Succeeded::no;} - - if (this->inter_iteration_filter_interval<0) - { error("Range error in inter-iteration filter interval (has to be >= 0)"); return Succeeded::no; } + if (this->save_interval < 1 || this->save_interval > this->num_subiterations) + { + error("Range error in iteration save interval (has to be between 1 and num_subiterations-1)"); + return Succeeded::no; + } - if (this->start_subiteration_num<1) - { error("Range error in starting subiteration number (has to be >= 1)"); return Succeeded::no; } + if (this->inter_iteration_filter_interval < 0) + { + error("Range error in inter-iteration filter interval (has to be >= 0)"); + return Succeeded::no; + } + + if (this->start_subiteration_num < 1) + { + error("Range error in starting subiteration number (has to be >= 1)"); + return Succeeded::no; + } if (this->objective_function_sptr->set_up(target_data_sptr) == Succeeded::no) return Succeeded::no; @@ -493,15 +492,15 @@ set_up(shared_ptr const& target_data_sptr) ////////////////// 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 - // be caught before doing any projections or so done. + // 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 + // be caught before doing any projections or so done. #if 0 /* KT 04/06/2003 disabled the explicit calling of inter_iteration_filter_ptr->set_up() @@ -525,104 +524,91 @@ 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) +void +IterativeReconstruction::end_of_iteration_processing(TargetT& current_estimate) { - std::stringstream cerr; + 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)) + 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); + /*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) + + 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<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 << 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; + } + info(cerr.str()); // 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++) - { - - 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++) + temp_array[i] = i; - for (int j=index;jnum_subsets-(i+1);j++) - temp_array[j]=temp_array[j+1]; + for (int i = 0; i < this->num_subsets; 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]; - { - std::stringstream s; - s<<"Generating new subset sequence: "; - for(int i=0;inum_subsets;i++) s<num_subsets - (i + 1); j++) + temp_array[j] = temp_array[j + 1]; + } - return final_array; + { + std::stringstream s; + s << "Generating new subset sequence: "; + for (int i = 0; i < this->num_subsets; i++) + s << final_array[i] << " "; + info(s.str(), 2); + } + 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)) @@ -632,41 +618,33 @@ 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() +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; + 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; } -# 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 9936e6e97..d9b038fa6 100644 --- a/src/recon_buildblock/LogcoshPrior.cxx +++ b/src/recon_buildblock/LogcoshPrior.cxx @@ -55,54 +55,53 @@ template bool LogcoshPrior::post_processing() { - if (base_type::post_processing()==true) + 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 - } - else - { - if (!this->weights.is_regular()) + if (this->weights.size() == 0) { - warning("Sorry. LogcoshPrior currently only supports regular arrays for the weights"); - return true; + // will call compute_weights() to fill it in } - - 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) + else { - const unsigned int size_y = this->weights[z].size(); - if (size_y%2==0) + 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) 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_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); + } + } } - } if (warn_about_even_size) 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 @@ -117,9 +116,7 @@ LogcoshPrior::set_defaults() } template <> -const char * const - LogcoshPrior::registered_name = - "Logcosh"; +const char* const LogcoshPrior::registered_name = "Logcosh"; template LogcoshPrior::LogcoshPrior() @@ -127,19 +124,18 @@ LogcoshPrior::LogcoshPrior() set_defaults(); } - template LogcoshPrior::LogcoshPrior(const bool only_2D_v, float penalisation_factor_v) - : only_2D(only_2D_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; @@ -148,25 +144,26 @@ LogcoshPrior::LogcoshPrior(const bool only_2D_v, float penalisation_facto template bool -LogcoshPrior:: -is_convex() const +LogcoshPrior::is_convex() const { return true; } //! 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 @@ -174,83 +171,83 @@ 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) - { - min_dz = max_dz = 0; - } + { + 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 + { + 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) { - weights[z][y][x] = - grid_spacing.x()/ - sqrt(square(x*grid_spacing.x())+ - square(y*grid_spacing.y())+ - square(z*grid_spacing.z())); + 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 -LogcoshPrior:: -compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate) +LogcoshPrior::compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate) { - if (this->penalisation_factor==0) - { - return 0.; - } + 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) - { - compute_weights(this->weights, current_image_cast.get_grid_spacing(), this->only_2D); - } + 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); @@ -260,70 +257,70 @@ 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(); + 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] * - 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 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++) { - // 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); - if (do_kappa) - current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; - result += static_cast(current); + 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] * + 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) + { + // 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); + 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/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) - { - prior_gradient.fill(0); - return; - } + 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) - { - compute_weights(this->weights, current_image_cast.get_grid_spacing(), this->only_2D); - } + 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)) @@ -331,86 +328,84 @@ 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); - - 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_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_dz = max(weights.get_min_index(), min_z - z); + const int max_dz = min(weights.get_max_index(), max_z - z); - const int min_x = current_image_estimate[z][y].get_min_index(); - const int max_x = current_image_estimate[z][y].get_max_index(); + const int min_y = current_image_estimate[z].get_min_index(); + const int max_y = current_image_estimate[z].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/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); + 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); - if (do_kappa) - current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; + 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 += current; + 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/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); + + 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; } - 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); - OutputFileFormat >::default_sptr()-> - 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); + 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) const +LogcoshPrior::compute_Hessian(DiscretisedDensity<3, elemT>& prior_Hessian_for_single_densel, + const BasicCoordinate<3, int>& coords, + const DiscretisedDensity<3, elemT>& current_image_estimate) const { - assert( prior_Hessian_for_single_densel.has_same_characteristics(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) - { - return; - } + 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); + 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) - { - compute_weights(weights, current_image_cast.get_grid_spacing(), this->only_2D); - } + 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); @@ -420,69 +415,68 @@ 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) - { - elemT current = 0.0; - if (dz == 0 && dy == 0 && dx == 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) { - // The j == k case (diagonal Hessian element), which is a sum over the neighbourhood. - for (int ddz=min_dz;ddz<=max_dz;++ddz) - for (int ddy=min_dy;ddy<=max_dy;++ddy) - for (int ddx=min_dx;ddx<=max_dx;++ddx) - { - elemT diagonal_current = weights[ddz][ddy][ddx] * - derivative_20(current_image_estimate[z][y][x], - current_image_estimate[z + ddz][y + ddy][x + ddx]); - if (do_kappa) - diagonal_current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+ddz][y+ddy][x+ddx]; - current += diagonal_current; - } - } - else - { - // The j != k vases (off-diagonal Hessian elements) - current = weights[dz][dy][dx] * derivative_11(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]; + elemT current = 0.0; + if (dz == 0 && dy == 0 && dx == 0) + { + // The j == k case (diagonal Hessian element), which is a sum over the neighbourhood. + for (int ddz = min_dz; ddz <= max_dz; ++ddz) + for (int ddy = min_dy; ddy <= max_dy; ++ddy) + for (int ddx = min_dx; ddx <= max_dx; ++ddx) + { + elemT diagonal_current + = weights[ddz][ddy][ddx] + * derivative_20(current_image_estimate[z][y][x], current_image_estimate[z + ddz][y + ddy][x + ddx]); + if (do_kappa) + diagonal_current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + ddz][y + ddy][x + ddx]; + current += diagonal_current; + } + } + else + { + // The j != k vases (off-diagonal Hessian elements) + current = weights[dz][dy][dx] + * derivative_11(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]; + } + 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; - } } - 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) - { - parabolic_surrogate_curvature.fill(0); - return; - } + 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) - { - compute_weights(weights, current_image_cast.get_grid_spacing(), this->only_2D); - } + 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); @@ -491,70 +485,69 @@ 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); - - 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_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) - { - // psi'(t)/t = tanh/t - 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); + const int min_dz = max(weights.get_min_index(), min_z - z); + const int max_dz = min(weights.get_max_index(), max_z - z); - if (do_kappa) - current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; + 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); - gradient += current; + 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) + { + // psi'(t)/t = tanh/t + 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]; + + 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 void -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) - { - return; - } + assert(output.has_same_characteristics(input)); + if (this->penalisation_factor == 0) + { + return; + } - DiscretisedDensityOnCartesianGrid<3,elemT>& output_cast = - dynamic_cast &>(output); + DiscretisedDensityOnCartesianGrid<3, elemT>& output_cast = dynamic_cast&>(output); - if (weights.get_length() ==0) - { - compute_weights(weights, output_cast.get_grid_spacing(), this->only_2D); - } + 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); @@ -563,81 +556,81 @@ 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); - - 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++) + for (int z = min_z; z <= max_z; z++) { - 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(); + 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 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); + const int min_y = output[z].get_min_index(); + const int max_y = output[z].get_max_index(); - 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]; - if (current == elemT(0)) - continue; - if ((dz == 0) && (dy == 0) && (dx == 0)) { - // The j == k case - current *= derivative_20(current_estimate[z][y][x], - current_estimate[z + dz][y + dy][x + dx]) * input[z][y][x]; - } else { - current *= (derivative_20(current_estimate[z][y][x], - current_estimate[z + dz][y + dy][x + dx]) * input[z][y][x] + - derivative_11(current_estimate[z][y][x], - current_estimate[z + dz][y + dy][x + dx]) * - input[z + dz][y + dy][x + dx]); - } + 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); - if (do_kappa) - current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+dz][y+dy][x+dx]; + const int min_x = output[z][y].get_min_index(); + const int max_x = output[z][y].get_max_index(); - result += current; + 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]; + if (current == elemT(0)) + continue; + if ((dz == 0) && (dy == 0) && (dx == 0)) + { + // The j == k case + current *= derivative_20(current_estimate[z][y][x], current_estimate[z + dz][y + dy][x + dx]) + * input[z][y][x]; + } + else + { + current *= (derivative_20(current_estimate[z][y][x], current_estimate[z + dz][y + dy][x + dx]) + * input[z][y][x] + + derivative_11(current_estimate[z][y][x], current_estimate[z + dz][y + dy][x + 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; } - - output[z][y][x] += result * this->penalisation_factor; - } + } } - } } template elemT -LogcoshPrior:: -derivative_20(const elemT x_j, const elemT x_k) const +LogcoshPrior::derivative_20(const elemT x_j, const elemT x_k) const { - return square((1/ cosh((x_j - x_k) * scalar))); + return square((1 / cosh((x_j - x_k) * scalar))); } template elemT -LogcoshPrior:: -derivative_11(const elemT x_j, const elemT x_k) const +LogcoshPrior::derivative_11(const elemT x_j, const elemT x_k) const { return -derivative_20(x_j, x_k); } -# 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/ML_estimate_component_based_normalisation.cxx b/src/recon_buildblock/ML_estimate_component_based_normalisation.cxx index cae62f8a8..a22ed6b0b 100644 --- a/src/recon_buildblock/ML_estimate_component_based_normalisation.cxx +++ b/src/recon_buildblock/ML_estimate_component_based_normalisation.cxx @@ -36,9 +36,16 @@ START_NAMESPACE_STIR void -ML_estimate_component_based_normalisation(const std::string& out_filename_prefix, const ProjData& measured_data, - const ProjData& model_data, int num_eff_iterations, int num_iterations, bool do_geo, - bool do_block, bool do_symmetry_per_block, bool do_KL, bool do_display) +ML_estimate_component_based_normalisation(const std::string& out_filename_prefix, + const ProjData& measured_data, + const ProjData& model_data, + int num_eff_iterations, + int num_iterations, + bool do_geo, + bool do_block, + bool do_symmetry_per_block, + bool do_KL, + bool do_display) { const int num_transaxial_blocks = measured_data.get_proj_data_info_sptr()->get_scanner_sptr()->get_num_transaxial_blocks(); @@ -82,10 +89,14 @@ ML_estimate_component_based_normalisation(const std::string& out_filename_prefix DetectorEfficiencies data_fan_sums(IndexRange2D(num_physical_rings, num_physical_detectors_per_ring)); DetectorEfficiencies efficiencies(IndexRange2D(num_physical_rings, num_physical_detectors_per_ring)); - GeoData3D measured_geo_data(num_physical_axial_crystals_per_basic_unit, num_physical_transaxial_crystals_per_basic_unit / 2, - num_physical_rings, num_physical_detectors_per_ring); // inputes have to be modified - GeoData3D norm_geo_data(num_physical_axial_crystals_per_basic_unit, num_physical_transaxial_crystals_per_basic_unit / 2, - num_physical_rings, num_physical_detectors_per_ring); // inputes have to be modified + GeoData3D measured_geo_data(num_physical_axial_crystals_per_basic_unit, + num_physical_transaxial_crystals_per_basic_unit / 2, + num_physical_rings, + num_physical_detectors_per_ring); // inputes have to be modified + GeoData3D norm_geo_data(num_physical_axial_crystals_per_basic_unit, + num_physical_transaxial_crystals_per_basic_unit / 2, + num_physical_rings, + num_physical_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); @@ -278,8 +289,10 @@ ML_estimate_component_based_normalisation(const std::string& out_filename_prefix if (do_KL) { DetectorEfficiencies fan_sums(IndexRange2D(num_physical_rings, num_physical_detectors_per_ring)); - GeoData3D geo_data(num_physical_axial_crystals_per_basic_unit, num_physical_transaxial_crystals_per_basic_unit / 2, - num_physical_rings, num_physical_detectors_per_ring); // inputes have to be modified + GeoData3D geo_data(num_physical_axial_crystals_per_basic_unit, + num_physical_transaxial_crystals_per_basic_unit / 2, + num_physical_rings, + num_physical_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); diff --git a/src/recon_buildblock/NiftyPET_projector/BackProjectorByBinNiftyPET.cxx b/src/recon_buildblock/NiftyPET_projector/BackProjectorByBinNiftyPET.cxx index 420bdf135..8cc27f8bc 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 @@ -31,23 +31,21 @@ START_NAMESPACE_STIR ////////////////////////////////////////////////////////// -const char * const -BackProjectorByBinNiftyPET::registered_name = - "NiftyPET"; +const char* const BackProjectorByBinNiftyPET::registered_name = "NiftyPET"; -BackProjectorByBinNiftyPET::BackProjectorByBinNiftyPET() : - _cuda_device(0), _cuda_verbosity(true), _use_truncation(false) +BackProjectorByBinNiftyPET::BackProjectorByBinNiftyPET() + : _cuda_device(0), + _cuda_verbosity(true), + _use_truncation(false) { - this->_already_set_up = 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"); @@ -56,39 +54,35 @@ initialise_keymap() } void -BackProjectorByBinNiftyPET:: -set_up(const shared_ptr& proj_data_info_sptr, - const shared_ptr >& density_info_sptr) +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(); + 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."); @@ -96,66 +90,61 @@ get_symmetries_used() const } void -BackProjectorByBinNiftyPET:: -back_project(const ProjData& proj_data, int subset_num, int num_subsets) +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)."); + // 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); + _helper.convert_proj_data_stir_to_niftyPET(_np_sino_w_gaps, proj_data); } void -BackProjectorByBinNiftyPET:: -get_output(DiscretisedDensity<3,float> &density) const +BackProjectorByBinNiftyPET::get_output(DiscretisedDensity<3, float>& density) const { - // --------------------------------------------------------------- // - // Remove gaps from sinogram - // --------------------------------------------------------------- // + // --------------------------------------------------------------- // + // 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); + std::vector sino_no_gaps = _helper.create_niftyPET_sinogram_no_gaps(); + _helper.remove_gaps(sino_no_gaps, _np_sino_w_gaps); - // --------------------------------------------------------------- // - // Back project - // --------------------------------------------------------------- // + // --------------------------------------------------------------- // + // Back project + // --------------------------------------------------------------- // - std::vector np_im = _helper.create_niftyPET_image(); - _helper.back_project(np_im,sino_no_gaps); + std::vector np_im = _helper.create_niftyPET_image(); + _helper.back_project(np_im, sino_no_gaps); - // --------------------------------------------------------------- // - // NiftyPET -> STIR image conversion - // --------------------------------------------------------------- // + // --------------------------------------------------------------- // + // NiftyPET -> STIR image conversion + // --------------------------------------------------------------- // - _helper.convert_image_niftyPET_to_stir(density,np_im); + _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); + // 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() +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(); + // 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) +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); + 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 eeb0874c1..c77bc5161 100644 --- a/src/recon_buildblock/NiftyPET_projector/ForwardProjectorByBinNiftyPET.cxx +++ b/src/recon_buildblock/NiftyPET_projector/ForwardProjectorByBinNiftyPET.cxx @@ -33,23 +33,21 @@ START_NAMESPACE_STIR ////////////////////////////////////////////////////////// -const char * const -ForwardProjectorByBinNiftyPET::registered_name = - "NiftyPET"; +const char* const ForwardProjectorByBinNiftyPET::registered_name = "NiftyPET"; -ForwardProjectorByBinNiftyPET::ForwardProjectorByBinNiftyPET() : - _cuda_device(0), _cuda_verbosity(true), _use_truncation(false) +ForwardProjectorByBinNiftyPET::ForwardProjectorByBinNiftyPET() + : _cuda_device(0), + _cuda_verbosity(true), + _use_truncation(false) { - this->_already_set_up = 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"); @@ -58,40 +56,35 @@ initialise_keymap() } void -ForwardProjectorByBinNiftyPET:: -set_up(const shared_ptr& proj_data_info_sptr, - const shared_ptr >& density_info_sptr) +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(); + 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."); @@ -99,67 +92,60 @@ get_symmetries_used() const } void -ForwardProjectorByBinNiftyPET:: -actual_forward_project(RelatedViewgrams&, - const DiscretisedDensity<3,float>&, - const int, const int, - const int, const int) +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."); + 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) +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(); + // 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); + viewgrams = _projected_data_sptr->get_related_viewgrams(viewgrams.get_basic_view_segment_num(), _symmetries_sptr); } void -ForwardProjectorByBinNiftyPET:: -set_input(const DiscretisedDensity<3,float> & density) +ForwardProjectorByBinNiftyPET::set_input(const DiscretisedDensity<3, float>& density) { - ForwardProjectorByBin::set_input(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 53b92c308..e4349bbe6 100644 --- a/src/recon_buildblock/NiftyPET_projector/NiftyPETHelper.cxx +++ b/src/recon_buildblock/NiftyPET_projector/NiftyPETHelper.cxx @@ -48,1256 +48,1320 @@ START_NAMESPACE_STIR -NiftyPETHelper::~NiftyPETHelper() {} +NiftyPETHelper::~NiftyPETHelper() +{} -static void delete_axialLUT(axialLUT *axlut_ptr) +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; + 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) +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); + 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) +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(); + 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; + 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()); + 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->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->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->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->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->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->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->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->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->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->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->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->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 + 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; + 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) +static inline unsigned +to_1d_idx(const unsigned nrow, const unsigned ncol, const unsigned row, const unsigned col) { - return col + ncol*row; + return col + ncol * row; } -template -dataType* create_heap_array(const unsigned numel, const dataType val = dataType(0)) +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; + 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."); + 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 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 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; + // --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; } } } - // 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; i 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 } } - // 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 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; } } - //====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 subscript indecies for positive and negative RDs - if (m==0) { - r1 = floor(float(li)/float(NRNG)); - r0 = li - r1*NRNG; + //====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; } - // for positive now (? or vice versa) - else { - r0 = floor(float(li)/float(NRNG)); - r1 = li - r0*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; + // 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_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_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)]; + sn1_sn11no[sni] = Mnos[to_1d_idx(NRNG, NRNG, r0, r1)]; - Msn1[to_1d_idx(NRNG,NRNG,r0,r1)] = sni; - //-- - sni += 1; + Msn1[to_1d_idx(NRNG, NRNG, r0, r1)] = sni; + //-- + sni += 1; } } } - // 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_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; 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 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(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; + // 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) +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; + 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(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() +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"); - } + 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; i(unsigned(AW)); + for (unsigned i = 0; i < unsigned(AW); i++) + _isub[i] = int(i); - _already_set_up = true; + _already_set_up = true; } void -NiftyPETHelper:: -check_set_up() const +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."); + 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() +NiftyPETHelper::create_niftyPET_image() { - return std::vector(SZ_IMZ*SZ_IMX*SZ_IMY,0); + return std::vector(SZ_IMZ * SZ_IMX * SZ_IMY, 0); } -shared_ptr > -NiftyPETHelper:: -create_stir_im() +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; + 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 +NiftyPETHelper::create_niftyPET_sinogram_no_gaps() const { - check_set_up(); - return std::vector(_isub.size() * static_cast(_nsinos), 0); + check_set_up(); + return std::vector(_isub.size() * static_cast(_nsinos), 0); } std::vector -NiftyPETHelper:: -create_niftyPET_sinogram_with_gaps() const +NiftyPETHelper::create_niftyPET_sinogram_with_gaps() const { - return std::vector(NSBINS*NSANGLES*unsigned(_nsinos), 0); + 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) +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; + 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) +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; + 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 +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; + 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 +NiftyPETHelper::remove_gaps(std::vector& sino_no_gaps, const std::vector& sino_w_gaps) const { - check_set_up(); - assert(!sino_no_gaps.empty()); + check_set_up(); + assert(!sino_no_gaps.empty()); - if (_verbose) - getMemUse(); + if (_verbose) + getMemUse(); - ::remove_gaps(sino_no_gaps.data(), - const_cast(sino_w_gaps.data()), - _nsinos, - _txlut_sptr->aw2ali, - *_cnt_sptr); + ::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 +NiftyPETHelper::put_gaps(std::vector& sino_w_gaps, const std::vector& sino_no_gaps) const { - check_set_up(); - assert(!sino_w_gaps.empty()); + check_set_up(); + assert(!sino_w_gaps.empty()); - std::vector unpermuted_sino_w_gaps = this->create_niftyPET_sinogram_with_gaps(); + std::vector unpermuted_sino_w_gaps = this->create_niftyPET_sinogram_with_gaps(); - if (_verbose) - getMemUse(); + if (_verbose) + getMemUse(); - ::put_gaps(unpermuted_sino_w_gaps.data(), - const_cast(sino_no_gaps.data()), - _txlut_sptr->aw2ali, - *_cnt_sptr); + ::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); + // 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 +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); + 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 +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); + 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; + 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) +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; + // 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 * +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"); + 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 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); + std::string header; + std::getline(numpy_file, header); + // Read + float* axf1 = read_from_binary_file(numpy_file, num_elements); - // Close file - numpy_file.close(); + // Close file + numpy_file.close(); - return axf1; + return axf1; } // Taken from mmrnorm.py -static -NormCmp get_norm_helper_struct(const std::string &norm_binary_file, const Cnst &cnt) +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; + // 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) +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; - } + // number of single rates reported for the given second + // nsr = (hstout['bck'][1,:,:]>>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 buckets(B,0); - for (unsigned i=0; i 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 +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(); + 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); + // 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; i1, " + "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 [] 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; + 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[] 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; + // 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*."); + 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]) +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()); + 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) +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()); + // 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) +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]; + // 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) +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]; + // 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) +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(&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) +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) +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 &np_vec, const Viewgram& viewgram) const +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(); - - // 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) { - - unsigned np_sino; - - // 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); - - 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); + // 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(); + + // 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) + { + + unsigned np_sino; + + // 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); + + 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 +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)); + 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 +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); + // 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); + stir.set_sinogram(sino); } } diff --git a/src/recon_buildblock/NiftyPET_projector/ProjectorByBinPairUsingNiftyPET.cxx b/src/recon_buildblock/NiftyPET_projector/ProjectorByBinPairUsingNiftyPET.cxx index 5a6ce37a1..e109d1177 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 @@ -19,30 +19,24 @@ 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 +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() { @@ -54,16 +48,15 @@ ProjectorByBinPairUsingNiftyPET::set_defaults() bool ProjectorByBinPairUsingNiftyPET::post_processing() { - this->set_verbosity(this->_verbosity); - this->set_use_truncation(this->_use_truncation); + 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); @@ -74,7 +67,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); @@ -85,34 +78,36 @@ set_up(const shared_ptr& proj_data_info_sptr, return Succeeded::yes; }*/ -void ProjectorByBinPairUsingNiftyPET::set_verbosity(const bool verbosity) +void +ProjectorByBinPairUsingNiftyPET::set_verbosity(const bool verbosity) { - _verbosity = 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 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); + 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) +void +ProjectorByBinPairUsingNiftyPET::set_use_truncation(const bool use_truncation) { - _use_truncation = 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 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); + 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 3f9f424de..74ae5b6ea 100644 --- a/src/recon_buildblock/PLSPrior.cxx +++ b/src/recon_buildblock/PLSPrior.cxx @@ -52,68 +52,68 @@ PLSPrior::initialise_keymap() this->parser.add_stop_key("END PLS Prior Parameters"); } - template Succeeded -PLSPrior::set_up (shared_ptr > const& target_sptr) +PLSPrior::set_up(shared_ptr> const& target_sptr) { - base_type::set_up(target_sptr); + base_type::set_up(target_sptr); - if (is_null_ptr( this->anatomical_sptr)) + if (is_null_ptr(this->anatomical_sptr)) { - error("PLS prior needs an anatomical image"); + 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) + 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); @@ -129,15 +129,13 @@ 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() @@ -147,542 +145,544 @@ PLSPrior::PLSPrior() template bool -PLSPrior:: -is_convex() const +PLSPrior::is_convex() const { return true; } template PLSPrior::PLSPrior(const bool only_2D_v, float penalisation_factor_v) - : only_2D(only_2D_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; +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; + 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; + 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) +PLSPrior::set_anatomical_image_sptr(const shared_ptr>& arg) { - this->anatomical_sptr = arg; - this->anatomical_filename = ""; // Clear filename in case it was set. + 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 == 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 == 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) +PLSPrior::set_kappa_sptr(const shared_ptr>& k) { - this->kappa_ptr = k; - kappa_filename = ""; // Clear filename in case it was set. + 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) +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 ); + 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) +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 ); + 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 ="<::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]; - } - - } - } - } - + if (z + 1 > 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) +{ + const int min_z = image_grad_x.get_min_index(); + const int max_z = image_grad_x.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 = image_grad_x[z].get_min_index(); - const int max_y = image_grad_x[z].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 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(); - for (int y=min_y;y<= max_y;y++) + for (int x = min_x; x <= max_x; x++) + { + if (only_2D) { - - 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)); - - } - } - - } - } + 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) +{ + if (!only_2D) + compute_image_gradient_element(pet_im_grad_z, 0, pet_image); - const int min_z = pet_image.get_min_index(); - const int max_z = pet_image.get_max_index(); + compute_image_gradient_element(pet_im_grad_y, 1, pet_image); + compute_image_gradient_element(pet_im_grad_x, 2, pet_image); + const int min_z = pet_image.get_min_index(); + const int max_z = pet_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 = pet_image[z].get_min_index(); - const int max_y = pet_image[z].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 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(); - for (int y=min_y;y<= max_y;y++) + for (int x = min_x; x <= max_x; x++) + { + if (only_2D) { - - 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]; - - 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])); - } - } - } - } - + 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])); + } + } + } + } } template double -PLSPrior:: -compute_value(const DiscretisedDensity<3,elemT> ¤t_image_estimate) +PLSPrior::compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate) { - if (this->penalisation_factor==0) - { - return 0.; - } + 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++) + 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 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) - { - prior_gradient.fill(0); - return; - } - - shared_ptr > pet_im_grad_z_sptr; - shared_ptr > gradientz_sptr; + if (this->penalisation_factor == 0) + { + prior_gradient.fill(0); + return; + } - 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_z_sptr; + shared_ptr> gradientz_sptr; - 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 ()); + 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 > inner_product_sptr(this->anatomical_sptr->get_empty_copy ()); - shared_ptr > penalty_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 > gradienty_sptr(this->anatomical_sptr->get_empty_copy ()); - shared_ptr > gradientx_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()); - 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++) + 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 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++) + 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++) + 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 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++) + 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]); - - } - else{ + if (only_2D) + { - (*gradient_sptr)[z][y][x] = -((*gradientz_sptr)[z][y][x] + (*gradienty_sptr)[z][y][x] + (*gradientx_sptr)[z][y][x]); + (*gradient_sptr)[z][y][x] = -((*gradienty_sptr)[z][y][x] + (*gradientx_sptr)[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] ; + (*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) + if (gradient_filename_prefix.size() > 0) { - char *filename = new char[gradient_filename_prefix.size()+100]; + 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/Parallelproj_projector/BackProjectorByBinParallelproj.cxx b/src/recon_buildblock/Parallelproj_projector/BackProjectorByBinParallelproj.cxx index 77291a8d6..6390c226d 100644 --- a/src/recon_buildblock/Parallelproj_projector/BackProjectorByBinParallelproj.cxx +++ b/src/recon_buildblock/Parallelproj_projector/BackProjectorByBinParallelproj.cxx @@ -8,7 +8,7 @@ \author Richard Brown \author Kris Thielemans - + */ /* Copyright (C) 2019, 2021 University College London @@ -31,9 +31,9 @@ #include "stir/LORCoordinates.h" #include "stir/recon_array_functions.h" #ifdef parallelproj_built_with_CUDA -#include "parallelproj_cuda.h" +# include "parallelproj_cuda.h" #else -#include "parallelproj_c.h" +# include "parallelproj_c.h" #endif // for debugging, remove later #include "stir/info.h" @@ -41,28 +41,24 @@ #include "stir/stream.h" #include - START_NAMESPACE_STIR ////////////////////////////////////////////////////////// -const char * const -BackProjectorByBinParallelproj::registered_name = - "Parallelproj"; +const char* const BackProjectorByBinParallelproj::registered_name = "Parallelproj"; -BackProjectorByBinParallelproj::BackProjectorByBinParallelproj() : - _cuda_verbosity(true), _num_gpu_chunks(1) +BackProjectorByBinParallelproj::BackProjectorByBinParallelproj() + : _cuda_verbosity(true), + _num_gpu_chunks(1) { - this->_already_set_up = false; - this->_do_not_setup_helper = false; + this->_already_set_up = false; + this->_do_not_setup_helper = false; } BackProjectorByBinParallelproj::~BackProjectorByBinParallelproj() -{ -} +{} void -BackProjectorByBinParallelproj:: -initialise_keymap() +BackProjectorByBinParallelproj::initialise_keymap() { parser.add_start_key("Back Projector Using Parallelproj Parameters"); parser.add_stop_key("End Back Projector Using Parallelproj Parameters"); @@ -71,14 +67,12 @@ initialise_keymap() } void -BackProjectorByBinParallelproj:: -set_defaults() +BackProjectorByBinParallelproj::set_defaults() { _cuda_verbosity = true; _num_gpu_chunks = 1; } - void BackProjectorByBinParallelproj::set_helper(shared_ptr helper) { @@ -87,25 +81,22 @@ BackProjectorByBinParallelproj::set_helper(shared_ptr& proj_data_info_sptr, - const shared_ptr >& density_info_sptr) +BackProjectorByBinParallelproj::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)); + 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)); - // Create sinogram - _proj_data_to_backproject_sptr.reset( - new ProjDataInMemory(this->_density_sptr->get_exam_info_sptr(), proj_data_info_sptr)); + // Create sinogram + _proj_data_to_backproject_sptr.reset(new ProjDataInMemory(this->_density_sptr->get_exam_info_sptr(), proj_data_info_sptr)); - if (!this->_do_not_setup_helper) - _helper = std::make_shared(*proj_data_info_sptr, *density_info_sptr); + if (!this->_do_not_setup_helper) + _helper = std::make_shared(*proj_data_info_sptr, *density_info_sptr); } -const DataSymmetriesForViewSegmentNumbers * -BackProjectorByBinParallelproj:: -get_symmetries_used() const +const DataSymmetriesForViewSegmentNumbers* +BackProjectorByBinParallelproj::get_symmetries_used() const { if (!this->_already_set_up) error("BackProjectorByBin method called without calling set_up first."); @@ -126,42 +117,44 @@ back_project(const ProjData& proj_data, int subset_num, int num_subsets) #endif void -BackProjectorByBinParallelproj:: -get_output(DiscretisedDensity<3,float> &density) const +BackProjectorByBinParallelproj::get_output(DiscretisedDensity<3, float>& density) const { - std::vector image_vec(density.size_all()); - // create an alias for the projection data - const ProjDataInMemory& p(*_proj_data_to_backproject_sptr); + std::vector image_vec(density.size_all()); + // create an alias for the projection data + const ProjDataInMemory& p(*_proj_data_to_backproject_sptr); - info("Calling parallelproj backprojector", 2); + info("Calling parallelproj backprojector", 2); #ifdef parallelproj_built_with_CUDA - long long num_image_voxel = static_cast(image_vec.size()); - long long num_lors = static_cast(p.get_proj_data_info_sptr()->size_all()); - - long long num_lors_per_chunk_floor = num_lors / _num_gpu_chunks; - long long remainder = num_lors % _num_gpu_chunks; - - long long num_lors_per_chunk; - long long offset = 0; - - // send image to all visible CUDA devices - float** image_on_cuda_devices; - image_on_cuda_devices = copy_float_array_to_all_devices(image_vec.data(), num_image_voxel); - - // do (chuck-wise) back projection on the CUDA devices - for(int chunk_num = 0; chunk_num < _num_gpu_chunks; chunk_num++){ - if(chunk_num < remainder){ - num_lors_per_chunk = num_lors_per_chunk_floor + 1; - } - else{ - num_lors_per_chunk = num_lors_per_chunk_floor; - } - - joseph3d_back_cuda(_helper->xstart.data() + 3*offset, - _helper->xend.data() + 3*offset, + long long num_image_voxel = static_cast(image_vec.size()); + long long num_lors = static_cast(p.get_proj_data_info_sptr()->size_all()); + + long long num_lors_per_chunk_floor = num_lors / _num_gpu_chunks; + long long remainder = num_lors % _num_gpu_chunks; + + long long num_lors_per_chunk; + long long offset = 0; + + // send image to all visible CUDA devices + float** image_on_cuda_devices; + image_on_cuda_devices = copy_float_array_to_all_devices(image_vec.data(), num_image_voxel); + + // do (chuck-wise) back projection on the CUDA devices + for (int chunk_num = 0; chunk_num < _num_gpu_chunks; chunk_num++) + { + if (chunk_num < remainder) + { + num_lors_per_chunk = num_lors_per_chunk_floor + 1; + } + else + { + num_lors_per_chunk = num_lors_per_chunk_floor; + } + + joseph3d_back_cuda(_helper->xstart.data() + 3 * offset, + _helper->xend.data() + 3 * offset, image_on_cuda_devices, _helper->origin.data(), _helper->voxsize.data(), @@ -173,65 +166,65 @@ get_output(DiscretisedDensity<3,float> &density) const offset += num_lors_per_chunk; } - // sum backprojected images on the first CUDA device - sum_float_arrays_on_first_device(image_on_cuda_devices, num_image_voxel); + // sum backprojected images on the first CUDA device + sum_float_arrays_on_first_device(image_on_cuda_devices, num_image_voxel); - // copy summed image back to host - get_float_array_from_device(image_on_cuda_devices, num_image_voxel, 0, image_vec.data()); + // copy summed image back to host + get_float_array_from_device(image_on_cuda_devices, num_image_voxel, 0, image_vec.data()); - // free image array from CUDA devices - free_float_array_on_all_devices(image_on_cuda_devices); + // free image array from CUDA devices + free_float_array_on_all_devices(image_on_cuda_devices); #else - joseph3d_back(_helper->xstart.data(), - _helper->xend.data(), - image_vec.data(), - _helper->origin.data(), - _helper->voxsize.data(), - p.get_const_data_ptr(), - static_cast(p.get_proj_data_info_sptr()->size_all()), - _helper->imgdim.data()); + joseph3d_back(_helper->xstart.data(), + _helper->xend.data(), + image_vec.data(), + _helper->origin.data(), + _helper->voxsize.data(), + p.get_const_data_ptr(), + static_cast(p.get_proj_data_info_sptr()->size_all()), + _helper->imgdim.data()); #endif - info("done", 2); - - p.release_const_data_ptr(); - - // --------------------------------------------------------------- // - // Parallelproj -> STIR image conversion - // --------------------------------------------------------------- // - std::copy(image_vec.begin(), image_vec.end(), density.begin_all()); - - // After the back projection, we enforce a truncation outside of the FOV. - // This is because the parallelproj projector seems to have some trouble at the edges and this - // could cause some voxel values to spiral out of control. - //if (_use_truncation) - { - const float radius = p.get_proj_data_info_sptr()->get_scanner_sptr()->get_inner_ring_radius(); - const float image_radius = _helper->voxsize[2]*_helper->imgdim[2]/2; - truncate_rim(density, static_cast(std::max((image_radius-radius) / _helper->voxsize[2],0.F))); - } + info("done", 2); + + p.release_const_data_ptr(); + + // --------------------------------------------------------------- // + // Parallelproj -> STIR image conversion + // --------------------------------------------------------------- // + std::copy(image_vec.begin(), image_vec.end(), density.begin_all()); + + // After the back projection, we enforce a truncation outside of the FOV. + // This is because the parallelproj projector seems to have some trouble at the edges and this + // could cause some voxel values to spiral out of control. + // if (_use_truncation) + { + const float radius = p.get_proj_data_info_sptr()->get_scanner_sptr()->get_inner_ring_radius(); + const float image_radius = _helper->voxsize[2] * _helper->imgdim[2] / 2; + truncate_rim(density, static_cast(std::max((image_radius - radius) / _helper->voxsize[2], 0.F))); + } } void -BackProjectorByBinParallelproj:: -start_accumulating_in_new_target() +BackProjectorByBinParallelproj::start_accumulating_in_new_target() { - // Call base level - BackProjectorByBin::start_accumulating_in_new_target(); - // reset the Parallelproj sinogram - _proj_data_to_backproject_sptr->fill(0.F); + // Call base level + BackProjectorByBin::start_accumulating_in_new_target(); + // reset the Parallelproj sinogram + _proj_data_to_backproject_sptr->fill(0.F); } void -BackProjectorByBinParallelproj:: -actual_back_project(const RelatedViewgrams& related_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) +BackProjectorByBinParallelproj::actual_back_project(const RelatedViewgrams& related_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 ((min_axial_pos_num != this->_proj_data_info_sptr->get_min_axial_pos_num(related_viewgrams.get_basic_segment_num())) || - (max_axial_pos_num != this->_proj_data_info_sptr->get_max_axial_pos_num(related_viewgrams.get_basic_segment_num())) || - (min_tangential_pos_num != this->_proj_data_info_sptr->get_min_tangential_pos_num()) || - (max_tangential_pos_num != this->_proj_data_info_sptr->get_max_tangential_pos_num())) + if ((min_axial_pos_num != this->_proj_data_info_sptr->get_min_axial_pos_num(related_viewgrams.get_basic_segment_num())) + || (max_axial_pos_num != this->_proj_data_info_sptr->get_max_axial_pos_num(related_viewgrams.get_basic_segment_num())) + || (min_tangential_pos_num != this->_proj_data_info_sptr->get_min_tangential_pos_num()) + || (max_tangential_pos_num != this->_proj_data_info_sptr->get_max_tangential_pos_num())) error("STIR wrapping of Parallelproj projectors current only handles projecting all data"); _proj_data_to_backproject_sptr->set_related_viewgrams(related_viewgrams); diff --git a/src/recon_buildblock/Parallelproj_projector/ForwardProjectorByBinParallelproj.cxx b/src/recon_buildblock/Parallelproj_projector/ForwardProjectorByBinParallelproj.cxx index 020a84e25..9c37632c9 100644 --- a/src/recon_buildblock/Parallelproj_projector/ForwardProjectorByBinParallelproj.cxx +++ b/src/recon_buildblock/Parallelproj_projector/ForwardProjectorByBinParallelproj.cxx @@ -29,32 +29,30 @@ #include "stir/error.h" #include "stir/recon_array_functions.h" #ifdef parallelproj_built_with_CUDA -#include "parallelproj_cuda.h" +# include "parallelproj_cuda.h" #else -#include "parallelproj_c.h" +# include "parallelproj_c.h" #endif START_NAMESPACE_STIR ////////////////////////////////////////////////////////// -const char * const -ForwardProjectorByBinParallelproj::registered_name = - "Parallelproj"; +const char* const ForwardProjectorByBinParallelproj::registered_name = "Parallelproj"; -ForwardProjectorByBinParallelproj::ForwardProjectorByBinParallelproj() : - _cuda_verbosity(true), _use_truncation(true), _num_gpu_chunks(1) +ForwardProjectorByBinParallelproj::ForwardProjectorByBinParallelproj() + : _cuda_verbosity(true), + _use_truncation(true), + _num_gpu_chunks(1) { - this->_already_set_up = false; - this->_do_not_setup_helper = false; + this->_already_set_up = false; + this->_do_not_setup_helper = false; } ForwardProjectorByBinParallelproj::~ForwardProjectorByBinParallelproj() -{ -} +{} void -ForwardProjectorByBinParallelproj:: -initialise_keymap() +ForwardProjectorByBinParallelproj::initialise_keymap() { parser.add_start_key("Forward Projector Using Parallelproj Parameters"); parser.add_stop_key("End Forward Projector Using Parallelproj Parameters"); @@ -63,15 +61,13 @@ initialise_keymap() } void -ForwardProjectorByBinParallelproj:: -set_defaults() +ForwardProjectorByBinParallelproj::set_defaults() { _cuda_verbosity = true; _use_truncation = true; _num_gpu_chunks = 1; } - void ForwardProjectorByBinParallelproj::set_helper(shared_ptr helper) { @@ -80,13 +76,12 @@ ForwardProjectorByBinParallelproj::set_helper(shared_ptr& proj_data_info_sptr, - const shared_ptr >& density_info_sptr) +ForwardProjectorByBinParallelproj::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)); + 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)); #if 0 shared_ptr @@ -95,18 +90,15 @@ set_up(const shared_ptr& proj_data_info_sptr, proj_data_info_sptr)); if (is_null_ptr(proj_data_info_cy_no_ar_cor_sptr)) error("ForwardProjectorByBinParallelproj: Failed casting to ProjDataInfoCylindricalNoArcCorr"); -#endif - // 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)); - if (!this->_do_not_setup_helper) - _helper = std::make_shared(*proj_data_info_sptr, *density_info_sptr); - +#endif + // 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)); + if (!this->_do_not_setup_helper) + _helper = std::make_shared(*proj_data_info_sptr, *density_info_sptr); } -const DataSymmetriesForViewSegmentNumbers * -ForwardProjectorByBinParallelproj:: -get_symmetries_used() const +const DataSymmetriesForViewSegmentNumbers* +ForwardProjectorByBinParallelproj::get_symmetries_used() const { if (!this->_already_set_up) error("ForwardProjectorByBin method called without calling set_up first."); @@ -114,72 +106,74 @@ get_symmetries_used() const } void -ForwardProjectorByBinParallelproj:: -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) +ForwardProjectorByBinParallelproj::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 ((min_axial_pos_num != this->_proj_data_info_sptr->get_min_axial_pos_num(viewgrams.get_basic_segment_num())) || - (max_axial_pos_num != this->_proj_data_info_sptr->get_max_axial_pos_num(viewgrams.get_basic_segment_num())) || - (min_tangential_pos_num != this->_proj_data_info_sptr->get_min_tangential_pos_num()) || - (max_tangential_pos_num != this->_proj_data_info_sptr->get_max_tangential_pos_num())) + if ((min_axial_pos_num != this->_proj_data_info_sptr->get_min_axial_pos_num(viewgrams.get_basic_segment_num())) + || (max_axial_pos_num != this->_proj_data_info_sptr->get_max_axial_pos_num(viewgrams.get_basic_segment_num())) + || (min_tangential_pos_num != this->_proj_data_info_sptr->get_min_tangential_pos_num()) + || (max_tangential_pos_num != this->_proj_data_info_sptr->get_max_tangential_pos_num())) error("STIR wrapping of Parallelproj projectors current only handles projecting all data"); - viewgrams = _projected_data_sptr->get_related_viewgrams( - viewgrams.get_basic_view_segment_num(), _symmetries_sptr); + viewgrams = _projected_data_sptr->get_related_viewgrams(viewgrams.get_basic_view_segment_num(), _symmetries_sptr); } void -ForwardProjectorByBinParallelproj:: -set_input(const DiscretisedDensity<3,float> & density) +ForwardProjectorByBinParallelproj::set_input(const DiscretisedDensity<3, float>& density) { - ForwardProjectorByBin::set_input(density); + ForwardProjectorByBin::set_input(density); - // Before forward projection, we enforce a truncation outside of the FOV. - // This is because the parallelproj projector seems to have some trouble at the edges and this - // could cause some voxel values to spiral out of control. - //if (_use_truncation) - { - const float radius = this->_proj_data_info_sptr->get_scanner_sptr()->get_inner_ring_radius(); - const float image_radius = _helper->voxsize[2]*_helper->imgdim[2]/2; - truncate_rim(*_density_sptr, static_cast(std::max((image_radius-radius) / _helper->voxsize[2],0.F))); - } + // Before forward projection, we enforce a truncation outside of the FOV. + // This is because the parallelproj projector seems to have some trouble at the edges and this + // could cause some voxel values to spiral out of control. + // if (_use_truncation) + { + const float radius = this->_proj_data_info_sptr->get_scanner_sptr()->get_inner_ring_radius(); + const float image_radius = _helper->voxsize[2] * _helper->imgdim[2] / 2; + truncate_rim(*_density_sptr, static_cast(std::max((image_radius - radius) / _helper->voxsize[2], 0.F))); + } - std::vector image_vec(density.size_all()); - std::copy(_density_sptr->begin_all(), _density_sptr->end_all(), image_vec.begin()); + std::vector image_vec(density.size_all()); + std::copy(_density_sptr->begin_all(), _density_sptr->end_all(), image_vec.begin()); #if 0 // needed to set output to zero as parallelproj accumulates but is no longer the case _projected_data_sptr->fill(0.F); #endif - info("Calling parallelproj forward",2); + info("Calling parallelproj forward", 2); #ifdef parallelproj_built_with_CUDA - long long num_image_voxel = static_cast(image_vec.size()); - long long num_lors = static_cast(_projected_data_sptr->get_proj_data_info_sptr()->size_all()); - - long long num_lors_per_chunk_floor = num_lors / _num_gpu_chunks; - long long remainder = num_lors % _num_gpu_chunks; - - long long num_lors_per_chunk; - long long offset = 0; - - // send image to all visible CUDA devices - float** image_on_cuda_devices; - image_on_cuda_devices = copy_float_array_to_all_devices(image_vec.data(), num_image_voxel); - - // do (chuck-wise) projection on the CUDA devices - for(int chunk_num = 0; chunk_num < _num_gpu_chunks; chunk_num++){ - if(chunk_num < remainder){ - num_lors_per_chunk = num_lors_per_chunk_floor + 1; - } - else{ - num_lors_per_chunk = num_lors_per_chunk_floor; - } - - joseph3d_fwd_cuda(_helper->xstart.data() + 3*offset, - _helper->xend.data() + 3*offset, + long long num_image_voxel = static_cast(image_vec.size()); + long long num_lors = static_cast(_projected_data_sptr->get_proj_data_info_sptr()->size_all()); + + long long num_lors_per_chunk_floor = num_lors / _num_gpu_chunks; + long long remainder = num_lors % _num_gpu_chunks; + + long long num_lors_per_chunk; + long long offset = 0; + + // send image to all visible CUDA devices + float** image_on_cuda_devices; + image_on_cuda_devices = copy_float_array_to_all_devices(image_vec.data(), num_image_voxel); + + // do (chuck-wise) projection on the CUDA devices + for (int chunk_num = 0; chunk_num < _num_gpu_chunks; chunk_num++) + { + if (chunk_num < remainder) + { + num_lors_per_chunk = num_lors_per_chunk_floor + 1; + } + else + { + num_lors_per_chunk = num_lors_per_chunk_floor; + } + + joseph3d_fwd_cuda(_helper->xstart.data() + 3 * offset, + _helper->xend.data() + 3 * offset, image_on_cuda_devices, _helper->origin.data(), _helper->voxsize.data(), @@ -191,22 +185,22 @@ set_input(const DiscretisedDensity<3,float> & density) offset += num_lors_per_chunk; } - // free image array from CUDA devices - free_float_array_on_all_devices(image_on_cuda_devices); + // free image array from CUDA devices + free_float_array_on_all_devices(image_on_cuda_devices); #else - joseph3d_fwd(_helper->xstart.data(), - _helper->xend.data(), - image_vec.data(), - _helper->origin.data(), - _helper->voxsize.data(), - _projected_data_sptr->get_data_ptr(), - static_cast(_projected_data_sptr->get_proj_data_info_sptr()->size_all()), - _helper->imgdim.data()); + joseph3d_fwd(_helper->xstart.data(), + _helper->xend.data(), + image_vec.data(), + _helper->origin.data(), + _helper->voxsize.data(), + _projected_data_sptr->get_data_ptr(), + static_cast(_projected_data_sptr->get_proj_data_info_sptr()->size_all()), + _helper->imgdim.data()); #endif - info("done", 2); + info("done", 2); - _projected_data_sptr->release_data_ptr(); + _projected_data_sptr->release_data_ptr(); } END_NAMESPACE_STIR diff --git a/src/recon_buildblock/Parallelproj_projector/ParallelprojHelper.cxx b/src/recon_buildblock/Parallelproj_projector/ParallelprojHelper.cxx index 8c90bf24f..beddaace3 100644 --- a/src/recon_buildblock/Parallelproj_projector/ParallelprojHelper.cxx +++ b/src/recon_buildblock/Parallelproj_projector/ParallelprojHelper.cxx @@ -7,7 +7,7 @@ \brief non-inline implementations for stir::ParallelprojHelper \author Kris Thielemans - + */ /* Copyright (C) 2021, 2023 University College London @@ -33,60 +33,61 @@ START_NAMESPACE_STIR detail::ParallelprojHelper::~ParallelprojHelper() -{ -} +{} template -static inline void copy_to_array(const BasicCoordinate<3,T>& c, std::array& a) +static inline void +copy_to_array(const BasicCoordinate<3, T>& c, std::array& a) { std::copy(c.begin(), c.end(), a.begin()); } -detail::ParallelprojHelper::ParallelprojHelper(const ProjDataInfo& p_info, const DiscretisedDensity<3,float> &density) : - xstart(p_info.size_all()*3), - xend(p_info.size_all()*3) +detail::ParallelprojHelper::ParallelprojHelper(const ProjDataInfo& p_info, const DiscretisedDensity<3, float>& density) + : xstart(p_info.size_all() * 3), + xend(p_info.size_all() * 3) { info("Creating parallelproj data-structures", 2); auto& stir_image = dynamic_cast&>(density); - + auto stir_voxel_size = stir_image.get_voxel_size(); #ifndef NEWSCALE // parallelproj projectors work in units of the voxel_size passed. // STIR projectors have to be in pixel units, so convert the voxel-size - const float rescale = 1/stir_voxel_size[3]; + const float rescale = 1 / stir_voxel_size[3]; #else const float rescale = 1.F; #endif - copy_to_array(stir_voxel_size*rescale, voxsize); + copy_to_array(stir_voxel_size * rescale, voxsize); copy_to_array(stir_image.get_lengths(), imgdim); - BasicCoordinate<3,int> min_indices, max_indices; + BasicCoordinate<3, int> min_indices, max_indices; stir_image.get_regular_range(min_indices, max_indices); auto coord_first_voxel = stir_image.get_physical_coordinates_for_indices(min_indices); // TODO origin shift get_LOR() uses the "centred w.r.t. gantry" coordinate system - coord_first_voxel[1] -= (stir_image.get_min_index() + stir_image.get_max_index())/2.F * stir_voxel_size[1]; - copy_to_array(coord_first_voxel*rescale, origin); + coord_first_voxel[1] -= (stir_image.get_min_index() + stir_image.get_max_index()) / 2.F * stir_voxel_size[1]; + copy_to_array(coord_first_voxel * rescale, origin); // loop over all LORs in the projdata const float radius = p_info.get_scanner_sptr()->get_max_FOV_radius(); - // warning: next loop needs to be the same as how ProjDataInMemory stores its data. There is no guarantee that this will remain the case in the future. + // warning: next loop needs to be the same as how ProjDataInMemory stores its data. There is no guarantee that this will remain + // the case in the future. const auto segment_sequence = ProjData::standard_segment_sequence(p_info); std::size_t index(0); #ifdef STIR_OPENMP // Using too many threads is counterproductive according to my timings, so I limited to 8 (not necessarily optimal!). - const auto num_threads_to_use = std::min(8,get_max_num_threads()); -# if _OPENMP >=201012 -# define ATOMICWRITE _Pragma("omp atomic write") \ + const auto num_threads_to_use = std::min(8, get_max_num_threads()); +# if _OPENMP >= 201012 +# define ATOMICWRITE _Pragma("omp atomic write") # define CRITICALSECTION # else # define ATOMICWRITE # if defined(_MSC_VER) && (_MSC_VER < 1910) - // no _Pragma until VS 2017 + // no _Pragma until VS 2017 # define CRITICALSECTION # else # define CRITICALSECTION _Pragma("omp critical(PARALLELPROJHELPER_INIT)") @@ -98,14 +99,17 @@ detail::ParallelprojHelper::ParallelprojHelper(const ProjDataInfo& p_info, const #endif for (int seg : segment_sequence) { - for (int axial_pos_num = p_info.get_min_axial_pos_num(seg); axial_pos_num <= p_info.get_max_axial_pos_num(seg); ++axial_pos_num) + for (int axial_pos_num = p_info.get_min_axial_pos_num(seg); axial_pos_num <= p_info.get_max_axial_pos_num(seg); + ++axial_pos_num) { for (int view_num = p_info.get_min_view_num(); view_num <= p_info.get_max_view_num(); ++view_num) { #ifdef STIR_OPENMP - #pragma omp parallel for num_threads(num_threads_to_use) +# pragma omp parallel for num_threads(num_threads_to_use) #endif - for (int tangential_pos_num = p_info.get_min_tangential_pos_num(); tangential_pos_num <= p_info.get_max_tangential_pos_num(); ++tangential_pos_num) + for (int tangential_pos_num = p_info.get_min_tangential_pos_num(); + tangential_pos_num <= p_info.get_max_tangential_pos_num(); + ++tangential_pos_num) { Bin bin; bin.segment_num() = seg; @@ -113,7 +117,7 @@ detail::ParallelprojHelper::ParallelprojHelper(const ProjDataInfo& p_info, const bin.view_num() = view_num; bin.tangential_pos_num() = tangential_pos_num; // compute index for this bin (independent of multi-threading) - const std::size_t this_index = index + (bin.tangential_pos_num() - p_info.get_min_tangential_pos_num())*3; + const std::size_t this_index = index + (bin.tangential_pos_num() - p_info.get_min_tangential_pos_num()) * 3; LORInAxialAndNoArcCorrSinogramCoordinates lor; LORAs2Points lor_points; @@ -122,31 +126,31 @@ detail::ParallelprojHelper::ParallelprojHelper(const ProjDataInfo& p_info, const { // memory is already allocated, so just passing in points that will produce nothing CRITICALSECTION - { - ATOMICWRITE xstart[this_index] = 0; - ATOMICWRITE xend[this_index] = 0; - ATOMICWRITE xstart[this_index+1] = 0; - ATOMICWRITE xend[this_index+1] = 0; - ATOMICWRITE xstart[this_index+2] = 0; - ATOMICWRITE xend[this_index+2] = 0; - } - } + { + ATOMICWRITE xstart[this_index] = 0; + ATOMICWRITE xend[this_index] = 0; + ATOMICWRITE xstart[this_index + 1] = 0; + ATOMICWRITE xend[this_index + 1] = 0; + ATOMICWRITE xstart[this_index + 2] = 0; + ATOMICWRITE xend[this_index + 2] = 0; + } + } else - { - const auto p1 = lor_points.p1()*rescale; - const auto p2 = lor_points.p2()*rescale; - CRITICALSECTION + { + const auto p1 = lor_points.p1() * rescale; + const auto p2 = lor_points.p2() * rescale; + CRITICALSECTION { ATOMICWRITE xstart[this_index] = p1[1]; ATOMICWRITE xend[this_index] = p2[1]; - ATOMICWRITE xstart[this_index+1] = p1[2]; - ATOMICWRITE xend[this_index+1] = p2[2]; - ATOMICWRITE xstart[this_index+2] = p1[3]; - ATOMICWRITE xend[this_index+2] = p2[3]; + ATOMICWRITE xstart[this_index + 1] = p1[2]; + ATOMICWRITE xend[this_index + 1] = p2[2]; + ATOMICWRITE xstart[this_index + 2] = p1[3]; + ATOMICWRITE xend[this_index + 2] = p2[3]; } - } + } } - index += p_info.get_num_tangential_poss()*3; + index += p_info.get_num_tangential_poss() * 3; } } } @@ -154,5 +158,4 @@ detail::ParallelprojHelper::ParallelprojHelper(const ProjDataInfo& p_info, const info("done", 2); } - END_NAMESPACE_STIR diff --git a/src/recon_buildblock/Parallelproj_projector/ProjectorByBinPairUsingParallelproj.cxx b/src/recon_buildblock/Parallelproj_projector/ProjectorByBinPairUsingParallelproj.cxx index 8ecf0d71b..ea35717f3 100644 --- a/src/recon_buildblock/Parallelproj_projector/ProjectorByBinPairUsingParallelproj.cxx +++ b/src/recon_buildblock/Parallelproj_projector/ProjectorByBinPairUsingParallelproj.cxx @@ -3,10 +3,10 @@ \ingroup Parallelproj \brief non-inline implementations for stir::ProjectorByBinPairUsingParallelproj - + \author Richard Brown \author Kris Thielemans - + */ /* Copyright (C) 2019, 2021 University College London @@ -17,7 +17,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/Parallelproj_projector/ProjectorByBinPairUsingParallelproj.h" #include "stir/recon_buildblock/Parallelproj_projector/ForwardProjectorByBinParallelproj.h" #include "stir/recon_buildblock/Parallelproj_projector/BackProjectorByBinParallelproj.h" @@ -26,22 +25,17 @@ START_NAMESPACE_STIR +const char* const ProjectorByBinPairUsingParallelproj::registered_name = "Parallelproj"; -const char * const -ProjectorByBinPairUsingParallelproj::registered_name = - "Parallelproj"; - - -void +void ProjectorByBinPairUsingParallelproj::initialise_keymap() { base_type::initialise_keymap(); parser.add_start_key("Projector Pair Using Parallelproj Parameters"); parser.add_stop_key("End Projector Pair Using Parallelproj Parameters"); - parser.add_key("verbosity",&_verbosity); + parser.add_key("verbosity", &_verbosity); } - void ProjectorByBinPairUsingParallelproj::set_defaults() { @@ -52,15 +46,14 @@ ProjectorByBinPairUsingParallelproj::set_defaults() bool ProjectorByBinPairUsingParallelproj::post_processing() { - this->set_verbosity(this->_verbosity); + this->set_verbosity(this->_verbosity); if (base_type::post_processing()) return true; return false; } -ProjectorByBinPairUsingParallelproj:: -ProjectorByBinPairUsingParallelproj() +ProjectorByBinPairUsingParallelproj::ProjectorByBinPairUsingParallelproj() { this->forward_projector_sptr.reset(new ForwardProjectorByBinParallelproj); this->back_projector_sptr.reset(new BackProjectorByBinParallelproj); @@ -68,22 +61,18 @@ ProjectorByBinPairUsingParallelproj() } BackProjectorByBinParallelproj* -BackProjectorByBinParallelproj:: -clone() const +BackProjectorByBinParallelproj::clone() const { - return new BackProjectorByBinParallelproj(*this); + return new BackProjectorByBinParallelproj(*this); } Succeeded -ProjectorByBinPairUsingParallelproj:: -set_up(const shared_ptr& proj_data_info_sptr, - const shared_ptr >& image_info_sptr) +ProjectorByBinPairUsingParallelproj::set_up(const shared_ptr& proj_data_info_sptr, + const shared_ptr>& image_info_sptr) { _helper = std::make_shared(*proj_data_info_sptr, *image_info_sptr); - dynamic_pointer_cast(this->forward_projector_sptr) - ->set_helper(_helper); - dynamic_pointer_cast(this->back_projector_sptr) - ->set_helper(_helper); + dynamic_pointer_cast(this->forward_projector_sptr)->set_helper(_helper); + dynamic_pointer_cast(this->back_projector_sptr)->set_helper(_helper); // the forward_projector->set_up etc will be called in the base class @@ -93,20 +82,20 @@ set_up(const shared_ptr& proj_data_info_sptr, return Succeeded::yes; } -void ProjectorByBinPairUsingParallelproj::set_verbosity(const bool verbosity) +void +ProjectorByBinPairUsingParallelproj::set_verbosity(const bool verbosity) { - _verbosity = 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 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); + 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); } - END_NAMESPACE_STIR diff --git a/src/recon_buildblock/PinholeSPECTUB_Tools.cxx b/src/recon_buildblock/PinholeSPECTUB_Tools.cxx index 866fac2ad..1098d522c 100644 --- a/src/recon_buildblock/PinholeSPECTUB_Tools.cxx +++ b/src/recon_buildblock/PinholeSPECTUB_Tools.cxx @@ -13,7 +13,7 @@ \author Matthew Strugari */ -//system libraries +// system libraries #include #include #include @@ -31,7 +31,7 @@ #include #include -//user defined libraries +// user defined libraries #include "stir/recon_buildblock/PinholeSPECTUB_Tools.h" #include "stir/recon_buildblock/PinholeSPECTUB_Weight3d.h" @@ -46,60 +46,64 @@ namespace SPECTUB_mph #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)) + //#ifndef M_PI //#define M_PI 3.141592653589793 //#endif //#define dg2rd 0.01745329251994 -float dg2rd = boost::math::constants::pi() / (float)180. ; - -#define DELIMITER1 '#' //delimiter character in input parameter text file -#define DELIMITER2 '%' //delimiter character in input parameter text file +float dg2rd = boost::math::constants::pi() / (float)180.; +#define DELIMITER1 '#' // delimiter character in input parameter text file +#define DELIMITER2 '%' // delimiter character in input parameter text file //============================================================================= //=== wm_alloc ============================================================= //============================================================================= -void wm_alloc( int * Nitems, wm_da_type &wm, wmh_mph_type &wmh ) +void +wm_alloc(int* Nitems, wm_da_type& wm, wmh_mph_type& wmh) { - //... double array wm.val and wm.col ..................................................... - - //if ( ( wm.val = new (nothrow) float * [ wmh.prj.NbOS ] ) == NULL ) error_wmtools_SPECT_mph( 200, wmh.prj.NbOS, "wm.val[]" ); - //if ( ( wm.col = new (nothrow) int * [ wmh.prj.NbOS ] ) == NULL ) error_wmtools_SPECT_mph( 200, wmh.prj.NbOS, "wm.col[]" ); - - //... array wm.ne ......................................................................... - - //if ( ( wm.ne = new (nothrow) int [ wmh.prj.NbOS + 1 ] ) == 0 ) error_wmtools_SPECT_mph(200, wmh.prj.NbOS + 1, "wm.ne[]"); + //... double array wm.val and wm.col ..................................................... - - //... memory allocation for wm double arrays ................................... - - for( int i = 0 ; i < wmh.prj.NbOS ; i++ ){ - - if ( ( wm.val[ i ] = new (nothrow) float [ Nitems[ i ] ]) == NULL ) error_wmtools_SPECT_mph( 200, Nitems[ i ], "wm.val[][]" ); - if ( ( wm.col[ i ] = new (nothrow) int [ Nitems[ i ] ]) == NULL ) error_wmtools_SPECT_mph( 200, Nitems[ i ], "wm.col[][]" ); + // if ( ( wm.val = new (nothrow) float * [ wmh.prj.NbOS ] ) == NULL ) error_wmtools_SPECT_mph( 200, wmh.prj.NbOS, "wm.val[]" ); + // if ( ( wm.col = new (nothrow) int * [ wmh.prj.NbOS ] ) == NULL ) error_wmtools_SPECT_mph( 200, wmh.prj.NbOS, "wm.col[]" ); + + //... array wm.ne ......................................................................... + + // if ( ( wm.ne = new (nothrow) int [ wmh.prj.NbOS + 1 ] ) == 0 ) error_wmtools_SPECT_mph(200, wmh.prj.NbOS + 1, "wm.ne[]"); + + //... memory allocation for wm double arrays ................................... + + for (int i = 0; i < wmh.prj.NbOS; i++) + { + + if ((wm.val[i] = new (nothrow) float[Nitems[i]]) == NULL) + error_wmtools_SPECT_mph(200, Nitems[i], "wm.val[][]"); + if ((wm.col[i] = new (nothrow) int[Nitems[i]]) == NULL) + error_wmtools_SPECT_mph(200, Nitems[i], "wm.col[][]"); } - - //... to initialize wm to zero ...................... - - for ( int i = 0 ; i < wmh.prj.NbOS ; i++ ){ - - wm.ne[ i ] = 0; - - for( int j = 0 ; j < Nitems[ i ] ; j++ ){ - - wm.val[ i ][ j ] = (float)0.; - wm.col[ i ][ j ] = 0; + + //... to initialize wm to zero ...................... + + for (int i = 0; i < wmh.prj.NbOS; i++) + { + + wm.ne[i] = 0; + + for (int j = 0; j < Nitems[i]; j++) + { + + wm.val[i][j] = (float)0.; + wm.col[i][j] = 0; } } - wm.ne[ wmh.prj.NbOS ] = 0; + wm.ne[wmh.prj.NbOS] = 0; } //============================================================================= @@ -272,140 +276,161 @@ void write_wm_STIR_mph() //=== precalculated functions =============================================== //============================================================================== -void fill_pcf( wmh_mph_type &wmh, pcf_type &pcf ) +void +fill_pcf(wmh_mph_type& wmh, pcf_type& pcf) { - - //... distribution function for a round shape hole ................. - - if ( wmh.do_round_cumsum ){ - - float lngcmd2 = (float) 0.5 ; - - float d1, d2_2, d2; - - pcf.round.res = wmh.highres; - int dimd2 = (int) floorf ( lngcmd2 / pcf.round.res ) + 2 ; // add 2 to have at least one column of zeros as margin - pcf.round.dim = dimd2 * 2 ; // length of the density function (in resolution elements). even number - lngcmd2 += (float)2. * pcf.round.res ; // center of the function - - pcf.round.val = new float * [ pcf.round.dim ]; // density function allocation - - for (int j = 0 ; j < pcf.round.dim ; j++){ - - pcf.round.val[ j ] = new float [ pcf.round.dim ]; - - d2 = (float) j * pcf.round.res - lngcmd2 ; - d2_2 = d2 * d2 ; - - for ( int i = 0 ; i < pcf.round.dim; i++) { - - d1 = (float) i * pcf.round.res - lngcmd2 ; - - if ( sqrtf ( d2_2 + d1 * d1 ) <= (float)0.5 ) pcf.round.val[ j ][ i ] = (float) 1.; - else pcf.round.val[ j ][ i ] = (float) 0.; + + //... distribution function for a round shape hole ................. + + if (wmh.do_round_cumsum) + { + + float lngcmd2 = (float)0.5; + + float d1, d2_2, d2; + + pcf.round.res = wmh.highres; + int dimd2 = (int)floorf(lngcmd2 / pcf.round.res) + 2; // add 2 to have at least one column of zeros as margin + pcf.round.dim = dimd2 * 2; // length of the density function (in resolution elements). even number + lngcmd2 += (float)2. * pcf.round.res; // center of the function + + pcf.round.val = new float*[pcf.round.dim]; // density function allocation + + for (int j = 0; j < pcf.round.dim; j++) + { + + pcf.round.val[j] = new float[pcf.round.dim]; + + d2 = (float)j * pcf.round.res - lngcmd2; + d2_2 = d2 * d2; + + for (int i = 0; i < pcf.round.dim; i++) + { + + d1 = (float)i * pcf.round.res - lngcmd2; + + if (sqrtf(d2_2 + d1 * d1) <= (float)0.5) + pcf.round.val[j][i] = (float)1.; + else + pcf.round.val[j][i] = (float)0.; } } - - calc_cumsum( &pcf.round ); - //cout << "\n\tLength of pcf.round density function: " << pcf.round.dim << endl; + calc_cumsum(&pcf.round); + + // cout << "\n\tLength of pcf.round density function: " << pcf.round.dim << endl; } - - //... distribution function for a square shape hole ................... - - if ( wmh.do_square_cumsum ){ - - float lngcmd2 = (float) 0.5 ; - - float d1, d2; - - pcf.square.res = wmh.highres; - - int dimd2 = (int) floorf ( lngcmd2 / pcf.square.res ) + 2 ; // add 2 to have at least one column of zeros as margin - pcf.square.dim = dimd2 * 2 ; // length of the density function (in resolution elements). even number - lngcmd2 += (float)2. * pcf.square.res ; // center of the function - - pcf.square.val = new float * [ pcf.square.dim ]; // density function allocation - - for ( int j = 0 ; j < pcf.square.dim ; j++ ){ - - pcf.square.val[ j ] = new float [ pcf.square.dim ]; - - d2 = lngcmd2 - (float) j * pcf.square.res ; - - for ( int i = 0 ; i < pcf.square.dim ; i++ ){ - - if ( fabs( d2 ) > (float)0.5 ) pcf.square.val[ j ][ i ] = (float)0. ; - else{ - d1 = lngcmd2 - (float) i * pcf.square.res ; - if ( fabs( d1 ) > (float)0.5 ) pcf.square.val[ j ][ i ] = (float)0. ; - else pcf.square.val[ j ][ i ] = (float) 1.; + + //... distribution function for a square shape hole ................... + + if (wmh.do_square_cumsum) + { + + float lngcmd2 = (float)0.5; + + float d1, d2; + + pcf.square.res = wmh.highres; + + int dimd2 = (int)floorf(lngcmd2 / pcf.square.res) + 2; // add 2 to have at least one column of zeros as margin + pcf.square.dim = dimd2 * 2; // length of the density function (in resolution elements). even number + lngcmd2 += (float)2. * pcf.square.res; // center of the function + + pcf.square.val = new float*[pcf.square.dim]; // density function allocation + + for (int j = 0; j < pcf.square.dim; j++) + { + + pcf.square.val[j] = new float[pcf.square.dim]; + + d2 = lngcmd2 - (float)j * pcf.square.res; + + for (int i = 0; i < pcf.square.dim; i++) + { + + if (fabs(d2) > (float)0.5) + pcf.square.val[j][i] = (float)0.; + else + { + d1 = lngcmd2 - (float)i * pcf.square.res; + if (fabs(d1) > (float)0.5) + pcf.square.val[j][i] = (float)0.; + else + pcf.square.val[j][i] = (float)1.; } } } - - calc_cumsum( &pcf.square ); - - //cout << "\n\tLength of pcf.square density function: " << pcf.square.dim << endl; + + calc_cumsum(&pcf.square); + + // cout << "\n\tLength of pcf.square density function: " << pcf.square.dim << endl; } - - if ( wmh.do_depth ){ - - pcf.cr_att.dim = (int) floorf( wmh.prj.max_dcr / wmh.highres ) ; - - pcf.cr_att.i_max = pcf.cr_att.dim - 1 ; - - pcf.cr_att.val = new float [ pcf.cr_att.dim ] ; - - float stp = wmh.highres * wmh.prj.crattcoef ; - - for ( int i = 0 ; i < pcf.cr_att.dim ; i ++ ) pcf.cr_att.val[ i ] = expf( - (float)i * stp ); - - //cout << "\n\tLength of exponential to correct for crystal attenuation when do_depth: " << pcf.cr_att.dim << endl; + + if (wmh.do_depth) + { + + pcf.cr_att.dim = (int)floorf(wmh.prj.max_dcr / wmh.highres); + + pcf.cr_att.i_max = pcf.cr_att.dim - 1; + + pcf.cr_att.val = new float[pcf.cr_att.dim]; + + float stp = wmh.highres * wmh.prj.crattcoef; + + for (int i = 0; i < pcf.cr_att.dim; i++) + pcf.cr_att.val[i] = expf(-(float)i * stp); + + // cout << "\n\tLength of exponential to correct for crystal attenuation when do_depth: " << pcf.cr_att.dim << endl; } - } //========================================================================== //=== calc_round_cumsum =================================================== //========================================================================== -void calc_cumsum ( discrf2d_type *f ) +void +calc_cumsum(discrf2d_type* f) { - //... cumulative sum by columns ........................... - - for ( int j = 0 ; j < f->dim ; j++ ){ - - for ( int i = 1 ; i < f->dim ; i++ ){ - - f->val[ j ][ i ] = f->val[ j ][ i ] + f->val[ j ][ i - 1 ]; + //... cumulative sum by columns ........................... + + for (int j = 0; j < f->dim; j++) + { + + for (int i = 1; i < f->dim; i++) + { + + f->val[j][i] = f->val[j][i] + f->val[j][i - 1]; } } - - //... cumulative sum by rows ............................... - - for ( int j = 1 ; j < f->dim ; j++ ){ - - for ( int i = 0 ; i < f->dim ; i++ ){ - - f->val[ j ][ i ] = f->val[ j ][ i ] + f->val[ j - 1 ][ i ]; + + //... cumulative sum by rows ............................... + + for (int j = 1; j < f->dim; j++) + { + + for (int i = 0; i < f->dim; i++) + { + + f->val[j][i] = f->val[j][i] + f->val[j - 1][i]; } } - - //... normalization to one ................................. - - float vmax = f->val[ f->dim - 1 ][ f->dim - 1 ]; - - for ( int j = 0 ; j < f->dim ; j++ ){ - - for ( int i = 0 ; i < f->dim ; i++ ){ - - f->val[ j ][ i ] /= vmax; + + //... normalization to one ................................. + + float vmax = f->val[f->dim - 1][f->dim - 1]; + + for (int j = 0; j < f->dim; j++) + { + + for (int i = 0; i < f->dim; i++) + { + + f->val[j][i] /= vmax; } } - - f->i_max = f->j_max = f->dim -1 ; + + f->i_max = f->j_max = f->dim - 1; } //============================================================================== @@ -414,74 +439,74 @@ void calc_cumsum ( discrf2d_type *f ) /* void read_prj_params_mph() { - string token; + string token; detel_type d; - + char DELIMITER = ':'; - + ifstream stream1; stream1.open( wmh.detector_fn.c_str() ); if( !stream1 ) error_wmtools_SPECT_mph( 122, 0, wmh.detector_fn ); - + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); int Nring = atoi ( token.c_str() ); - + if ( Nring <= 0 ) error_wmtools_SPECT_mph(222, Nring, "Nring"); - + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); wmh.prj.rad = atof ( token.c_str() ); - + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); float FOVcmx = atof ( token.c_str() ); - + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); float FOVcmz = atof ( token.c_str() ); token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); wmh.prj.Nbin = atoi ( token.c_str() ); - + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); wmh.prj.Nsli = atoi ( token.c_str() ); - + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); wmh.prj.sgm_i = atof ( token.c_str() ); - + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); wmh.prj.crth = atof ( token.c_str() ); - + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); wmh.prj.crattcoef = atof ( token.c_str() ); - + //... check for parameters ........................................... - + if ( wmh.prj.Nbin <= 0 ) error_wmtools_SPECT_mph( 190, wmh.prj.Nbin ,"Nbin < 1" ); if ( wmh.prj.Nsli <= 0 ) error_wmtools_SPECT_mph( 190, wmh.prj.Nsli ,"Nsli < 1" ); - + if ( FOVcmx <= 0.) error_wmtools_SPECT_mph( 190, FOVcmx ,"FOVcmx non positive" ); if ( FOVcmz <= 0.) error_wmtools_SPECT_mph( 190, FOVcmz ,"FOVcmz non positive" ); - + if ( wmh.prj.rad <= 0.) error_wmtools_SPECT_mph( 190, wmh.prj.rad ,"Drad non positive" ); if ( wmh.prj.sgm_i < 0.) error_wmtools_SPECT_mph( 190, wmh.prj.sgm_i ,"PSF int: sigma non positive" ); - + //... derived variables ....................... - + wmh.prj.Nbd = wmh.prj.Nsli * wmh.prj.Nbin; - + wmh.prj.FOVxcmd2 = FOVcmx / (float) 2.; wmh.prj.FOVzcmd2 = FOVcmz / (float) 2.; - + wmh.prj.szcm = FOVcmx / (float) wmh.prj.Nbin ; wmh.prj.thcm = FOVcmz / (float) wmh.prj.Nsli ; - + wmh.prj.radc = wmh.prj.rad + wmh.prj.crth ; wmh.prj.szcmd2 = wmh.prj.szcm / (float) 2.; wmh.prj.thcmd2 = wmh.prj.thcm / (float) 2. ; wmh.prj.crth_2 = wmh.prj.crth * wmh.prj.crth ; - + if ( !wmh.do_depth ) wmh.prj.rad += wmh.prj.crth / (float)2.; // setting detection plane at half of the crystal thickness - + //... print out values (to comment or remove).............................. - + cout << "\n\tNumber of rings: " << Nring << endl; cout << "\tRadius (cm): " << wmh.prj.rad << endl; cout << "\tFOVcmx (cm): " << FOVcmx << endl; @@ -492,62 +517,62 @@ void read_prj_params_mph() cout << "\tSlice thickness (cm): " << wmh.prj.thcm << endl; cout << "\tIntrinsic PSF sigma (cm): " << wmh.prj.sgm_i << endl; cout << "\tCrystal thickness (cm): " << wmh.prj.crth << endl; - + //... for each ring .............................. - + wmh.prj.Ndt = 0 ; - + for ( int i = 0 ; i < Nring ; i++ ){ - + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); int Nang = atoi ( token.c_str() ); if ( Nang <= 0 ) error_wmtools_SPECT_mph( 190, Nang ,"Nang < 1" ); - + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); float ang0 = atof ( token.c_str() ); - + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); float incr = atof ( token.c_str() ); - + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); d.z0 = atof ( token.c_str() ); - + d.nh = 0; - + for ( int j= 0 ; j < Nang ; j++ ){ - + //... angles and ratios ................................................ - + d.theta = ( ang0 + (float)j * incr ) * dg2rd; // projection angle in radians d.costh = cosf( d.theta ); // cosinus of the angle d.sinth = sinf( d.theta ); // sinus of the angle - + //... cartesian coordinates of the center of the detector element ............. - + d.x0 = wmh.prj.rad * d.costh; d.y0 = wmh.prj.rad * d.sinth; - + //... coordinates of the first bin of each projection and increments for consecutive bins .... - + if(wmh.do_att){ - + d.incx = wmh.prj.szcm * d.costh; d.incy = wmh.prj.szcm * d.sinth; d.incz = wmh.prj.thcm; - + d.xbin0 = -wmh.prj.rad * d.sinth - ( wmh.prj.FOVxcmd2 + wmh.prj.szcm * (float)0.5 ) * d.costh ; d.ybin0 = wmh.prj.rad * d.costh - ( wmh.prj.FOVxcmd2 + wmh.prj.szcm * (float)0.5 ) * d.sinth ; d.zbin0 = d.z0 - wmh.prj.FOVzcmd2 + wmh.prj.thcmd2 ; } wmh.detel.push_back( d ); } - + //... update of wmh cumulative values ..................................... - + wmh.prj.Ndt += Nang ; - + //... print out values (to comment or remove).............................. - + cout << "\n\tDetector ring: " << i << endl; cout << "\tNumber of angles: " << Nang << endl; cout << "\tang0: " << ang0 << endl; @@ -555,484 +580,544 @@ void read_prj_params_mph() cout << "\tz0: " << d.z0 << endl; cout << "\tNumber of holes per detel: " << d.nh << endl; } - + //... fill detel ..................................................... - + stream1.close(); - + wmh.prj.Nbt = wmh.prj.Nbd * wmh.prj.Ndt ; - + cout << "\n\tTotal number of detels: " << wmh.prj.Ndt << endl; cout << "\tTotal number of bins: " << wmh.prj.Nbt << endl; - + return; }*/ - -void read_prj_params_mph( wmh_mph_type &wmh ) +void +read_prj_params_mph(wmh_mph_type& wmh) { - string token; - detel_type d; - std::stringstream info_stream; - - char DELIMITER = ':'; - - ifstream stream1; - stream1.open( wmh.detector_fn.c_str() ); - if( !stream1 ) error_wmtools_SPECT_mph( 122, 0, wmh.detector_fn ); - - token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - int Nring = atoi ( token.c_str() ); - - if ( Nring <= 0 ) error_wmtools_SPECT_mph(222, Nring, "Nring"); - /* - token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - float FOVcmx = atof ( token.c_str() ); - - token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - float FOVcmz = atof ( token.c_str() ); + string token; + detel_type d; + std::stringstream info_stream; - token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - wmh.prj.Nbin = atoi ( token.c_str() ); - - token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - wmh.prj.Nsli = atoi ( token.c_str() ); - */ - token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - wmh.prj.sgm_i = atof ( token.c_str() ); - - token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - wmh.prj.crth = atof ( token.c_str() ); - - token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - wmh.prj.crattcoef = atof ( token.c_str() ); - - //... check for parameters ........................................... + char DELIMITER = ':'; - if ( wmh.prj.Nbin <= 0 ) error_wmtools_SPECT_mph( 190, wmh.prj.Nbin ,"Nbin < 1" ); - if ( wmh.prj.Nsli <= 0 ) error_wmtools_SPECT_mph( 190, wmh.prj.Nsli ,"Nsli < 1" ); - - if ( wmh.prj.szcm <= 0.) error_wmtools_SPECT_mph( 190, wmh.prj.szcm ,"szcm non positive" ); - if ( wmh.prj.thcm <= 0.) error_wmtools_SPECT_mph( 190, wmh.prj.thcm ,"thcm non positive" ); - - if ( wmh.prj.rad <= 0.) error_wmtools_SPECT_mph( 190, wmh.prj.rad ,"Drad non positive" ); - if ( wmh.prj.sgm_i < 0.) error_wmtools_SPECT_mph( 190, wmh.prj.sgm_i ,"PSF int: sigma non positive" ); + ifstream stream1; + stream1.open(wmh.detector_fn.c_str()); + if (!stream1) + error_wmtools_SPECT_mph(122, 0, wmh.detector_fn); - //... derived variables ....................... - - wmh.prj.radc = wmh.prj.rad + wmh.prj.crth ; - wmh.prj.crth_2 = wmh.prj.crth * wmh.prj.crth ; - - if ( !wmh.do_depth ) wmh.prj.rad += wmh.prj.crth / (float)2.; // setting detection plane at half of the crystal thickness - - //... print out values (to comment or remove).............................. - - info_stream << "Projection parameters" << endl; - info_stream << "Number of rings: " << Nring << endl; - info_stream << "Radius (cm): " << wmh.prj.rad << endl; - info_stream << "FOVcmx (cm): " << wmh.prj.FOVxcmd2*2. << endl; - info_stream << "FOVcmz (cm): " << wmh.prj.FOVzcmd2*2. << endl; - info_stream << "Number of bins: " << wmh.prj.Nbin << endl; - info_stream << "Number of slices: " << wmh.prj.Nsli << endl; - info_stream << "Bin size (cm): " << wmh.prj.szcm << endl; - info_stream << "Slice thickness (cm): " << wmh.prj.thcm << endl; - info_stream << "Intrinsic PSF sigma (cm): " << wmh.prj.sgm_i << endl; - info_stream << "Crystal thickness (cm): " << wmh.prj.crth << endl; - - //... for each ring .............................. - - wmh.prj.Ndt = 0 ; - - for ( int i = 0 ; i < Nring ; i++ ){ - - token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - int Nang = atoi ( token.c_str() ); - if ( Nang <= 0 ) error_wmtools_SPECT_mph( 190, Nang ,"Nang < 1" ); - - token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - float ang0 = atof ( token.c_str() ); - - token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - float incr = atof ( token.c_str() ); - - token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - d.z0 = atof ( token.c_str() ); - - d.nh = 0; - - for ( int j= 0 ; j < Nang ; j++ ){ - - //... angles and ratios ................................................ - - d.theta = ( ang0 + (float)j * incr ) * dg2rd; // projection angle in radians - d.costh = cosf( d.theta ); // cosinus of the angle - d.sinth = sinf( d.theta ); // sinus of the angle - - //... cartesian coordinates of the center of the detector element ............. - - d.x0 = wmh.prj.rad * d.costh; - d.y0 = wmh.prj.rad * d.sinth; - - //... coordinates of the first bin of each projection and increments for consecutive bins .... - - if(wmh.do_att){ - - d.incx = wmh.prj.szcm * d.costh; - d.incy = wmh.prj.szcm * d.sinth; - d.incz = wmh.prj.thcm; - - d.xbin0 = -wmh.prj.rad * d.sinth - ( wmh.prj.FOVxcmd2 + wmh.prj.szcm * (float)0.5 ) * d.costh ; - d.ybin0 = wmh.prj.rad * d.costh - ( wmh.prj.FOVxcmd2 + wmh.prj.szcm * (float)0.5 ) * d.sinth ; - d.zbin0 = d.z0 - wmh.prj.FOVzcmd2 + wmh.prj.thcmd2 ; + token = wm_SPECT_read_value_1d(&stream1, DELIMITER); + int Nring = atoi(token.c_str()); + + if (Nring <= 0) + error_wmtools_SPECT_mph(222, Nring, "Nring"); + /* + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); + float FOVcmx = atof ( token.c_str() ); + + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); + float FOVcmz = atof ( token.c_str() ); + + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); + wmh.prj.Nbin = atoi ( token.c_str() ); + + token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); + wmh.prj.Nsli = atoi ( token.c_str() ); + */ + token = wm_SPECT_read_value_1d(&stream1, DELIMITER); + wmh.prj.sgm_i = atof(token.c_str()); + + token = wm_SPECT_read_value_1d(&stream1, DELIMITER); + wmh.prj.crth = atof(token.c_str()); + + token = wm_SPECT_read_value_1d(&stream1, DELIMITER); + wmh.prj.crattcoef = atof(token.c_str()); + + //... check for parameters ........................................... + + if (wmh.prj.Nbin <= 0) + error_wmtools_SPECT_mph(190, wmh.prj.Nbin, "Nbin < 1"); + if (wmh.prj.Nsli <= 0) + error_wmtools_SPECT_mph(190, wmh.prj.Nsli, "Nsli < 1"); + + if (wmh.prj.szcm <= 0.) + error_wmtools_SPECT_mph(190, wmh.prj.szcm, "szcm non positive"); + if (wmh.prj.thcm <= 0.) + error_wmtools_SPECT_mph(190, wmh.prj.thcm, "thcm non positive"); + + if (wmh.prj.rad <= 0.) + error_wmtools_SPECT_mph(190, wmh.prj.rad, "Drad non positive"); + if (wmh.prj.sgm_i < 0.) + error_wmtools_SPECT_mph(190, wmh.prj.sgm_i, "PSF int: sigma non positive"); + + //... derived variables ....................... + + wmh.prj.radc = wmh.prj.rad + wmh.prj.crth; + wmh.prj.crth_2 = wmh.prj.crth * wmh.prj.crth; + + if (!wmh.do_depth) + wmh.prj.rad += wmh.prj.crth / (float)2.; // setting detection plane at half of the crystal thickness + + //... print out values (to comment or remove).............................. + + info_stream << "Projection parameters" << endl; + info_stream << "Number of rings: " << Nring << endl; + info_stream << "Radius (cm): " << wmh.prj.rad << endl; + info_stream << "FOVcmx (cm): " << wmh.prj.FOVxcmd2 * 2. << endl; + info_stream << "FOVcmz (cm): " << wmh.prj.FOVzcmd2 * 2. << endl; + info_stream << "Number of bins: " << wmh.prj.Nbin << endl; + info_stream << "Number of slices: " << wmh.prj.Nsli << endl; + info_stream << "Bin size (cm): " << wmh.prj.szcm << endl; + info_stream << "Slice thickness (cm): " << wmh.prj.thcm << endl; + info_stream << "Intrinsic PSF sigma (cm): " << wmh.prj.sgm_i << endl; + info_stream << "Crystal thickness (cm): " << wmh.prj.crth << endl; + + //... for each ring .............................. + + wmh.prj.Ndt = 0; + + for (int i = 0; i < Nring; i++) + { + + token = wm_SPECT_read_value_1d(&stream1, DELIMITER); + int Nang = atoi(token.c_str()); + if (Nang <= 0) + error_wmtools_SPECT_mph(190, Nang, "Nang < 1"); + + token = wm_SPECT_read_value_1d(&stream1, DELIMITER); + float ang0 = atof(token.c_str()); + + token = wm_SPECT_read_value_1d(&stream1, DELIMITER); + float incr = atof(token.c_str()); + + token = wm_SPECT_read_value_1d(&stream1, DELIMITER); + d.z0 = atof(token.c_str()); + + d.nh = 0; + + for (int j = 0; j < Nang; j++) + { + + //... angles and ratios ................................................ + + d.theta = (ang0 + (float)j * incr) * dg2rd; // projection angle in radians + d.costh = cosf(d.theta); // cosinus of the angle + d.sinth = sinf(d.theta); // sinus of the angle + + //... cartesian coordinates of the center of the detector element ............. + + d.x0 = wmh.prj.rad * d.costh; + d.y0 = wmh.prj.rad * d.sinth; + + //... coordinates of the first bin of each projection and increments for consecutive bins .... + + if (wmh.do_att) + { + + d.incx = wmh.prj.szcm * d.costh; + d.incy = wmh.prj.szcm * d.sinth; + d.incz = wmh.prj.thcm; + + d.xbin0 = -wmh.prj.rad * d.sinth - (wmh.prj.FOVxcmd2 + wmh.prj.szcm * (float)0.5) * d.costh; + d.ybin0 = wmh.prj.rad * d.costh - (wmh.prj.FOVxcmd2 + wmh.prj.szcm * (float)0.5) * d.sinth; + d.zbin0 = d.z0 - wmh.prj.FOVzcmd2 + wmh.prj.thcmd2; } - wmh.detel.push_back( d ); + wmh.detel.push_back(d); } - - //... update of wmh cumulative values ..................................... - - wmh.prj.Ndt += Nang ; - - //... print out values (to comment or remove).............................. - - info_stream << "\nDetector ring: " << i << endl; - info_stream << "Number of angles: " << Nang << endl; - info_stream << "ang0: " << ang0 << endl; - info_stream << "incr: " << incr << endl; - info_stream << "z0: " << d.z0 << endl; - info_stream << "Number of holes per detel: " << d.nh << endl; + + //... update of wmh cumulative values ..................................... + + wmh.prj.Ndt += Nang; + + //... print out values (to comment or remove).............................. + + info_stream << "\nDetector ring: " << i << endl; + info_stream << "Number of angles: " << Nang << endl; + info_stream << "ang0: " << ang0 << endl; + info_stream << "incr: " << incr << endl; + info_stream << "z0: " << d.z0 << endl; + info_stream << "Number of holes per detel: " << d.nh << endl; } - - //... fill detel ..................................................... - - stream1.close(); - - wmh.prj.Nbt = wmh.prj.Nbd * wmh.prj.Ndt ; - - info_stream << "\nTotal number of detels: " << wmh.prj.Ndt << endl; - info_stream << "Total number of bins: " << wmh.prj.Nbt << endl; - - stir::info(info_stream.str()); - - return; -} + //... fill detel ..................................................... + + stream1.close(); + + wmh.prj.Nbt = wmh.prj.Nbd * wmh.prj.Ndt; + info_stream << "\nTotal number of detels: " << wmh.prj.Ndt << endl; + info_stream << "Total number of bins: " << wmh.prj.Nbt << endl; + + stir::info(info_stream.str()); + + return; +} ///============================================================================= //=== read collimator params mph =============================================== //============================================================================== -void read_coll_params_mph( wmh_mph_type &wmh ) +void +read_coll_params_mph(wmh_mph_type& wmh) { - string token; - vector param; - std::stringstream info_stream; - - char DELIMITER = ':'; - - ifstream stream1; - stream1.open( wmh.collim_fn.c_str() ); - - if( !stream1 ) error_wmtools_SPECT_mph( 122, 0, wmh.collim_fn ); - - wmh.collim.model = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - - token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - wmh.collim.rad = atof ( token.c_str() ); - - token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - wmh.collim.L = atof ( token.c_str() ); - wmh.collim.Ld2 = wmh.collim.L / (float)2. ; - - token = wm_SPECT_read_value_1d ( &stream1, DELIMITER ); - wmh.collim.Nht = atoi ( token.c_str() ); - -// wmh.collim.holes = new hole_type [ wmh.collim.Nht ]; - - int nh = 0; - if ( wmh.collim.model == "cyl" ) wm_SPECT_read_hvalues_mph( &stream1, DELIMITER, &nh, true, wmh ); - else{ - if ( wmh.collim.model == "pol" ) wm_SPECT_read_hvalues_mph( &stream1, DELIMITER, &nh, false, wmh ); - else error_wmtools_SPECT_mph ( 334, 0, wmh.collim.model ); + string token; + vector param; + std::stringstream info_stream; + + char DELIMITER = ':'; + + ifstream stream1; + stream1.open(wmh.collim_fn.c_str()); + + if (!stream1) + error_wmtools_SPECT_mph(122, 0, wmh.collim_fn); + + wmh.collim.model = wm_SPECT_read_value_1d(&stream1, DELIMITER); + + token = wm_SPECT_read_value_1d(&stream1, DELIMITER); + wmh.collim.rad = atof(token.c_str()); + + token = wm_SPECT_read_value_1d(&stream1, DELIMITER); + wmh.collim.L = atof(token.c_str()); + wmh.collim.Ld2 = wmh.collim.L / (float)2.; + + token = wm_SPECT_read_value_1d(&stream1, DELIMITER); + wmh.collim.Nht = atoi(token.c_str()); + + // wmh.collim.holes = new hole_type [ wmh.collim.Nht ]; + + int nh = 0; + if (wmh.collim.model == "cyl") + wm_SPECT_read_hvalues_mph(&stream1, DELIMITER, &nh, true, wmh); + else + { + if (wmh.collim.model == "pol") + wm_SPECT_read_hvalues_mph(&stream1, DELIMITER, &nh, false, wmh); + else + error_wmtools_SPECT_mph(334, 0, wmh.collim.model); } - - if ( nh != wmh.collim.Nht ) error_wmtools_SPECT_mph( 150, nh, "" ); - - //... check for parameters ........................................... - - - if ( wmh.collim.rad <= 0. ) error_wmtools_SPECT_mph( 190, wmh.collim.rad ,"Collimator radius non positive" ); - - if ( wmh.collim.Nht <= 0 ) error_wmtools_SPECT_mph( 190, wmh.collim.Nht ,"Number of Holes < 1" ); - - //... print out values (to comment or remove).............................. - - stream1.close(); - - info_stream << "Collimator parameters" << endl; - info_stream << "\nCollimator model: " << wmh.collim.model << endl; - info_stream << "Collimator rad: " << wmh.collim.rad << endl; - info_stream << "Number of holes: " << wmh.collim.Nht << endl; - - stir::info(info_stream.str()); - return; + if (nh != wmh.collim.Nht) + error_wmtools_SPECT_mph(150, nh, ""); + + //... check for parameters ........................................... + + if (wmh.collim.rad <= 0.) + error_wmtools_SPECT_mph(190, wmh.collim.rad, "Collimator radius non positive"); + + if (wmh.collim.Nht <= 0) + error_wmtools_SPECT_mph(190, wmh.collim.Nht, "Number of Holes < 1"); + + //... print out values (to comment or remove).............................. + + stream1.close(); + + info_stream << "Collimator parameters" << endl; + info_stream << "\nCollimator model: " << wmh.collim.model << endl; + info_stream << "Collimator rad: " << wmh.collim.rad << endl; + info_stream << "Number of holes: " << wmh.collim.Nht << endl; + + stir::info(info_stream.str()); + + return; } //===================================================================== //======== wm_SPECT_read_hvalues_mph ============================== //===================================================================== -void wm_SPECT_read_hvalues_mph( ifstream * stream1 , char DELIMITER, int * nh, bool do_cyl, wmh_mph_type &wmh ) +void +wm_SPECT_read_hvalues_mph(ifstream* stream1, char DELIMITER, int* nh, bool do_cyl, wmh_mph_type& wmh) { - - size_t pos1, pos2, pos3; - string line, token; - hole_type h; - - float max_hsxcm = (float) 0.; - float max_hszcm = (float) 0.; - - float max_aix = (float) 0.; - float max_aiz = (float) 0.; - *nh = 0 ; - - while ( getline ( *stream1, line ) ){ - - pos1 = line.find( DELIMITER ); - - if ( pos1 == string::npos ) continue; - - //... detel index ................... - - pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1 ); - pos3 = line.find_first_of(" \t\f\v\n\r", pos2); - if ( pos2 == string::npos || pos3 == string::npos ) error_wmtools_SPECT_mph ( 333, *nh, "idet" ); - token = line.substr( pos2 , pos3 - pos2 ); - int idet = atoi( token.c_str() ) - 1 ; - wmh.detel[ idet ].who.push_back( *nh ); - wmh.detel[ idet ].nh ++; - pos1 = pos3; - - //... second parameter ........................... - - if ( do_cyl ){ - - //... angle ........................... - - pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1 ); - pos3 = line.find_first_of(" \t\f\v\n\r", pos2); - if ( pos2 == string::npos || pos3 == string::npos ) error_wmtools_SPECT_mph ( 333, *nh, "angle(deg)" ); - token = line.substr( pos2 , pos3 - pos2 ); - h.acy = atof( token.c_str() ) * dg2rd ; - pos1 = pos3; + size_t pos1, pos2, pos3; + string line, token; + hole_type h; + + float max_hsxcm = (float)0.; + float max_hszcm = (float)0.; + + float max_aix = (float)0.; + float max_aiz = (float)0.; + + *nh = 0; + + while (getline(*stream1, line)) + { + + pos1 = line.find(DELIMITER); + + if (pos1 == string::npos) + continue; + + //... detel index ................... + + pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1); + pos3 = line.find_first_of(" \t\f\v\n\r", pos2); + if (pos2 == string::npos || pos3 == string::npos) + error_wmtools_SPECT_mph(333, *nh, "idet"); + token = line.substr(pos2, pos3 - pos2); + int idet = atoi(token.c_str()) - 1; + wmh.detel[idet].who.push_back(*nh); + wmh.detel[idet].nh++; + pos1 = pos3; + + //... second parameter ........................... + + if (do_cyl) + { + + //... angle ........................... + + pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1); + pos3 = line.find_first_of(" \t\f\v\n\r", pos2); + if (pos2 == string::npos || pos3 == string::npos) + error_wmtools_SPECT_mph(333, *nh, "angle(deg)"); + token = line.substr(pos2, pos3 - pos2); + h.acy = atof(token.c_str()) * dg2rd; + pos1 = pos3; } - else{ - - //... x position ........................... - - pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1 ); - pos3 = line.find_first_of(" \t\f\v\n\r", pos2); - if ( pos2 == string::npos || pos3 == string::npos ) error_wmtools_SPECT_mph ( 333, *nh, "x(cm)" ); - token = line.substr( pos2 , pos3 - pos2 ); - h.x1 = atof( token.c_str() ); - pos1 = pos3; + else + { + + //... x position ........................... + + pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1); + pos3 = line.find_first_of(" \t\f\v\n\r", pos2); + if (pos2 == string::npos || pos3 == string::npos) + error_wmtools_SPECT_mph(333, *nh, "x(cm)"); + token = line.substr(pos2, pos3 - pos2); + h.x1 = atof(token.c_str()); + pos1 = pos3; } - - //... y position (along collimator wall. 0 for centrer of collimator wall) ................... - - pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1 ); - pos3 = line.find_first_of(" \t\f\v\n\r", pos2); - if ( pos2 == string::npos || pos3 == string::npos ) error_wmtools_SPECT_mph ( 333, *nh, "y(cm)" ); - token = line.substr( pos2 , pos3 - pos2 ); - float yd = atof( token.c_str() ); - pos1 = pos3; - - //... z position ................... - - pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1 ); - pos3 = line.find_first_of(" \t\f\v\n\r", pos2); - if ( pos2 == string::npos || pos3 == string::npos ) error_wmtools_SPECT_mph ( 333, *nh, "z(cm)" ); - token = line.substr( pos2 , pos3 - pos2 ); - h.z1 = atof( token.c_str() ); - pos1 = pos3; - - //... shape ............................. - - pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1 ); - pos3 = line.find_first_of(" \t\f\v\n\r", pos2); - if ( pos2 == string::npos || pos3 == string::npos ) error_wmtools_SPECT_mph ( 333, *nh, "shape" ); - token = line.substr( pos2 , pos3 - pos2 ); - if ( token.compare( "rect") != 0 && token.compare( "round" ) != 0 ) error_wmtools_SPECT_mph ( 444, *nh, ""); - h.shape = token.c_str(); - pos1 = pos3; - - if ( token.compare( "rect") == 0 ){ - wmh.do_square_cumsum = true; - h.do_round = false; + + //... y position (along collimator wall. 0 for centrer of collimator wall) ................... + + pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1); + pos3 = line.find_first_of(" \t\f\v\n\r", pos2); + if (pos2 == string::npos || pos3 == string::npos) + error_wmtools_SPECT_mph(333, *nh, "y(cm)"); + token = line.substr(pos2, pos3 - pos2); + float yd = atof(token.c_str()); + pos1 = pos3; + + //... z position ................... + + pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1); + pos3 = line.find_first_of(" \t\f\v\n\r", pos2); + if (pos2 == string::npos || pos3 == string::npos) + error_wmtools_SPECT_mph(333, *nh, "z(cm)"); + token = line.substr(pos2, pos3 - pos2); + h.z1 = atof(token.c_str()); + pos1 = pos3; + + //... shape ............................. + + pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1); + pos3 = line.find_first_of(" \t\f\v\n\r", pos2); + if (pos2 == string::npos || pos3 == string::npos) + error_wmtools_SPECT_mph(333, *nh, "shape"); + token = line.substr(pos2, pos3 - pos2); + if (token.compare("rect") != 0 && token.compare("round") != 0) + error_wmtools_SPECT_mph(444, *nh, ""); + h.shape = token.c_str(); + pos1 = pos3; + + if (token.compare("rect") == 0) + { + wmh.do_square_cumsum = true; + h.do_round = false; } - else{ - wmh.do_round_cumsum = true; - h.do_round = true; + else + { + wmh.do_round_cumsum = true; + h.do_round = true; } - - //... dimension x cm ....................... - - pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1 ); - pos3 = line.find_first_of(" \t\f\v\n\r", pos2); - if ( pos2 == string::npos ) error_wmtools_SPECT_mph ( 333, *nh, "dxcm" ); - token = line.substr( pos2 , pos3 - pos2 ); - h.dxcm = atof( token.c_str() ); - if ( h.dxcm > max_hsxcm ) max_hsxcm = h.dxcm; - pos1 = pos3; - - //... dimension z cm ....................... - - pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1 ); - pos3 = line.find_first_of(" \t\f\v\n\r", pos2); - if ( pos2 == string::npos ) error_wmtools_SPECT_mph ( 333, *nh, "dzcm" ); - token = line.substr( pos2 , pos3 - pos2 ); - h.dzcm = atof( token.c_str() ); - if ( h.dzcm > max_hszcm ) max_hszcm = h.dzcm; - pos1 = pos3; - - //... hole axial angle x ....................... - - pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1 ); - pos3 = line.find_first_of(" \t\f\v\n\r", pos2); - if ( pos2 == string::npos ) error_wmtools_SPECT_mph ( 333, *nh, "ahx" ); - token = line.substr( pos2 , pos3 - pos2 ); - h.ahx = atof( token.c_str() ) * dg2rd ; - pos1 = pos3; - - //... hole axial angle z ....................... - - pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1 ); - pos3 = line.find_first_of(" \t\f\v\n\r", pos2); - if ( pos2 == string::npos ) error_wmtools_SPECT_mph ( 333, *nh, "ahz" ); - token = line.substr( pos2 , pos3 - pos2 ); - h.ahz = atof( token.c_str() ) * dg2rd ; - pos1 = pos3; - - //... x acceptance angle ........................ - - pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1 ); - pos3 = line.find_first_of(" \t\f\v\n\r", pos2); - if ( pos2 == string::npos ) error_wmtools_SPECT_mph ( 333, *nh, "aa_x" ); - token = line.substr( pos2 , pos3 - pos2 ); - h.aa_x = atof( token.c_str() ) * dg2rd ; - pos1 = pos3; - - //... z acceptance angle ........................ - - pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1 ); - pos3 = line.find_first_of(" \t\f\v\n\r", pos2); - if ( pos2 == string::npos ) error_wmtools_SPECT_mph ( 333, *nh, "aa_z" ); - token = line.substr( pos2 , pos3 - pos2 ); - h.aa_z = atof( token.c_str() ) * dg2rd ; - - //... derived variables ........................................ - - if( do_cyl ) { - h.acyR = h.acy - wmh.detel[ idet ].theta ; - h.x1 = ( wmh.collim.rad + yd ) * sinf( h.acyR ); - h.y1 = ( wmh.collim.rad + yd ) * cosf( h.acyR ) ; + + //... dimension x cm ....................... + + pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1); + pos3 = line.find_first_of(" \t\f\v\n\r", pos2); + if (pos2 == string::npos) + error_wmtools_SPECT_mph(333, *nh, "dxcm"); + token = line.substr(pos2, pos3 - pos2); + h.dxcm = atof(token.c_str()); + if (h.dxcm > max_hsxcm) + max_hsxcm = h.dxcm; + pos1 = pos3; + + //... dimension z cm ....................... + + pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1); + pos3 = line.find_first_of(" \t\f\v\n\r", pos2); + if (pos2 == string::npos) + error_wmtools_SPECT_mph(333, *nh, "dzcm"); + token = line.substr(pos2, pos3 - pos2); + h.dzcm = atof(token.c_str()); + if (h.dzcm > max_hszcm) + max_hszcm = h.dzcm; + pos1 = pos3; + + //... hole axial angle x ....................... + + pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1); + pos3 = line.find_first_of(" \t\f\v\n\r", pos2); + if (pos2 == string::npos) + error_wmtools_SPECT_mph(333, *nh, "ahx"); + token = line.substr(pos2, pos3 - pos2); + h.ahx = atof(token.c_str()) * dg2rd; + pos1 = pos3; + + //... hole axial angle z ....................... + + pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1); + pos3 = line.find_first_of(" \t\f\v\n\r", pos2); + if (pos2 == string::npos) + error_wmtools_SPECT_mph(333, *nh, "ahz"); + token = line.substr(pos2, pos3 - pos2); + h.ahz = atof(token.c_str()) * dg2rd; + pos1 = pos3; + + //... x acceptance angle ........................ + + pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1); + pos3 = line.find_first_of(" \t\f\v\n\r", pos2); + if (pos2 == string::npos) + error_wmtools_SPECT_mph(333, *nh, "aa_x"); + token = line.substr(pos2, pos3 - pos2); + h.aa_x = atof(token.c_str()) * dg2rd; + pos1 = pos3; + + //... z acceptance angle ........................ + + pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1); + pos3 = line.find_first_of(" \t\f\v\n\r", pos2); + if (pos2 == string::npos) + error_wmtools_SPECT_mph(333, *nh, "aa_z"); + token = line.substr(pos2, pos3 - pos2); + h.aa_z = atof(token.c_str()) * dg2rd; + + //... derived variables ........................................ + + if (do_cyl) + { + h.acyR = h.acy - wmh.detel[idet].theta; + h.x1 = (wmh.collim.rad + yd) * sinf(h.acyR); + h.y1 = (wmh.collim.rad + yd) * cosf(h.acyR); } - else{ - h.y1 = wmh.collim.rad + yd ; + else + { + h.y1 = wmh.collim.rad + yd; } - - h.z1 = wmh.detel[ idet ].z0 + h.z1 ; - - //... edge slope x,z minor and major ....................... - - h.Egx = h.ahx + h.aa_x ; - h.egx = h.ahx - h.aa_x ; - h.Egz = h.ahz + h.aa_z ; - h.egz = h.ahz - h.aa_z ; - - //... angles max and min .......................................... - - h.ax_M = h.Egx ; - h.ax_m = h.egx ; - h.az_M = h.Egz ; - h.az_m = h.egz ; - - //... incidence angle maximum, for PSF allocation when correction for depth............... - - if ( fabs ( h.ax_m ) > max_aix ) max_aix = h.ax_m ; - if ( fabs ( h.ax_M ) > max_aix ) max_aix = h.ax_M ; - - if ( fabs ( h.az_m ) > max_aiz ) max_aiz = h.az_m ; - if ( fabs ( h.az_M ) > max_aiz ) max_aiz = h.az_M ; - - wmh.collim.holes.push_back ( h ); - - *nh = *nh + 1; + + h.z1 = wmh.detel[idet].z0 + h.z1; + + //... edge slope x,z minor and major ....................... + + h.Egx = h.ahx + h.aa_x; + h.egx = h.ahx - h.aa_x; + h.Egz = h.ahz + h.aa_z; + h.egz = h.ahz - h.aa_z; + + //... angles max and min .......................................... + + h.ax_M = h.Egx; + h.ax_m = h.egx; + h.az_M = h.Egz; + h.az_m = h.egz; + + //... incidence angle maximum, for PSF allocation when correction for depth............... + + if (fabs(h.ax_m) > max_aix) + max_aix = h.ax_m; + if (fabs(h.ax_M) > max_aix) + max_aix = h.ax_M; + + if (fabs(h.az_m) > max_aiz) + max_aiz = h.az_m; + if (fabs(h.az_M) > max_aiz) + max_aiz = h.az_M; + + wmh.collim.holes.push_back(h); + + *nh = *nh + 1; } - - //... maximum hole dimensions and incidence angles ................. - - wmh.max_hsxcm = max_hsxcm; - wmh.max_hszcm = max_hszcm; - - wmh.tmax_aix = tanf( max_aix ); - wmh.tmax_aiz = tanf( max_aiz ); - - wmh.prj.max_dcr = (float)1.2 * wmh.prj.crth / cosf( max ( max_aix , max_aiz ) ) ; + + //... maximum hole dimensions and incidence angles ................. + + wmh.max_hsxcm = max_hsxcm; + wmh.max_hszcm = max_hszcm; + + wmh.tmax_aix = tanf(max_aix); + wmh.tmax_aiz = tanf(max_aiz); + + wmh.prj.max_dcr = (float)1.2 * wmh.prj.crth / cosf(max(max_aix, max_aiz)); } //============================================================================= //=== generate_msk_mph ======================================================== //============================================================================= -void generate_msk_mph ( bool *msk_3d, float *attmap, wmh_mph_type &wmh ) +void +generate_msk_mph(bool* msk_3d, float* attmap, wmh_mph_type& wmh) { - -// bool do_save_resulting_msk = true; - - //... 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 read a mask from a (int) file .................... - if ( wmh.do_msk_file ) stir::error("Mask incorrectly read from file."); //read_msk_file_mph( msk_3d ); // STIR implementation never calls this to avoid using read_msk_file_mph - - else { - - //... to create a cylindrical mask...................... - - float xi2, yi2; - - float Rmax2 = wmh.ro * wmh.ro; // Maximum allowed radius (distance from volume centre) - - for ( int j = 0 , ip = 0 ; j < wmh.vol.Dimy ; j++ ){ - - yi2 = ( (float)j + (float)0.5 ) * wmh.vol.szcm - wmh.vol.FOVcmyd2 ; - yi2 *= yi2; - - for ( int i = 0 ; i < wmh.vol.Dimx ; i++ , ip++ ){ - - xi2 = ( (float)i + (float)0.5 ) * wmh.vol.szcm - wmh.vol.FOVxcmd2 ; - xi2 *= xi2; - - if ( ( xi2 + yi2 ) > Rmax2 ){ - - for ( int k = 0 ; k < wmh.vol.Dimz ; k ++ ) msk_3d[ ip + k * wmh.vol.Npix ] = false; - } - else { - for ( int k = 0 ; k < wmh.vol.Dimz ; k ++ ) msk_3d[ ip + k * wmh.vol.Npix ] = true; + // bool do_save_resulting_msk = true; + + //... 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 read a mask from a (int) file .................... + + if (wmh.do_msk_file) + stir::error("Mask incorrectly read from file."); // read_msk_file_mph( msk_3d ); // STIR implementation never calls this + // to avoid using read_msk_file_mph + + else + { + + //... to create a cylindrical mask...................... + + float xi2, yi2; + + float Rmax2 = wmh.ro * wmh.ro; // Maximum allowed radius (distance from volume centre) + + for (int j = 0, ip = 0; j < wmh.vol.Dimy; j++) + { + + yi2 = ((float)j + (float)0.5) * wmh.vol.szcm - wmh.vol.FOVcmyd2; + yi2 *= yi2; + + for (int i = 0; i < wmh.vol.Dimx; i++, ip++) + { + + xi2 = ((float)i + (float)0.5) * wmh.vol.szcm - wmh.vol.FOVxcmd2; + xi2 *= xi2; + + if ((xi2 + yi2) > Rmax2) + { + + for (int k = 0; k < wmh.vol.Dimz; k++) + msk_3d[ip + k * wmh.vol.Npix] = false; } - } - } - } - } + else + { + for (int k = 0; k < wmh.vol.Dimz; k++) + msk_3d[ip + k * wmh.vol.Npix] = true; + } + } + } + } + } } //============================================================================= @@ -1085,31 +1170,35 @@ void read_att_map_mph( float *attmap ) //======== wm_SPECT_read_value_1d ===================================== //===================================================================== -string wm_SPECT_read_value_1d ( ifstream * stream1, char DELIMITER ) +string +wm_SPECT_read_value_1d(ifstream* stream1, char DELIMITER) { - - size_t pos1, pos2, pos3; - string line; - - int k = 0 ; - - while ( !stream1->eof() ){ - getline ( *stream1, line ); - - pos1 = line.find( DELIMITER ); - - if ( pos1 != string::npos ){ - k++; - break; + + size_t pos1, pos2, pos3; + string line; + + int k = 0; + + while (!stream1->eof()) + { + getline(*stream1, line); + + pos1 = line.find(DELIMITER); + + if (pos1 != string::npos) + { + k++; + break; } } - - if ( k == 0 ) error_wmtools_SPECT_mph (888, 0 ,"" ); - - pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1 ); - pos3 = line.find_first_of(" \t\f\v\n\r", pos2); - - return( line.substr( pos2 , pos3 - pos2 ) ); + + if (k == 0) + error_wmtools_SPECT_mph(888, 0, ""); + + pos2 = line.find_first_not_of(" \t\f\v\n\r", pos1 + 1); + pos3 = line.find_first_of(" \t\f\v\n\r", pos2); + + return (line.substr(pos2, pos3 - pos2)); } //============================================================================= @@ -1204,7 +1293,8 @@ void free_pcf( ) //== error_wmtools_SPECT_mph ====================================================== //============================================================================= -void error_wmtools_SPECT_mph( int nerr, int ip, string txt ) +void +error_wmtools_SPECT_mph(int nerr, int ip, string txt) { #if 0 switch(nerr){ @@ -1234,39 +1324,71 @@ void error_wmtools_SPECT_mph( int nerr, int ip, string txt ) exit(0); #else - using stir::error; - switch(nerr){ + using stir::error; + switch (nerr) + { + + case 55: + printf("\n\nError %d weight3d: Dowmsampling. Incongruency factor-dim: %d \n", nerr, ip); + break; + case 56: + printf("\n\nError %d weight3d: Downsampling. Resulting dim bigger than max %d \n", nerr, ip); + break; + case 77: + printf("\n\nError %d weight3d: Convolution. psf_out is not big enough %d. Verify geometry. \n", nerr, ip); + break; + case 78: + printf("\n\nError %d weight3d: Geometric PSF. psf_out is not big enough %d. Verify geometry. \n", nerr, ip); + break; + + //... error: value of argv[].......................... + + case 122: + printf("\n\nError wm_SPECT: File with variable parameters: %s not found.\n", txt.c_str()); + break; + case 124: + printf("\n\nError wm_SPECT: Cannot open attenuation map: %s for reading..\n", txt.c_str()); + break; + case 126: + printf("\n\nError wm_SPECT: Cannot open file mask: %s for reading\n", txt.c_str()); + break; + case 150: + printf("\n\nError wm_SPECT: List of hole parameters has different length (%d) than number of holes.\n", ip); + break; + case 190: + printf("\n\nError wm_SPECT: Wrong value in detector parameter: %s \n", txt.c_str()); + break; + case 200: + printf("\n\nError wm_SPECT: Cannot allocate %d element of the variable: %s\n", ip, txt.c_str()); + break; + case 222: + printf("\n\nError wm_SPECT: Wrong number of rings: %d\n", ip); + break; + case 333: + printf("\n\nError wm_SPECT: Missing parameter in hole %d definition: %s\n", ip, txt.c_str()); + break; + case 334: + printf("\n\nError wm_SPECT: %s unknown collimator model. Options: cyl/pol.\n", txt.c_str()); + break; + case 444: + printf("\n\nError wm_SPECT: Hole %d: Wrong hole shape. Hole shape should be either rect or round.\n", ip); + break; + case 888: + error("\n\nError wm_SPECT: Missing parameter in collimator file.\n"); + break; + default: + printf("\n\nError wmtools_SPECT: %d unknown error number on error_wmtools_SPECT().", nerr); + } - case 55: printf( "\n\nError %d weight3d: Dowmsampling. Incongruency factor-dim: %d \n", nerr, ip ); break; - case 56: printf( "\n\nError %d weight3d: Downsampling. Resulting dim bigger than max %d \n", nerr, ip ); break; - case 77: printf( "\n\nError %d weight3d: Convolution. psf_out is not big enough %d. Verify geometry. \n", nerr, ip ); break; - case 78: printf( "\n\nError %d weight3d: Geometric PSF. psf_out is not big enough %d. Verify geometry. \n", nerr, ip ); break; - - //... error: value of argv[].......................... - - case 122: printf("\n\nError wm_SPECT: File with variable parameters: %s not found.\n",txt.c_str() ); break; - case 124: printf("\n\nError wm_SPECT: Cannot open attenuation map: %s for reading..\n", txt.c_str() ); break; - case 126: printf("\n\nError wm_SPECT: Cannot open file mask: %s for reading\n",txt.c_str() ); break; - case 150: printf("\n\nError wm_SPECT: List of hole parameters has different length (%d) than number of holes.\n", ip); break; - case 190: printf("\n\nError wm_SPECT: Wrong value in detector parameter: %s \n", txt.c_str()); break; - case 200: printf("\n\nError wm_SPECT: Cannot allocate %d element of the variable: %s\n",ip, txt.c_str() ); break; - case 222: printf("\n\nError wm_SPECT: Wrong number of rings: %d\n", ip ); break; - case 333: printf("\n\nError wm_SPECT: Missing parameter in hole %d definition: %s\n", ip, txt.c_str() ); break; - case 334: printf("\n\nError wm_SPECT: %s unknown collimator model. Options: cyl/pol.\n", txt.c_str() ); break; - case 444: printf("\n\nError wm_SPECT: Hole %d: Wrong hole shape. Hole shape should be either rect or round.\n",ip); break; - case 888: error("\n\nError wm_SPECT: Missing parameter in collimator file.\n"); break; - default: printf("\n\nError wmtools_SPECT: %d unknown error number on error_wmtools_SPECT().",nerr); - } - - exit(0); + exit(0); #endif -} +} //========================================================================== //=== error_wm ==================================================== //========================================================================== //=== Originally implemented in wm_SPECT_mph.cpp -//=== Deprecated after main integration into ProjMatricByBinPinholeSPECTUB.cxx +//=== Deprecated after main integration into ProjMatricByBinPinholeSPECTUB.cxx //=== STIR error handling is with error() and warning() //========================================================================== #if 0 @@ -1338,4 +1460,4 @@ void error_wm_SPECT_mph( int nerr, string txt) } #endif -} // end of namespace +} // namespace SPECTUB_mph diff --git a/src/recon_buildblock/PinholeSPECTUB_Weight3d.cxx b/src/recon_buildblock/PinholeSPECTUB_Weight3d.cxx index f649fa6d5..ad50ee821 100644 --- a/src/recon_buildblock/PinholeSPECTUB_Weight3d.cxx +++ b/src/recon_buildblock/PinholeSPECTUB_Weight3d.cxx @@ -13,14 +13,14 @@ \author Matthew Strugari */ -//system libraries +// system libraries #include #include #include #include #include -//user defined libraries +// user defined libraries #include "stir/recon_buildblock/PinholeSPECTUB_Tools.h" #include "stir/recon_buildblock/PinholeSPECTUB_Weight3d.h" #include "stir/error.h" @@ -31,26 +31,26 @@ namespace SPECTUB_mph { -#define in_limits( a ,l1 , l2 ) ( (a) < (l1) ? (l1) : ( (a) > (l2) ? (l2) : (a) ) ) +#define in_limits(a, l1, l2) ((a) < (l1) ? (l1) : ((a) > (l2) ? (l2) : (a))) #define NUMARG 23 #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)) + //#ifndef M_PI //#define M_PI 3.141592653589793 //#endif //#define dg2rd 0.01745329251994 -#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 using namespace std; @@ -58,458 +58,519 @@ using namespace std; //=== wm_calculation ======================================================= //========================================================================== -void wm_calculation_mph ( bool do_calc, - const int kOS, - psf2d_type *psf_bin, - psf2d_type *psf_subs, - psf2d_type *psf_aux, - psf2d_type *kern, - float *attmap, - bool *msk_3d, - int *Nitems, - wmh_mph_type &wmh, - wm_da_type &wm, - pcf_type &pcf ) +void +wm_calculation_mph(bool do_calc, + const int kOS, + psf2d_type* psf_bin, + psf2d_type* psf_subs, + psf2d_type* psf_aux, + psf2d_type* kern, + float* attmap, + bool* msk_3d, + int* Nitems, + wmh_mph_type& wmh, + wm_da_type& wm, + pcf_type& pcf) { - voxel_type vox; // structure with voxel information - bin_type bin; // structure with bin information - lor_type l; // structure with lor information - discrf2d_type *f; // structure with cumsum function - - float weight; - float coeff_att = (float) 1.; - int jp; - float w_max= -1.; - int Dimxd2, Dimyd2; - - //... collimator parameters ........................................ - - mphcoll_type * c = & wmh.collim; - - //... STIR origin offset ....................................... - Dimxd2 = wmh.vol.Dimx / 2; - Dimyd2 = wmh.vol.Dimy / 2; - - if ( do_calc ){ - - //... STIR indices ....................................................................... - - if ( wm.do_save_STIR ){ - - jp = -1; // projection index (row index of the weight matrix ) - int j1; - - for ( int j = 0 ; j < wmh.prj.NdOS ; j++ ){ - - j1 = kOS; - - for ( int k = 0 ; k < wmh.prj.Nsli ; k++ ){ - - int nbd2 = wmh.prj.Nbin / 2; - - for ( int i = 0 ; i < wmh.prj.Nbin ; i++){ - - jp++; - wm.na[ jp ] = j1; - wm.nb[ jp ] = i - nbd2; - wm.ns[ jp ] = k; + voxel_type vox; // structure with voxel information + bin_type bin; // structure with bin information + lor_type l; // structure with lor information + discrf2d_type* f; // structure with cumsum function + + float weight; + float coeff_att = (float)1.; + int jp; + float w_max = -1.; + int Dimxd2, Dimyd2; + + //... collimator parameters ........................................ + + mphcoll_type* c = &wmh.collim; + + //... STIR origin offset ....................................... + Dimxd2 = wmh.vol.Dimx / 2; + Dimyd2 = wmh.vol.Dimy / 2; + + if (do_calc) + { + + //... STIR indices ....................................................................... + + if (wm.do_save_STIR) + { + + jp = -1; // projection index (row index of the weight matrix ) + int j1; + + for (int j = 0; j < wmh.prj.NdOS; j++) + { + + j1 = kOS; + + for (int k = 0; k < wmh.prj.Nsli; k++) + { + + int nbd2 = wmh.prj.Nbin / 2; + + for (int i = 0; i < wmh.prj.Nbin; i++) + { + + jp++; + wm.na[jp] = j1; + wm.nb[jp] = i - nbd2; + wm.ns[jp] = k; } } } } } - //=== LOOP1: IMAGE SLICES ================================================================ - - for ( vox.iz = wmh.vol.first_sl ; vox.iz < wmh.vol.last_sl ; vox.iz++ ){ - - vox.z = wmh.vol.z0 + vox.iz * wmh.vol.thcm; - - //cout << "weights: " << 100.*(vox.iz+1)/wmh.vol.Dimz << "%" << endl; - - //=== LOOP2: IMAGE ROWS ======================================================================= - - for ( vox.iy = 0 , vox.ip = 0 ; vox.iy < wmh.vol.Dimy ; vox.iy++ ){ - - vox.y = wmh.vol.y0 + vox.iy * wmh.vol.szcm ; // y coordinate of the voxel (index 0->Dimy-1: ix) - - //=== LOOP3: IMAGE COLUMNS ================================================================= - - for ( vox.ix = 0 ; vox.ix < wmh.vol.Dimx ; vox.ix++, vox.ip++ ){ - - vox.iv = vox.iz * wmh.vol.Npix + vox.ip; - - if ( !msk_3d[ vox.iv ] ) continue; - - vox.x = wmh.vol.x0 + vox.ix * wmh.vol.szcm ; // x coordinate of the voxel (index 0->Dimx-1: ix) - - //=== LOOP4: DETELS: DETECTOR ELEMENTS =========================================== - - for( int k = 0 ; k < wmh.prj.NdOS ; k++ ){ - - detel_type * d = & wmh.detel[ kOS ]; - - //... cordinates of the voxel in the rotated reference system. ................. - - vox.x1 = vox.x * d->costh + vox.y * d->sinth ; - vox.y1 = -vox.x * d->sinth + vox.y * d->costh ; - - //=== LOOP5: HOLES PER DETEL ==================================== - - for( int ih = 0 ; ih < d->nh ; ih++ ){ - - hole_type * h = &c->holes[ d->who[ ih ] ]; - - if ( !check_xang_par( &vox, h ) ) continue; - if ( !check_zang_par( &vox, h ) ) continue; - - //...vector voxel-hole, angles and distances............................... - - voxel_projection_mph ( &l , &vox , h, wmh ); - - //... hole shape ....................................... - - if ( h->do_round ) f = &pcf.round; - else f = &pcf.square; - - //... geometrical part of the PSF .................................... - - if ( wmh.do_subsamp ){ - - if ( wmh.do_depth ) fill_psf_depth ( psf_subs, &l, f, wmh.subsamp, do_calc, wmh, pcf ); - - else fill_psf_geo ( psf_subs, &l, f, wmh.subsamp, do_calc, wmh ); - - if ( wmh.do_psfi ) psf_convol ( psf_subs, psf_aux, kern, do_calc ); - - downsample_psf( psf_subs, psf_bin, wmh.subsamp, do_calc ); + //=== LOOP1: IMAGE SLICES ================================================================ + + for (vox.iz = wmh.vol.first_sl; vox.iz < wmh.vol.last_sl; vox.iz++) + { + + vox.z = wmh.vol.z0 + vox.iz * wmh.vol.thcm; + + // cout << "weights: " << 100.*(vox.iz+1)/wmh.vol.Dimz << "%" << endl; + + //=== LOOP2: IMAGE ROWS ======================================================================= + + for (vox.iy = 0, vox.ip = 0; vox.iy < wmh.vol.Dimy; vox.iy++) + { + + vox.y = wmh.vol.y0 + vox.iy * wmh.vol.szcm; // y coordinate of the voxel (index 0->Dimy-1: ix) + + //=== LOOP3: IMAGE COLUMNS ================================================================= + + for (vox.ix = 0; vox.ix < wmh.vol.Dimx; vox.ix++, vox.ip++) + { + + vox.iv = vox.iz * wmh.vol.Npix + vox.ip; + + if (!msk_3d[vox.iv]) + continue; + + vox.x = wmh.vol.x0 + vox.ix * wmh.vol.szcm; // x coordinate of the voxel (index 0->Dimx-1: ix) + + //=== LOOP4: DETELS: DETECTOR ELEMENTS =========================================== + + for (int k = 0; k < wmh.prj.NdOS; k++) + { + + detel_type* d = &wmh.detel[kOS]; + + //... cordinates of the voxel in the rotated reference system. ................. + + vox.x1 = vox.x * d->costh + vox.y * d->sinth; + vox.y1 = -vox.x * d->sinth + vox.y * d->costh; + + //=== LOOP5: HOLES PER DETEL ==================================== + + for (int ih = 0; ih < d->nh; ih++) + { + + hole_type* h = &c->holes[d->who[ih]]; + + if (!check_xang_par(&vox, h)) + continue; + if (!check_zang_par(&vox, h)) + continue; + + //...vector voxel-hole, angles and distances............................... + + voxel_projection_mph(&l, &vox, h, wmh); + + //... hole shape ....................................... + + if (h->do_round) + f = &pcf.round; + else + f = &pcf.square; + + //... geometrical part of the PSF .................................... + + if (wmh.do_subsamp) + { + + if (wmh.do_depth) + fill_psf_depth(psf_subs, &l, f, wmh.subsamp, do_calc, wmh, pcf); + + else + fill_psf_geo(psf_subs, &l, f, wmh.subsamp, do_calc, wmh); + + if (wmh.do_psfi) + psf_convol(psf_subs, psf_aux, kern, do_calc); + + downsample_psf(psf_subs, psf_bin, wmh.subsamp, do_calc); } - - else fill_psf_geo ( psf_bin, &l, f, 1, do_calc, wmh ); - - //... calculus of simple attenuation ............................. - - if ( do_calc ){ - - if ( wmh.do_att && !wmh.do_full_att ){ // simple correction for attenuation - - bin.x = d->x0 + l.x1d_l * d->costh; // x coord of the projection of the center of the voxel in - bin.y = d->y0 + l.x1d_l * d->sinth; - bin.z = d->z0 + l.z1d_l ; - - coeff_att = calc_att_mph( bin, vox, attmap, wmh ); + + else + fill_psf_geo(psf_bin, &l, f, 1, do_calc, wmh); + + //... calculus of simple attenuation ............................. + + if (do_calc) + { + + if (wmh.do_att && !wmh.do_full_att) + { // simple correction for attenuation + + bin.x = d->x0 + l.x1d_l * d->costh; // x coord of the projection of the center of the voxel in + bin.y = d->y0 + l.x1d_l * d->sinth; + bin.z = d->z0 + l.z1d_l; + + coeff_att = calc_att_mph(bin, vox, attmap, wmh); } } - - //=== LOOP6: z-dim of PSF ==================================== - - for ( int j = 0, jb = psf_bin->jb0 ; j < psf_bin->dimz ; j++, jb++ ){ - - if ( jb < 0 ) continue; - if ( jb >= wmh.prj.Nsli ) continue; - - //=== LOOP7: x-dim of PSF ==================================== - - for ( int i = 0 , ib = psf_bin->ib0 ; i < psf_bin->dimx ; i++, ib++ ){ - - if ( ib < 0 ) continue; - if ( ib >= wmh.prj.Nbin ) continue; - - jp = k * wmh.prj.NbOS + jb * wmh.prj.Nbin + ib ; - - if ( do_calc ) { - - weight = psf_bin->val[ j ][ i ] * l.eff / psf_bin->sum ; - - if ( weight < wmh.mn_w ) continue ; - - //... to fill image STIR indices ........................... - - if ( wm.do_save_STIR ){ - wm.nx[ vox.iv ] = (short int)( vox.ix - Dimxd2 ) ; // centered index for STIR format - wm.ny[ vox.iv ] = (short int)( vox.iy - Dimyd2 ) ; // centered index for STIR format - wm.nz[ vox.iv ] = (short int) vox.iz ; // non-centered index for STIR format + + //=== LOOP6: z-dim of PSF ==================================== + + for (int j = 0, jb = psf_bin->jb0; j < psf_bin->dimz; j++, jb++) + { + + if (jb < 0) + continue; + if (jb >= wmh.prj.Nsli) + continue; + + //=== LOOP7: x-dim of PSF ==================================== + + for (int i = 0, ib = psf_bin->ib0; i < psf_bin->dimx; i++, ib++) + { + + if (ib < 0) + continue; + if (ib >= wmh.prj.Nbin) + continue; + + jp = k * wmh.prj.NbOS + jb * wmh.prj.Nbin + ib; + + if (do_calc) + { + + weight = psf_bin->val[j][i] * l.eff / psf_bin->sum; + + if (weight < wmh.mn_w) + continue; + + //... to fill image STIR indices ........................... + + if (wm.do_save_STIR) + { + wm.nx[vox.iv] = (short int)(vox.ix - Dimxd2); // centered index for STIR format + wm.ny[vox.iv] = (short int)(vox.iy - Dimyd2); // centered index for STIR format + wm.nz[vox.iv] = (short int)vox.iz; // non-centered index for STIR format } - - //... calculus of full attenuation ............... - - if ( wmh.do_full_att ){ - - bin.x = d->xbin0 + (float) ib * d->incx ; - bin.y = d->ybin0 + (float) ib * d->incy ; - bin.z = d->zbin0 + (float) jb * wmh.prj.thcm ; - - coeff_att = calc_att_mph( bin, vox, attmap, wmh ); + + //... calculus of full attenuation ............... + + if (wmh.do_full_att) + { + + bin.x = d->xbin0 + (float)ib * d->incx; + bin.y = d->ybin0 + (float)ib * d->incy; + bin.z = d->zbin0 + (float)jb * wmh.prj.thcm; + + coeff_att = calc_att_mph(bin, vox, attmap, wmh); } - - //... calculus and storage of the weight............ - - weight = weight * coeff_att; - - if ( weight > w_max ) w_max = weight; - - 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, "" ); + + //... calculus and storage of the weight............ + + weight = weight * coeff_att; + + if (weight > w_max) + w_max = weight; + + 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, ""); } - - else Nitems[ jp ]++; // for size estimation - - } //....... end 0f LOOP7: x-dim of PSF - } //........... end 0f LOOP6: z-dim of PSF - } //............... end of LOOP5: hole in detection element - } //................... end of LOOP4: detection element - } //....................... end of LOOP3: image rows - } //........................... end of LOOP2: image cols - } //............................... end of LOOP1: image slices - - // if ( do_calc ) cout << "Maximum weight: " << w_max << endl; + + else + Nitems[jp]++; // for size estimation + + } //....... end 0f LOOP7: x-dim of PSF + } //........... end 0f LOOP6: z-dim of PSF + } //............... end of LOOP5: hole in detection element + } //................... end of LOOP4: detection element + } //....................... end of LOOP3: image rows + } //........................... end of LOOP2: image cols + } //............................... end of LOOP1: image slices + + // if ( do_calc ) cout << "Maximum weight: " << w_max << endl; } //========================================================================== //=== fill_psfi ============================================================ //========================================================================== -void fill_psfi( psf2d_type * kern, wmh_mph_type &wmh ) +void +fill_psfi(psf2d_type* kern, wmh_mph_type& wmh) { - //float K0 = (float)0.39894228040143 / wmh.prj.sgm_i ; //Normalization factor: 1/sqrt(2*M_PI)/sigma - float K0 = (1.0f/boost::math::constants::root_two_pi()) / wmh.prj.sgm_i ; //Normalization factor: 1/sqrt(2*M_PI)/sigma - float f1 = - (float) 0.5 / ( wmh.prj.sgm_i * wmh.prj.sgm_i ); - - float * g1d; - float * g2d; - - g1d = new float [ kern->dimx ]; - for ( int i = 0 ; i < kern->dimx ; i++ ) g1d[ i ] = (float) 0.; - - g2d = new float [ kern->dimz ]; - for ( int i = 0; i < kern->dimz ; i++ ) g2d[ i ] = (float) 0.; - - int dimxd2 = kern->dimx / 2; - int dimzd2 = kern->dimz / 2; - - float res1 = wmh.prj.szcm / wmh.subsamp ; - float res2 = wmh.prj.thcm / wmh.subsamp ; - - //... 1d density function .................. - - float x = 0; - g1d[ dimxd2 ] = K0 ; - - for( int i = 1 ; i <= dimxd2 ; i++ ){ - - x += res1 ; - g1d[ dimxd2 - i ] = K0 * exp( f1 * x * x ); - g1d[ dimxd2 + i ] = g1d[ dimxd2 - i ]; - } - - //... 1d density function .................... - - float y = 0; - g2d[ dimzd2 ] = K0 ; - - for( int i = 1 ; i <= dimzd2 ; i++ ){ - - y += res2 ; - g2d[ dimzd2 - i ] = K0 * exp( f1 * y * y ); - g2d[ dimzd2 + i ] = g2d[ dimzd2 - i ]; - } - - //... to fill kern .................. - - float sum = (float) 0. ; - - for ( int j = 0 ; j < kern->dimz ; j++){ - - for ( int i = 0 ; i < kern->dimx ; i++ ){ - - kern->val[ j ][ i ] = g2d[ j ] * g1d[ i] ; - - sum += kern->val[ j ][ i ]; + // float K0 = (float)0.39894228040143 / wmh.prj.sgm_i ; //Normalization factor: 1/sqrt(2*M_PI)/sigma + float K0 = (1.0f / boost::math::constants::root_two_pi()) / wmh.prj.sgm_i; // Normalization factor: 1/sqrt(2*M_PI)/sigma + float f1 = -(float)0.5 / (wmh.prj.sgm_i * wmh.prj.sgm_i); + + float* g1d; + float* g2d; + + g1d = new float[kern->dimx]; + for (int i = 0; i < kern->dimx; i++) + g1d[i] = (float)0.; + + g2d = new float[kern->dimz]; + for (int i = 0; i < kern->dimz; i++) + g2d[i] = (float)0.; + + int dimxd2 = kern->dimx / 2; + int dimzd2 = kern->dimz / 2; + + float res1 = wmh.prj.szcm / wmh.subsamp; + float res2 = wmh.prj.thcm / wmh.subsamp; + + //... 1d density function .................. + + float x = 0; + g1d[dimxd2] = K0; + + for (int i = 1; i <= dimxd2; i++) + { + + x += res1; + g1d[dimxd2 - i] = K0 * exp(f1 * x * x); + g1d[dimxd2 + i] = g1d[dimxd2 - i]; + } + + //... 1d density function .................... + + float y = 0; + g2d[dimzd2] = K0; + + for (int i = 1; i <= dimzd2; i++) + { + + y += res2; + g2d[dimzd2 - i] = K0 * exp(f1 * y * y); + g2d[dimzd2 + i] = g2d[dimzd2 - i]; + } + + //... to fill kern .................. + + float sum = (float)0.; + + for (int j = 0; j < kern->dimz; j++) + { + + for (int i = 0; i < kern->dimx; i++) + { + + kern->val[j][i] = g2d[j] * g1d[i]; + + sum += kern->val[j][i]; } } - //... normalization to area 1 ........................ - - for ( int j = 0 ; j < kern->dimz ; j++){ - - for ( int i = 0 ; i < kern->dimx ; i++ ){ + //... normalization to area 1 ........................ + + for (int j = 0; j < kern->dimz; j++) + { + + for (int i = 0; i < kern->dimx; i++) + { - kern->val[ j ][ i ] /= sum ; + kern->val[j][i] /= sum; } } - - delete [] g1d; - delete [] g2d; + + delete[] g1d; + delete[] g2d; } //========================================================================== //=== check_xang_par ======================================================= //========================================================================== -bool check_xang_par( voxel_type * v, hole_type * h ){ - - bool ans = true; - - //...vector voxel-hole, angles and distances............................... - - float ux1 = h->x1 - v->x1 ; - float uy1 = h->y1 - v->y1 ; - - if ( uy1 <= EPSILON ) error_weight3d ( 88, "" ); - - float a = atan2f( ux1, uy1 ) ; - - if ( a > h->ax_M || a < h->ax_m ) ans = false ; - - return( ans ); +bool +check_xang_par(voxel_type* v, hole_type* h) +{ + + bool ans = true; + + //...vector voxel-hole, angles and distances............................... + + float ux1 = h->x1 - v->x1; + float uy1 = h->y1 - v->y1; + + if (uy1 <= EPSILON) + error_weight3d(88, ""); + + float a = atan2f(ux1, uy1); + + if (a > h->ax_M || a < h->ax_m) + ans = false; + + return (ans); } //========================================================================== //=== check_zang_par ======================================================= //========================================================================== -bool check_zang_par( voxel_type * v, hole_type * h ){ - - bool ans = true; - - float uz1 = h->z1 - v->z ; - float uy1 = h->y1 - v->y1 ; - - float a = atan2f( uz1 , uy1 ) ; - - if ( a > h->az_M || a < h->az_m ) ans = false ; - return ( ans ); +bool +check_zang_par(voxel_type* v, hole_type* h) +{ + + bool ans = true; + + float uz1 = h->z1 - v->z; + float uy1 = h->y1 - v->y1; + + float a = atan2f(uz1, uy1); + + if (a > h->az_M || a < h->az_m) + ans = false; + return (ans); } //========================================================================== //=== voxel_projection ===================================================== //========================================================================== -void voxel_projection_mph ( lor_type * l, voxel_type * v, hole_type * h, wmh_mph_type &wmh ) +void +voxel_projection_mph(lor_type* l, voxel_type* v, hole_type* h, wmh_mph_type& wmh) { - - //...vector voxel-hole, angles and distances............................... - - float ux1 = h->x1 - v->x1 ; - float uy1 = h->y1 - v->y1 ; - float uz1 = h->z1 - v->z ; - - if ( uy1 <= EPSILON ) error_weight3d(88, "" ); - - //...vector voxel-hole and distances............................... - - float dxyz_2 = ux1 * ux1 + uy1 * uy1 + uz1 * uz1 ; - float dvh_l = sqrtf( dxyz_2 ); - - ux1 /= dvh_l; - uy1 /= dvh_l; - uz1 /= dvh_l; - - //...distance over voxel-hole line from voxel and hole to detection plane.......... - - float dvd_l = ( wmh.prj.rad - v->y1 ) / uy1 ; - - l->x1d_l = v->x1 + dvd_l * ux1 ; - l->z1d_l = v->z + dvd_l * uz1 ; - - //...shadow of the hole .......... - - l->hsxcm_d = h->dxcm * dvd_l / dvh_l ; - l->hszcm_d = h->dzcm * dvd_l / dvh_l ; - l->hsxcm_d_d2 = l->hsxcm_d / (float)2. ; - l->hszcm_d_d2 = l->hszcm_d / (float)2. ; - - //... values at detection + crystal distance ................................ - - if ( wmh.do_depth ){ - - float dvdc_l = ( wmh.prj.radc - v->y1 )/ uy1 ; - - l->hsxcm_dc = h->dxcm * dvdc_l / dvh_l ; - l->hszcm_dc = h->dzcm * dvdc_l / dvh_l ; - - l->hsxcm_dc_d2 = l->hsxcm_d / (float)2. ; - l->hszcm_dc_d2 = l->hszcm_d / (float)2. ; - - l->x1dc_l = v->x1 + dvdc_l * ux1 ; - l->z1dc_l = v->z + dvdc_l * uz1 ; + + //...vector voxel-hole, angles and distances............................... + + float ux1 = h->x1 - v->x1; + float uy1 = h->y1 - v->y1; + float uz1 = h->z1 - v->z; + + if (uy1 <= EPSILON) + error_weight3d(88, ""); + + //...vector voxel-hole and distances............................... + + float dxyz_2 = ux1 * ux1 + uy1 * uy1 + uz1 * uz1; + float dvh_l = sqrtf(dxyz_2); + + ux1 /= dvh_l; + uy1 /= dvh_l; + uz1 /= dvh_l; + + //...distance over voxel-hole line from voxel and hole to detection plane.......... + + float dvd_l = (wmh.prj.rad - v->y1) / uy1; + + l->x1d_l = v->x1 + dvd_l * ux1; + l->z1d_l = v->z + dvd_l * uz1; + + //...shadow of the hole .......... + + l->hsxcm_d = h->dxcm * dvd_l / dvh_l; + l->hszcm_d = h->dzcm * dvd_l / dvh_l; + l->hsxcm_d_d2 = l->hsxcm_d / (float)2.; + l->hszcm_d_d2 = l->hszcm_d / (float)2.; + + //... values at detection + crystal distance ................................ + + if (wmh.do_depth) + { + + float dvdc_l = (wmh.prj.radc - v->y1) / uy1; + + l->hsxcm_dc = h->dxcm * dvdc_l / dvh_l; + l->hszcm_dc = h->dzcm * dvdc_l / dvh_l; + + l->hsxcm_dc_d2 = l->hsxcm_d / (float)2.; + l->hszcm_dc_d2 = l->hszcm_d / (float)2.; + + l->x1dc_l = v->x1 + dvdc_l * ux1; + l->z1dc_l = v->z + dvdc_l * uz1; } - - //... effectiveness ...................................................... - - l->eff = wmh.mndvh2 / dxyz_2 * fabsf ( uy1 ) ; + + //... effectiveness ...................................................... + + l->eff = wmh.mndvh2 / dxyz_2 * fabsf(uy1); } //========================================================================== //=== fill_psf_geo ========================================================= //========================================================================== -void fill_psf_geo ( psf2d_type * psf, lor_type *l, discrf2d_type *f, int factor, bool do_calc, wmh_mph_type &wmh ) -{ - psf->xc = l->x1d_l + wmh.prj.FOVxcmd2; // x distance of center of PSF to the begin of the FOVcm - psf->zc = l->z1d_l + wmh.prj.FOVzcmd2; // z distance of center of PSF to the begin of the FOVcm - - float xm = psf->xc - l->hsxcm_d_d2 ; - float xM = psf->xc + l->hsxcm_d_d2 ; - float zm = psf->zc - l->hszcm_d_d2 ; - float zM = psf->zc + l->hszcm_d_d2 ; - - float resx = f->res * l->hsxcm_d ; - float resz = f->res * l->hszcm_d ; - - //... first and last bin indices (they can be out of bound) ........ - - psf->ib0 = (int) floorf( xm / wmh.prj.szcm ) ; - psf->jb0 = (int) floorf( zm / wmh.prj.thcm ) ; - - int ib1 = (int) floorf ( xM / wmh.prj.szcm ) + 1 ; - int jb1 = (int) floorf ( zM / wmh.prj.thcm ) + 1 ; - - //... number of elements of the PSF .............................................................. - - psf->dimx = ( ib1 - psf->ib0 ) * factor ; - - if ( psf->dimx > psf->max_dimx ) error_wmtools_SPECT_mph(78, psf->dimx , "geo_dimx"); - - psf->dimz = ( jb1 - psf->jb0 ) * factor ; - - if ( psf->dimz > psf->max_dimz ) error_wmtools_SPECT_mph(78, psf->dimz , "geo_dimz"); - - //... increment of indices in PSF space to cover a bin ........................................... - - if ( do_calc ){ - - int if1, if2, jf1, jf2 ; - - int incxf = (int) roundf( wmh.prj.szcm / ( resx * (float)factor ) ); - int inczf = (int) roundf( wmh.prj.thcm / ( resz * (float)factor ) ); - - //... to fill psf ........................... - - float x0 = (float)psf->ib0 * wmh.prj.szcm ; // x distance from the first bin in psf from the begin of the FOVcm - float z0 = (float)psf->jb0 * wmh.prj.thcm ; // z distance from the first bin in psf from the begin of the FOVcm - - int if0 = (int) roundf( ( x0 - xm ) / resx ); // index of limit of the first bin of psf, in f space. It should be negative - int jf0 = (int) roundf( ( z0 - zm ) / resz ); // index of limit of the first bin of psf, in f space. It should be negative - - psf->sum = (float)0. ; - - for ( int j = 0 ; j < psf->dimz ; j++ ){ - - jf1 = minim ( maxim ( jf0 + j * inczf, 0 ), f->j_max ); - jf2 = maxim ( minim ( jf0 + ( j + 1 ) * inczf, f->j_max ) , 0 ) ; - - for ( int i = 0 ; i < psf->dimx ; i++ ){ - - if1 = minim ( maxim ( if0 + i * incxf, 0 ), f->i_max ); - if2 = maxim ( minim ( if0 + ( i + 1 ) * incxf, f->i_max ) , 0 ) ; - - psf->val [ j ][ i ] = f->val [ jf2 ][ if2 ] + f->val [ jf1 ][ if1 ] - f->val [ jf1 ][ if2 ] - f->val [ jf2 ][ if1 ]; - - psf->sum += psf->val [ j ][ i ]; +void +fill_psf_geo(psf2d_type* psf, lor_type* l, discrf2d_type* f, int factor, bool do_calc, wmh_mph_type& wmh) +{ + psf->xc = l->x1d_l + wmh.prj.FOVxcmd2; // x distance of center of PSF to the begin of the FOVcm + psf->zc = l->z1d_l + wmh.prj.FOVzcmd2; // z distance of center of PSF to the begin of the FOVcm + + float xm = psf->xc - l->hsxcm_d_d2; + float xM = psf->xc + l->hsxcm_d_d2; + float zm = psf->zc - l->hszcm_d_d2; + float zM = psf->zc + l->hszcm_d_d2; + + float resx = f->res * l->hsxcm_d; + float resz = f->res * l->hszcm_d; + + //... first and last bin indices (they can be out of bound) ........ + + psf->ib0 = (int)floorf(xm / wmh.prj.szcm); + psf->jb0 = (int)floorf(zm / wmh.prj.thcm); + + int ib1 = (int)floorf(xM / wmh.prj.szcm) + 1; + int jb1 = (int)floorf(zM / wmh.prj.thcm) + 1; + + //... number of elements of the PSF .............................................................. + + psf->dimx = (ib1 - psf->ib0) * factor; + + if (psf->dimx > psf->max_dimx) + error_wmtools_SPECT_mph(78, psf->dimx, "geo_dimx"); + + psf->dimz = (jb1 - psf->jb0) * factor; + + if (psf->dimz > psf->max_dimz) + error_wmtools_SPECT_mph(78, psf->dimz, "geo_dimz"); + + //... increment of indices in PSF space to cover a bin ........................................... + + if (do_calc) + { + + int if1, if2, jf1, jf2; + + int incxf = (int)roundf(wmh.prj.szcm / (resx * (float)factor)); + int inczf = (int)roundf(wmh.prj.thcm / (resz * (float)factor)); + + //... to fill psf ........................... + + float x0 = (float)psf->ib0 * wmh.prj.szcm; // x distance from the first bin in psf from the begin of the FOVcm + float z0 = (float)psf->jb0 * wmh.prj.thcm; // z distance from the first bin in psf from the begin of the FOVcm + + int if0 = (int)roundf((x0 - xm) / resx); // index of limit of the first bin of psf, in f space. It should be negative + int jf0 = (int)roundf((z0 - zm) / resz); // index of limit of the first bin of psf, in f space. It should be negative + + psf->sum = (float)0.; + + for (int j = 0; j < psf->dimz; j++) + { + + jf1 = minim(maxim(jf0 + j * inczf, 0), f->j_max); + jf2 = maxim(minim(jf0 + (j + 1) * inczf, f->j_max), 0); + + for (int i = 0; i < psf->dimx; i++) + { + + if1 = minim(maxim(if0 + i * incxf, 0), f->i_max); + if2 = maxim(minim(if0 + (i + 1) * incxf, f->i_max), 0); + + psf->val[j][i] = f->val[jf2][if2] + f->val[jf1][if1] - f->val[jf1][if2] - f->val[jf2][if1]; + + psf->sum += psf->val[j][i]; } } } @@ -519,198 +580,207 @@ void fill_psf_geo ( psf2d_type * psf, lor_type *l, discrf2d_type *f, int factor, //=== fill_psf_depth ========================================================== //============================================================================= -void fill_psf_depth( psf2d_type *psf, lor_type *l, discrf2d_type *f, int factor, bool do_calc, wmh_mph_type &wmh, pcf_type &pcf ) +void +fill_psf_depth(psf2d_type* psf, lor_type* l, discrf2d_type* f, int factor, bool do_calc, wmh_mph_type& wmh, pcf_type& pcf) { - float xc_d = l->x1d_l + wmh.prj.FOVxcmd2; // x distance of center of PSF from the begin of the FOVcm - float zc_d = l->z1d_l + wmh.prj.FOVzcmd2; // z distance of center of PSF from the begin of the FOVcm - - float xc_dc = l->x1dc_l + wmh.prj.FOVxcmd2; // x distance of center of PSF from the begin of the FOVcm - float zc_dc = l->z1dc_l + wmh.prj.FOVzcmd2; // z distance of center of PSF from the begin of the FOVcm - - float resx_d = f->res * l->hsxcm_d ; - float resz_d = f->res * l->hszcm_d ; - - float resx_dc = f->res * l->hsxcm_dc ; - float resz_dc = f->res * l->hszcm_dc ; - - psf->xc = ( xc_d + xc_dc ) / (float)2.; - psf->zc = ( zc_d + zc_dc ) / (float)2.; - - //... distance for correction for attenuation inside the crystal ............................ - - float dcr = sqrtf ( ( l->x1d_l - l->x1dc_l ) * ( l->x1d_l - l->x1dc_l ) + - ( l->z1d_l - l->z1dc_l ) * ( l->z1d_l - l->z1dc_l ) + wmh.prj.crth_2 ) ; - - //... first and last bin indices (they can be out of bound) ........ - - int ib0_d = (int) floorf( ( xc_d - l->hsxcm_d_d2 ) / wmh.prj.szcm ) ; - int jb0_d = (int) floorf( ( zc_d - l->hszcm_d_d2 ) / wmh.prj.thcm ) ; - - int ib1_d = (int) floorf ( ( xc_d + l->hsxcm_d_d2 ) / wmh.prj.szcm ) + 1 ; - int jb1_d = (int) floorf ( ( zc_d + l->hszcm_d_d2 ) / wmh.prj.thcm ) + 1 ; - - int ib0_dc = (int) floorf( ( xc_dc - l->hsxcm_dc_d2 ) / wmh.prj.szcm ) ; - int jb0_dc = (int) floorf( ( zc_dc - l->hszcm_dc_d2 ) / wmh.prj.thcm ) ; - - int ib1_dc = (int) floorf ( ( xc_dc + l->hsxcm_dc_d2 ) / wmh.prj.szcm ) + 1 ; - int jb1_dc = (int) floorf ( ( zc_dc + l->hszcm_dc_d2 ) / wmh.prj.thcm ) + 1 ; - - //... number of elements of the PSF .............................................................. - - psf->ib0 = min( ib0_d, ib0_dc); - psf->jb0 = min( jb0_d, jb0_dc); - - int ib1 = max( ib1_d, ib1_dc); - int jb1 = max( jb1_d, jb1_dc); - - psf->dimx = ( ib1 - psf->ib0 ) * factor ; - psf->dimz = ( jb1 - psf->jb0 ) * factor ; - - if ( do_calc ){ - - int if_d, jf_d, if_dc, jf_dc; - float v; - - float x0_d = (float) psf->ib0 * wmh.prj.szcm; // x distance from the fisrt bin in psf to the begin of the FOVcm - float z0_d = (float) psf->jb0 * wmh.prj.thcm; // z distance from the fisrt bin in psf to the begin of the FOVcm - - //... increments in f space ................................................... - - int incxf_d = (int) roundf( wmh.prj.szcm / ( resx_d * (float) factor ) ); - int inczf_d = (int) roundf( wmh.prj.thcm / ( resz_d * (float) factor ) ); - - int incxf_dc = (int) roundf( wmh.prj.szcm / ( resx_dc * (float) factor ) ); - int inczf_dc = (int) roundf( wmh.prj.thcm / ( resz_dc * (float) factor ) ); - - //... to fill psf ........................... - - int if0_d = ( x0_d - xc_d + l->hsxcm_d_d2 ) / resx_d ; // index of edge of the first bin of psf, in f space. It should be negative - int jf0_d = ( z0_d - zc_d + l->hszcm_d_d2 ) / resz_d ; // index of erdge of the first bin of psf, in f space. It should be negative - - int if0_dc = ( x0_d - xc_dc + l->hsxcm_dc_d2 ) / resx_dc ; // index of edge of the first bin of psf, in f space (negative) - int jf0_dc = ( z0_d - zc_dc + l->hszcm_dc_d2 ) / resz_dc ; // index of edge of the first bin of psf, in f space (negative) - - - //... to initilize to zero .............................. - - for ( int j = 0 ; j < psf->dimz ; j++ ){ - - for ( int i = 0 ; i < psf->dimx ; i++ ) psf->val [ j ][ i ] = (float)0. ; + float xc_d = l->x1d_l + wmh.prj.FOVxcmd2; // x distance of center of PSF from the begin of the FOVcm + float zc_d = l->z1d_l + wmh.prj.FOVzcmd2; // z distance of center of PSF from the begin of the FOVcm + + float xc_dc = l->x1dc_l + wmh.prj.FOVxcmd2; // x distance of center of PSF from the begin of the FOVcm + float zc_dc = l->z1dc_l + wmh.prj.FOVzcmd2; // z distance of center of PSF from the begin of the FOVcm + + float resx_d = f->res * l->hsxcm_d; + float resz_d = f->res * l->hszcm_d; + + float resx_dc = f->res * l->hsxcm_dc; + float resz_dc = f->res * l->hszcm_dc; + + psf->xc = (xc_d + xc_dc) / (float)2.; + psf->zc = (zc_d + zc_dc) / (float)2.; + + //... distance for correction for attenuation inside the crystal ............................ + + float dcr + = sqrtf((l->x1d_l - l->x1dc_l) * (l->x1d_l - l->x1dc_l) + (l->z1d_l - l->z1dc_l) * (l->z1d_l - l->z1dc_l) + wmh.prj.crth_2); + + //... first and last bin indices (they can be out of bound) ........ + + int ib0_d = (int)floorf((xc_d - l->hsxcm_d_d2) / wmh.prj.szcm); + int jb0_d = (int)floorf((zc_d - l->hszcm_d_d2) / wmh.prj.thcm); + + int ib1_d = (int)floorf((xc_d + l->hsxcm_d_d2) / wmh.prj.szcm) + 1; + int jb1_d = (int)floorf((zc_d + l->hszcm_d_d2) / wmh.prj.thcm) + 1; + + int ib0_dc = (int)floorf((xc_dc - l->hsxcm_dc_d2) / wmh.prj.szcm); + int jb0_dc = (int)floorf((zc_dc - l->hszcm_dc_d2) / wmh.prj.thcm); + + int ib1_dc = (int)floorf((xc_dc + l->hsxcm_dc_d2) / wmh.prj.szcm) + 1; + int jb1_dc = (int)floorf((zc_dc + l->hszcm_dc_d2) / wmh.prj.thcm) + 1; + + //... number of elements of the PSF .............................................................. + + psf->ib0 = min(ib0_d, ib0_dc); + psf->jb0 = min(jb0_d, jb0_dc); + + int ib1 = max(ib1_d, ib1_dc); + int jb1 = max(jb1_d, jb1_dc); + + psf->dimx = (ib1 - psf->ib0) * factor; + psf->dimz = (jb1 - psf->jb0) * factor; + + if (do_calc) + { + + int if_d, jf_d, if_dc, jf_dc; + float v; + + float x0_d = (float)psf->ib0 * wmh.prj.szcm; // x distance from the fisrt bin in psf to the begin of the FOVcm + float z0_d = (float)psf->jb0 * wmh.prj.thcm; // z distance from the fisrt bin in psf to the begin of the FOVcm + + //... increments in f space ................................................... + + int incxf_d = (int)roundf(wmh.prj.szcm / (resx_d * (float)factor)); + int inczf_d = (int)roundf(wmh.prj.thcm / (resz_d * (float)factor)); + + int incxf_dc = (int)roundf(wmh.prj.szcm / (resx_dc * (float)factor)); + int inczf_dc = (int)roundf(wmh.prj.thcm / (resz_dc * (float)factor)); + + //... to fill psf ........................... + + int if0_d + = (x0_d - xc_d + l->hsxcm_d_d2) / resx_d; // index of edge of the first bin of psf, in f space. It should be negative + int jf0_d + = (z0_d - zc_d + l->hszcm_d_d2) / resz_d; // index of erdge of the first bin of psf, in f space. It should be negative + + int if0_dc = (x0_d - xc_dc + l->hsxcm_dc_d2) / resx_dc; // index of edge of the first bin of psf, in f space (negative) + int jf0_dc = (z0_d - zc_dc + l->hszcm_dc_d2) / resz_dc; // index of edge of the first bin of psf, in f space (negative) + + //... to initilize to zero .............................. + + for (int j = 0; j < psf->dimz; j++) + { + + for (int i = 0; i < psf->dimx; i++) + psf->val[j][i] = (float)0.; } - psf->sum = (float)0. ; - - //... central part of PSF .......................................... - - for ( int j = 1 ; j < psf->dimz ; j++ ){ - - jf_d = jf0_d + j * inczf_d ; - jf_dc = jf0_dc + j * inczf_dc ; - - for ( int i = 1 ; i < psf->dimx ; i++ ){ - - if_d = if0_d + i * incxf_d ; - if_dc = if0_dc + i * incxf_dc ; - - v = bresenh_f( if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf ); - - psf->val [ j ][ i ] += v ; - psf->val [ j - 1 ][ i - 1 ] += v ; - psf->val [ j - 1 ][ i ] -= v ; - psf->val [ j ][ i - 1 ] -= v ; + psf->sum = (float)0.; + + //... central part of PSF .......................................... + + for (int j = 1; j < psf->dimz; j++) + { + + jf_d = jf0_d + j * inczf_d; + jf_dc = jf0_dc + j * inczf_dc; + + for (int i = 1; i < psf->dimx; i++) + { + + if_d = if0_d + i * incxf_d; + if_dc = if0_dc + i * incxf_dc; + + v = bresenh_f(if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf); + + psf->val[j][i] += v; + psf->val[j - 1][i - 1] += v; + psf->val[j - 1][i] -= v; + psf->val[j][i - 1] -= v; } } - - //... vertical edges PSF .......................................... - - for ( int j = 1 ; j < psf->dimz ; j++ ){ - - jf_d = jf0_d + j * inczf_d ; - jf_dc = jf0_dc + j * inczf_dc ; - - if_d = if0_d ; - if_dc = if0_dc ; - - v = bresenh_f( if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf ); - - psf->val [ j ][ 0 ] += v ; - psf->val [ j - 1 ][ 0 ] -= v ; - - if_d = if0_d + psf->dimx * incxf_d ; - if_dc = if0_dc + psf->dimx * incxf_d ; - - v = bresenh_f( if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf ); - - psf->val [ j ][ psf->dimx - 1 ] -= v ; - psf->val [ j - 1 ][ psf->dimx - 1 ] += v ; + + //... vertical edges PSF .......................................... + + for (int j = 1; j < psf->dimz; j++) + { + + jf_d = jf0_d + j * inczf_d; + jf_dc = jf0_dc + j * inczf_dc; + + if_d = if0_d; + if_dc = if0_dc; + + v = bresenh_f(if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf); + + psf->val[j][0] += v; + psf->val[j - 1][0] -= v; + + if_d = if0_d + psf->dimx * incxf_d; + if_dc = if0_dc + psf->dimx * incxf_d; + + v = bresenh_f(if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf); + + psf->val[j][psf->dimx - 1] -= v; + psf->val[j - 1][psf->dimx - 1] += v; } - - //... horizontal edges PSF .......................................... - - for ( int i = 1 ; i < psf->dimx ; i++ ){ - - jf_d = jf0_d ; - jf_dc = jf0_dc ; - - if_d = if0_d + i * incxf_d ; - if_dc = if0_dc + i * incxf_dc ; - - v = bresenh_f( if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf ); - - psf->val [ 0 ][ i ] += v ; - psf->val [ 0 ][ i - 1 ] -= v ; - - jf_d = jf0_d + psf->dimz * inczf_d ; - jf_dc = jf0_dc + psf->dimz * inczf_d ; - - v = bresenh_f( if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf ); - - psf->val [ psf->dimz - 1 ][ i ] -= v ; - psf->val [ psf->dimz - 1 ][ i - 1 ] += v ; + + //... horizontal edges PSF .......................................... + + for (int i = 1; i < psf->dimx; i++) + { + + jf_d = jf0_d; + jf_dc = jf0_dc; + + if_d = if0_d + i * incxf_d; + if_dc = if0_dc + i * incxf_dc; + + v = bresenh_f(if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf); + + psf->val[0][i] += v; + psf->val[0][i - 1] -= v; + + jf_d = jf0_d + psf->dimz * inczf_d; + jf_dc = jf0_dc + psf->dimz * inczf_d; + + v = bresenh_f(if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf); + + psf->val[psf->dimz - 1][i] -= v; + psf->val[psf->dimz - 1][i - 1] += v; } - - //... four corners ............................................ - - if_d = if0_d ; - if_dc = if0_dc ; - - jf_d = jf0_d ; - jf_dc = jf0_dc ; - - v = bresenh_f( if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf ); - - psf->val [ 0 ][ 0 ] += v ; - psf->sum += v ; - - //... - - if_d = if0_d + psf->dimx * incxf_d ; - if_dc = if0_dc + psf->dimx * incxf_d ; - - v = bresenh_f( if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf ); - - psf->val [ 0 ][ psf->dimx - 1 ] -= v ; - psf->sum -= v ; - - //... - - jf_d = jf0_d + psf->dimz * inczf_d ; - jf_dc = jf0_dc + psf->dimz * inczf_d ; - - v = bresenh_f( if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf ); - - psf->val [ psf->dimz - 1 ][ psf->dimx - 1 ] += v ; - psf->sum += v ; - - //... - - if_d = if0_d ; - if_dc = if0_dc ; - - v = bresenh_f( if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf ); - - psf->val [ psf->dimz - 1 ][ 0 ] -= v ; - psf->sum -= v ; + + //... four corners ............................................ + + if_d = if0_d; + if_dc = if0_dc; + + jf_d = jf0_d; + jf_dc = jf0_dc; + + v = bresenh_f(if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf); + + psf->val[0][0] += v; + psf->sum += v; + + //... + + if_d = if0_d + psf->dimx * incxf_d; + if_dc = if0_dc + psf->dimx * incxf_d; + + v = bresenh_f(if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf); + + psf->val[0][psf->dimx - 1] -= v; + psf->sum -= v; + + //... + + jf_d = jf0_d + psf->dimz * inczf_d; + jf_dc = jf0_dc + psf->dimz * inczf_d; + + v = bresenh_f(if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf); + + psf->val[psf->dimz - 1][psf->dimx - 1] += v; + psf->sum += v; + + //... + + if_d = if0_d; + if_dc = if0_dc; + + v = bresenh_f(if_d, jf_d, if_dc, jf_dc, f->val, f->i_max, f->j_max, dcr, wmh, pcf); + + psf->val[psf->dimz - 1][0] -= v; + psf->sum -= v; } } @@ -718,59 +788,73 @@ void fill_psf_depth( psf2d_type *psf, lor_type *l, discrf2d_type *f, int factor, //=== downsample_psf ======================================================= //========================================================================== -void downsample_psf ( psf2d_type * psf_in, psf2d_type * psf_out, int factor, bool do_calc ) +void +downsample_psf(psf2d_type* psf_in, psf2d_type* psf_out, int factor, bool do_calc) { - - //... temporal check to remove ......................... - - if ( ( psf_in->dimx % factor) != 0 ) error_wmtools_SPECT_mph( 55, psf_in->dimx , "dimx" ); - if ( ( psf_in->dimz % factor) != 0 ) error_wmtools_SPECT_mph( 55, psf_in->dimz , "dimz" ); - - //... dims ................................. - - psf_out->dimx = psf_in->dimx / factor ; - psf_out->dimz = psf_in->dimz / factor ; - - psf_out->ib0 = psf_in->ib0; - psf_out->jb0 = psf_in->jb0; - - if ( do_calc ){ - - if ( psf_out->dimx > psf_out->max_dimx ) error_wmtools_SPECT_mph( 56, psf_out->dimx , "dimx" ); - if ( psf_out->dimz > psf_out->max_dimz ) error_wmtools_SPECT_mph( 56, psf_out->dimz , "dimz" ); - - //... to fill values ........................ - - psf_out->sum = (float) 0. ; - - if ( factor == 1 ){ - - for ( int j = 0 ; j < psf_out->dimz ; j++ ){ - for ( int i = 0 ; i < psf_out->dimx ; i++ ){ - - psf_out->val[ j ][ i ] = psf_in->val[ j ][ i ] ; - psf_out->sum += psf_out->val[ j ][ i ]; + + //... temporal check to remove ......................... + + if ((psf_in->dimx % factor) != 0) + error_wmtools_SPECT_mph(55, psf_in->dimx, "dimx"); + if ((psf_in->dimz % factor) != 0) + error_wmtools_SPECT_mph(55, psf_in->dimz, "dimz"); + + //... dims ................................. + + psf_out->dimx = psf_in->dimx / factor; + psf_out->dimz = psf_in->dimz / factor; + + psf_out->ib0 = psf_in->ib0; + psf_out->jb0 = psf_in->jb0; + + if (do_calc) + { + + if (psf_out->dimx > psf_out->max_dimx) + error_wmtools_SPECT_mph(56, psf_out->dimx, "dimx"); + if (psf_out->dimz > psf_out->max_dimz) + error_wmtools_SPECT_mph(56, psf_out->dimz, "dimz"); + + //... to fill values ........................ + + psf_out->sum = (float)0.; + + if (factor == 1) + { + + for (int j = 0; j < psf_out->dimz; j++) + { + for (int i = 0; i < psf_out->dimx; i++) + { + + psf_out->val[j][i] = psf_in->val[j][i]; + psf_out->sum += psf_out->val[j][i]; } } } - else{ - for ( int j = 0 ; j < psf_out->dimz ; j++ ){ - - int jfa = j * factor; - - for ( int i = 0 ; i < psf_out->dimx ; i++ ){ - - int ifa = i * factor; - - psf_out->val[ j ][ i ] = (float) 0.; - - for ( int m = 0 ; m < factor ; m++ ){ - for ( int n = 0 ; n < factor ; n++ ){ - - psf_out->val[ j ][ i ] += psf_in->val[ jfa + m ][ ifa + n ] ; + else + { + for (int j = 0; j < psf_out->dimz; j++) + { + + int jfa = j * factor; + + for (int i = 0; i < psf_out->dimx; i++) + { + + int ifa = i * factor; + + psf_out->val[j][i] = (float)0.; + + for (int m = 0; m < factor; m++) + { + for (int n = 0; n < factor; n++) + { + + psf_out->val[j][i] += psf_in->val[jfa + m][ifa + n]; } } - psf_out->sum += psf_out->val[ j ][ i ]; + psf_out->sum += psf_out->val[j][i]; } } } @@ -781,266 +865,299 @@ void downsample_psf ( psf2d_type * psf_in, psf2d_type * psf_out, int factor, boo //=== psf_conv ============================================================= //========================================================================== -void psf_convol( psf2d_type * psf, psf2d_type * psf_aux, psf2d_type * kern, bool do_calc ) +void +psf_convol(psf2d_type* psf, psf2d_type* psf_aux, psf2d_type* kern, bool do_calc) { - int dimx = psf->dimx + kern->dimx - 1 ; - - if ( dimx > psf_aux->max_dimx || dimx > psf->max_dimx ) error_wmtools_SPECT_mph(77, dimx , "conv_dimx"); - - int dimz = psf->dimz + kern->dimz - 1 ; - - if ( dimz > psf_aux->max_dimz || dimz > psf->max_dimz ) error_wmtools_SPECT_mph(77, dimz , "conv_dimz"); - - //... convolution ....................... - - if ( do_calc ){ - - for ( int j = 0 ; j < dimz ; j++ ) { - - int N1 = kern->dimz - j - 1 ; - int N2 = psf->dimz + N1 ; - - for ( int i = 0 ; i < dimx ; i++ ) { - - int M1 = kern->dimx - i - 1 ; - int M2 = psf->dimx + M1 ; - - psf_aux->val[ j ][ i ] = (float)0. ; - - for ( int n = max( N1 , 0 ) ; n < min( N2 , kern->dimz ) ; n++ ) { - - for ( int m = max( M1 , 0 ) ; m < min( M2 , kern->dimx ) ; m++ ) { - - psf_aux->val[ j ][ i ] += kern->val[ n ][ m ] * psf->val[ n - N1 ][ m - M1 ]; + int dimx = psf->dimx + kern->dimx - 1; + + if (dimx > psf_aux->max_dimx || dimx > psf->max_dimx) + error_wmtools_SPECT_mph(77, dimx, "conv_dimx"); + + int dimz = psf->dimz + kern->dimz - 1; + + if (dimz > psf_aux->max_dimz || dimz > psf->max_dimz) + error_wmtools_SPECT_mph(77, dimz, "conv_dimz"); + + //... convolution ....................... + + if (do_calc) + { + + for (int j = 0; j < dimz; j++) + { + + int N1 = kern->dimz - j - 1; + int N2 = psf->dimz + N1; + + for (int i = 0; i < dimx; i++) + { + + int M1 = kern->dimx - i - 1; + int M2 = psf->dimx + M1; + + psf_aux->val[j][i] = (float)0.; + + for (int n = max(N1, 0); n < min(N2, kern->dimz); n++) + { + + for (int m = max(M1, 0); m < min(M2, kern->dimx); m++) + { + + psf_aux->val[j][i] += kern->val[n][m] * psf->val[n - N1][m - M1]; } } } } - - //... to refill psf with new values .................. - - for ( int j = 0 ; j < dimz ; j++ ) { - - for ( int i = 0 ; i < dimx ; i++ ) { - - psf->val[ j ][ i ] = psf_aux->val[ j ][ i ]; + + //... to refill psf with new values .................. + + for (int j = 0; j < dimz; j++) + { + + for (int i = 0; i < dimx; i++) + { + + psf->val[j][i] = psf_aux->val[j][i]; } } } - //... sizes and position .................... - - psf->ib0 += kern->ib0 ; - psf->jb0 += kern->jb0 ; - - psf->dimx = dimx; - psf->dimz = dimz; + //... sizes and position .................... + + psf->ib0 += kern->ib0; + psf->jb0 += kern->jb0; + + psf->dimx = dimx; + psf->dimz = dimz; } //========================================================================== //=== bresenh_f ============================================================ //========================================================================== -float bresenh_f( int i1, int j1, int i2, int j2, float ** f , int imax, int jmax, float dcr, wmh_mph_type &wmh, pcf_type &pcf ) +float +bresenh_f(int i1, int j1, int i2, int j2, float** f, int imax, int jmax, float dcr, wmh_mph_type& wmh, pcf_type& pcf) { - - int er; //the error term - int di, dj; - - float acum = f[ in_limits ( j1, 0, imax ) ][ in_limits ( i1, 0, jmax ) ]; - - //... difference between starting and ending points.......... - - int Di = i2 - i1; - int Dj = j2 - j1; - - int dist = max ( abs( Di ), abs( Dj ) ); - int ie = 0; - float inc_ie = dcr / ( (float)dist * wmh.highres ); - - //... calculate direction of the vector and store in ix and iy..... - - if ( Di >= 0 ) di = 1; - else { - di = -1; - Di = -Di; + + int er; // the error term + int di, dj; + + float acum = f[in_limits(j1, 0, imax)][in_limits(i1, 0, jmax)]; + + //... difference between starting and ending points.......... + + int Di = i2 - i1; + int Dj = j2 - j1; + + int dist = max(abs(Di), abs(Dj)); + int ie = 0; + float inc_ie = dcr / ((float)dist * wmh.highres); + + //... calculate direction of the vector and store in ix and iy..... + + if (Di >= 0) + di = 1; + else + { + di = -1; + Di = -Di; } - - if ( Dj >= 0 ) dj = 1; - else { - dj = -1; - Dj = -Dj; + + if (Dj >= 0) + dj = 1; + else + { + dj = -1; + Dj = -Dj; } - - //... scale deltas and store in dx2 and dy2..... - - int Di2 = Di * 2; - int Dj2 = Dj * 2; - - if ( Di > Dj ){ // dx is the major axis....... - - //... initialize the error term......... - - er = Dj2 - Di; - - for ( int k = 0 ; k < Di ; k++ ){ - - if (er >= 0){ - - er -= Di2; - j1 += dj; + + //... scale deltas and store in dx2 and dy2..... + + int Di2 = Di * 2; + int Dj2 = Dj * 2; + + if (Di > Dj) + { // dx is the major axis....... + + //... initialize the error term......... + + er = Dj2 - Di; + + for (int k = 0; k < Di; k++) + { + + if (er >= 0) + { + + er -= Di2; + j1 += dj; } - - er += Dj2; - i1 += di; - ie = (int) floorf( inc_ie * (float)k ); - - //if ( ie > pcf.cr_att.i_max ) cout << " out of bounds a bresenh_f " << endl; - - if ( ie <= pcf.cr_att.i_max ) acum += f[ in_limits ( j1, 0, imax ) ][ in_limits ( i1, 0, jmax ) ] * pcf.cr_att.val[ ie ]; + + er += Dj2; + i1 += di; + ie = (int)floorf(inc_ie * (float)k); + + // if ( ie > pcf.cr_att.i_max ) cout << " out of bounds a bresenh_f " << endl; + + if (ie <= pcf.cr_att.i_max) + acum += f[in_limits(j1, 0, imax)][in_limits(i1, 0, jmax)] * pcf.cr_att.val[ie]; } - if ( Di > 0 ) acum /= Di ; + if (Di > 0) + acum /= Di; } - - else { // dy is the major axis.............. - - //... initialize the error term ................ - - er = Di2 - Dj; - - for ( int k = 0 ; k < Dj ; k++ ){ - - if (er >= 0){ - - er -= Dj2; - i1 += di; + + else + { // dy is the major axis.............. + + //... initialize the error term ................ + + er = Di2 - Dj; + + for (int k = 0; k < Dj; k++) + { + + if (er >= 0) + { + + er -= Dj2; + i1 += di; } - - er += Di2; - j1 += dj; - - ie = (int) floorf( inc_ie * (float)k ); - - // if ( ie > pcf.cr_att.i_max ) cout << " out of bounds a bresenh_f " << endl; - //cout << pcf.cr_att.val[ ie ] << endl; - - if ( ie <= pcf.cr_att.i_max ) acum += f[ in_limits ( j1, 0, imax ) ][ in_limits ( i1, 0, jmax ) ] * pcf.cr_att.val[ ie ]; - + + er += Di2; + j1 += dj; + + ie = (int)floorf(inc_ie * (float)k); + + // if ( ie > pcf.cr_att.i_max ) cout << " out of bounds a bresenh_f " << endl; + // cout << pcf.cr_att.val[ ie ] << endl; + + if (ie <= pcf.cr_att.i_max) + acum += f[in_limits(j1, 0, imax)][in_limits(i1, 0, jmax)] * pcf.cr_att.val[ie]; } - if ( Dj > 0 ) acum /= Dj ; + if (Dj > 0) + acum /= Dj; } - return( acum ); + return (acum); } - + //============================================================================= //=== calc_att_mph ============================================================= //============================================================================= -float calc_att_mph( bin_type bin, voxel_type vox, float * attmap, wmh_mph_type &wmh ) +float +calc_att_mph(bin_type bin, voxel_type vox, float* attmap, wmh_mph_type& wmh) { - float dx, dy, dz; - float dlast_x, dlast_y, dlast_z, dlast; - float next_x, next_y, next_z; - int cas; - int iv = vox.iv; - - //... 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 = ux / dpb + EPSILON; // unit vector ux - uy = uy / dpb + EPSILON; // unit vector uy - uz = uz / dpb + EPSILON; // unit vector uz - - //... increment of variables along att pathway ............................ - - int inc_vi_y = signy * wmh.vol.Dimx; - int inc_vi_z = signz * wmh.vol.Npix; - float inc_dx = wmh.vol.szcm * signx / ux ; - float inc_dy = wmh.vol.szcm * signy / uy ; - float inc_dz = wmh.vol.thcm * signz / uz ; - - //... next and last distance to the attenuation map grip .................. - - if ( signx < 0 ){ - next_x = wmh.vol.x0 + ( (float) vox.ix - (float) 0.5 ) * wmh.vol.szcm ; - dlast_x = ( -wmh.vol.FOVxcmd2 - vox.x ) / ux ; - } - else{ - next_x = wmh.vol.x0 + ( (float) vox.ix + (float) 0.5 ) * wmh.vol.szcm ; - dlast_x = ( wmh.vol.FOVxcmd2 - vox.x ) / ux ; - } - - if ( signy < 0 ){ - next_y = wmh.vol.y0 + ( (float) vox.iy - (float) 0.5 ) * wmh.vol.szcm ; - dlast_y = ( -wmh.vol.FOVcmyd2 - vox.y ) / uy ; - } - else{ - next_y = wmh.vol.y0 + ( (float) vox.iy + (float) 0.5 ) * wmh.vol.szcm ; - dlast_y = ( wmh.vol.FOVcmyd2 - vox.y ) / uy ; - } - - if ( signz < 0 ){ - next_z = wmh.vol.z0 +( (float) vox.iz - (float) 0.5 ) * wmh.vol.thcm ; - dlast_z = ( -wmh.vol.FOVzcmd2 - vox.z ) / uz ; - } - else{ - next_z = wmh.vol.z0 + ( (float) vox.iz + (float) 0.5 ) * wmh.vol.thcm ; - dlast_z = ( wmh.vol.FOVzcmd2 - vox.z ) / uz ; - } - - dlast = minim ( minim ( dlast_x, dlast_y ) , minim ( dlast_z , dpb ) ); - - // ... distance to next planes ... - - dx = ( next_x - vox.x ) / ux ; - dy = ( next_y - vox.y ) / uy ; - dz = ( next_z - vox.z ) / uz ; - - //... variables initialization ..................................... - - float dant = (float)0. ; // previous distance (distance from voxel to the last change of voxel in the attenuation map) - float att_coef = (float)0.; - - //... loop while attenuation ray is inside the attenuation map - - for(;;){ - - cas = comp_dist( dx, dy, dz, dlast ); - - switch(cas){ - case 0: - att_coef = exp( -att_coef ); - return ( att_coef ); - case 1: - att_coef += ( dx - dant ) * attmap[ iv ]; - dant = dx ; - iv += signx ; - dx += inc_dx ; - break; - case 2: - att_coef += ( dy - dant ) * attmap[ iv ]; - dant = dy ; - iv += inc_vi_y ; - dy += inc_dy ; - break; - case 3: - att_coef += ( dz - dant ) * attmap[ iv ]; - dant = dz; - iv += inc_vi_z ; - dz += inc_dz ; - break; - default: - error_weight3d (40, ""); + float dx, dy, dz; + float dlast_x, dlast_y, dlast_z, dlast; + float next_x, next_y, next_z; + int cas; + int iv = vox.iv; + + //... 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 = ux / dpb + EPSILON; // unit vector ux + uy = uy / dpb + EPSILON; // unit vector uy + uz = uz / dpb + EPSILON; // unit vector uz + + //... increment of variables along att pathway ............................ + + int inc_vi_y = signy * wmh.vol.Dimx; + int inc_vi_z = signz * wmh.vol.Npix; + float inc_dx = wmh.vol.szcm * signx / ux; + float inc_dy = wmh.vol.szcm * signy / uy; + float inc_dz = wmh.vol.thcm * signz / uz; + + //... next and last distance to the attenuation map grip .................. + + if (signx < 0) + { + next_x = wmh.vol.x0 + ((float)vox.ix - (float)0.5) * wmh.vol.szcm; + dlast_x = (-wmh.vol.FOVxcmd2 - vox.x) / ux; + } + else + { + next_x = wmh.vol.x0 + ((float)vox.ix + (float)0.5) * wmh.vol.szcm; + dlast_x = (wmh.vol.FOVxcmd2 - vox.x) / ux; + } + + if (signy < 0) + { + next_y = wmh.vol.y0 + ((float)vox.iy - (float)0.5) * wmh.vol.szcm; + dlast_y = (-wmh.vol.FOVcmyd2 - vox.y) / uy; + } + else + { + next_y = wmh.vol.y0 + ((float)vox.iy + (float)0.5) * wmh.vol.szcm; + dlast_y = (wmh.vol.FOVcmyd2 - vox.y) / uy; + } + + if (signz < 0) + { + next_z = wmh.vol.z0 + ((float)vox.iz - (float)0.5) * wmh.vol.thcm; + dlast_z = (-wmh.vol.FOVzcmd2 - vox.z) / uz; + } + else + { + next_z = wmh.vol.z0 + ((float)vox.iz + (float)0.5) * wmh.vol.thcm; + dlast_z = (wmh.vol.FOVzcmd2 - vox.z) / uz; + } + + dlast = minim(minim(dlast_x, dlast_y), minim(dlast_z, dpb)); + + // ... distance to next planes ... + + dx = (next_x - vox.x) / ux; + dy = (next_y - vox.y) / uy; + dz = (next_z - vox.z) / uz; + + //... variables initialization ..................................... + + float dant = (float)0.; // previous distance (distance from voxel to the last change of voxel in the attenuation map) + float att_coef = (float)0.; + + //... loop while attenuation ray is inside the attenuation map + + for (;;) + { + + cas = comp_dist(dx, dy, dz, dlast); + + switch (cas) + { + case 0: + att_coef = exp(-att_coef); + return (att_coef); + case 1: + att_coef += (dx - dant) * attmap[iv]; + dant = dx; + iv += signx; + dx += inc_dx; + break; + case 2: + att_coef += (dy - dant) * attmap[iv]; + dant = dy; + iv += inc_vi_y; + dy += inc_dy; + break; + case 3: + att_coef += (dz - dant) * attmap[iv]; + dant = dz; + iv += inc_vi_z; + dz += inc_dz; + break; + default: + error_weight3d(40, ""); } } } @@ -1049,41 +1166,54 @@ float calc_att_mph( bin_type bin, voxel_type vox, float * attmap, wmh_mph_type & //=== comp_dist =============================================================== //============================================================================= -int comp_dist( float dx, - float dy, - float dz, - float dlast) +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 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); } //========================================================================== //=== error_weight3d ======================================================= //========================================================================== -void error_weight3d ( int nerr, string text ) +void +error_weight3d(int nerr, string text) { #if 0 // error messages from original weight3d_SPECT_mph.cpp, some were copied by Carles from SPECTUB i.e. not used. @@ -1102,15 +1232,23 @@ void error_weight3d ( int nerr, string text ) } exit(0); #else - using stir::error; - switch(nerr){ - 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 88: error( "\n\nError weight3d: Voxel located behind or within the hole.\nRevise volume settings or use cyl mask.\n" ); break; - default: printf( "\n\nError %d weight3d: %d unknown error number on error_weight3d().", nerr, nerr ); + using stir::error; + switch (nerr) + { + 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 88: + error("\n\nError weight3d: Voxel located behind or within the hole.\nRevise volume settings or use cyl mask.\n"); + break; + default: + printf("\n\nError %d weight3d: %d unknown error number on error_weight3d().", nerr, nerr); } - exit(0); + exit(0); #endif } -} // end of namespace +} // namespace SPECTUB_mph diff --git a/src/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.cxx b/src/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.cxx index 662cd7c38..4edcbcf2e 100644 --- a/src/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.cxx +++ b/src/recon_buildblock/PoissonLogLikelihoodWithLinearKineticModelAndDynamicProjectionData.cxx @@ -22,12 +22,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 031a346ac..885bb6b5c 100644 --- a/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMean.cxx +++ b/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMean.cxx @@ -35,24 +35,22 @@ 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(); @@ -60,13 +58,11 @@ initialise_keymap() 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; @@ -74,210 +70,189 @@ post_processing() 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->already_set_up = false; this->sensitivity_filename = filename; } -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -set_subsensitivity_filenames(const std::string& filenames) +PoissonLogLikelihoodWithLinearModelForMean::set_subsensitivity_filenames(const std::string& filenames) { this->already_set_up = false; this->subsensitivity_filenames = filenames; try { - const std::string test_sensitivity_filename = - boost::str(boost::format(this->subsensitivity_filenames) % 0); + 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()); + 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->already_set_up = this->already_set_up && (this->use_subset_sensitivities == 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->already_set_up = false; 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==""))) + 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") + 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"); + "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); + std::fill(this->sensitivity_sptr->begin_all(), this->sensitivity_sptr->end_all(), 1); } else { // read from file - try + 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; - } + 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) + 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); + 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()); + "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); + this->subsensitivity_sptrs[subset] = read_from_file(current_sensitivity_filename); string explanation; - if (!target_sptr->has_same_characteristics(*this->subsensitivity_sptrs[subset], - 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()); + 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; - } + 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; + 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)) + if (!target_sptr->has_same_characteristics(*this->sensitivity_sptr, explanation)) { - error("sensitivity and target should have the same characteristics.\n%s", - explanation.c_str()); + error("sensitivity and target should have the same characteristics.\n%s", explanation.c_str()); return Succeeded::no; } } @@ -297,15 +272,15 @@ set_up(shared_ptr const& target_sptr) return Succeeded::no; } - if(!this->subsets_are_approximately_balanced() && !this->get_use_subset_sensitivities()) + 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); + "You need to set 'use_subset_sensitivities' to true to handle this.", + this->num_subsets); return Succeeded::no; } - if(this->recompute_sensitivity) + if (this->recompute_sensitivity) { info("Computing sensitivity"); CPUTimer sens_timer; @@ -322,27 +297,24 @@ set_up(shared_ptr const& target_sptr) { if (this->get_use_subset_sensitivities()) { - if (this->subsensitivity_filenames.size()!=0) + if (this->subsensitivity_filenames.size() != 0) { - for (int subset=0; subsetget_num_subsets(); ++subset) + for (int subset = 0; subset < this->get_num_subsets(); ++subset) { - const std::string current_sensitivity_filename = - boost::str(boost::format(this->subsensitivity_filenames) % 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)); + 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; + 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()); + write_to_file(current_sensitivity_filename, this->get_sensitivity()); } } } @@ -356,54 +328,47 @@ set_up(shared_ptr const& target_sptr) return Succeeded::yes; } -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -compute_sub_gradient_without_penalty(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num) +PoissonLogLikelihoodWithLinearModelForMean::compute_sub_gradient_without_penalty(TargetT& gradient, + const TargetT& current_estimate, + const int subset_num) { if (!this->already_set_up) error("Need to call set_up() for objective function first"); this->actual_compute_subset_gradient_without_penalty(gradient, current_estimate, subset_num, false); } -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -compute_sub_gradient_without_penalty_plus_sensitivity(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num) +PoissonLogLikelihoodWithLinearModelForMean::compute_sub_gradient_without_penalty_plus_sensitivity( + TargetT& gradient, const TargetT& current_estimate, const int subset_num) { if (!this->already_set_up) error("Need to call set_up() for objective function first"); actual_compute_subset_gradient_without_penalty(gradient, current_estimate, subset_num, true); } -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -compute_sensitivities() +PoissonLogLikelihoodWithLinearModelForMean::compute_sensitivities() { // check subset balancing 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()); - } - } // end check balancing + { + 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()); + } + } // end check balancing // compute subset sensitivities - for (int subset_num=0; subset_numnum_subsets; ++subset_num) + 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); + std::fill(this->subsensitivity_sptrs[subset_num]->begin_all(), this->subsensitivity_sptrs[subset_num]->end_all(), 0); } else { @@ -424,7 +389,7 @@ compute_sensitivities() } if (!this->get_use_subset_sensitivities()) { - // copy full sensitivity (currently stored in subsensitivity[0]) + // copy full sensitivity (currently stored in subsensitivity[0]) this->sensitivity_sptr = this->subsensitivity_sptrs[0]; this->subsensitivity_sptrs[0].reset(); } @@ -432,23 +397,23 @@ compute_sensitivities() this->set_total_or_subset_sensitivities(); } -template +template void -PoissonLogLikelihoodWithLinearModelForMean:: -set_total_or_subset_sensitivities() +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) + 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; + ++sens_iter; + ++subsens_iter; } } } @@ -464,40 +429,33 @@ set_total_or_subset_sensitivities() *subsens_iter /= this->num_subsets; } // set all other pointers the same - for (int subset_num=1; subset_numnum_subsets; ++subset_num) + 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) + 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 08ef1eaf4..e1504a607 100644 --- a/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.cxx +++ b/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndGatedProjDataWithMotion.cxx @@ -1,11 +1,11 @@ /* Copyright (C) 2009- 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details - */ + */ /*! \file \ingroup GeneralisedObjectiveFunction @@ -18,11 +18,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 6af8e55f9..b7569f7a0 100644 --- a/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.cxx +++ b/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.cxx @@ -1,29 +1,29 @@ // -// -/* +// +/* Copyright (C) 2003- 2011, Hammersmith Imanet Ltd Copyright (C) 2018, 2022 University College London Copyright (C) 2021, University of Pennsylvania This file is part of STIR. SPDX-License-Identifier: Apache-2.0 - 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 + stir::PoissonLogLikelihoodWithLinearModelForMeanAndListModeData + + \author Kris Thielemans \author Nikos Efthimiou - \author Sanida Mustafovic - -*/ - -#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.h" + \author Sanida Mustafovic + +*/ + +#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeData.h" #include "stir/ProjDataInMemory.h" -#include "stir/Succeeded.h" +#include "stir/Succeeded.h" #include "stir/IO/read_from_file.h" #include "stir/recon_buildblock/TrivialBinNormalisation.h" #include "stir/is_null_ptr.h" @@ -36,32 +36,29 @@ 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 =""; +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::set_defaults() +{ + base_type::set_defaults(); + this->list_mode_filename = ""; + this->frame_defs_filename = ""; this->frame_defs = TimeFrameDefinitions(); - this->list_mode_data_sptr.reset(); - this->additive_projection_data_filename ="0"; + this->list_mode_data_sptr.reset(); + this->additive_projection_data_filename = "0"; this->additive_proj_data_sptr.reset(); this->has_add = false; this->reduce_memory_usage = false; this->normalisation_sptr.reset(new TrivialBinNormalisation); this->current_frame_num = 1; this->num_events_to_use = 0L; - this->max_segment_num_to_process =-1; + this->max_segment_num_to_process = -1; this->target_parameter_parser.set_defaults(); cache_lm_file = false; @@ -69,50 +66,50 @@ set_defaults() skip_lm_input_file = false; cache_path = ""; cache_size = 0; -} - -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); this->parser.add_key("time frame number", &this->current_frame_num); this->parser.add_key("maximum absolute segment number to process", &this->max_segment_num_to_process); - this->parser.add_key("additive sinogram",&this->additive_projection_data_filename); + this->parser.add_key("additive sinogram", &this->additive_projection_data_filename); this->parser.add_key("reduce memory usage", &reduce_memory_usage); this->parser.add_parsing_key("Bin Normalisation type", &this->normalisation_sptr); this->parser.add_key("cache path", &cache_path); this->parser.add_key("max cache size", &cache_size); this->parser.add_key("recompute cache", &recompute_cache); -} +} -template -bool -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::post_processing() +template +bool +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::post_processing() { - if (base_type::post_processing() == true) - return true; + if (base_type::post_processing() == true) + return true; if (this->list_mode_filename.length() == 0 && !this->skip_lm_input_file) - { warning("You need to specify an input file\n"); return true; } + { + warning("You need to specify an input file\n"); + return true; + } if (!this->skip_lm_input_file) { - 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->additive_projection_data_filename != "0") { - info(boost::format("Reading additive projdata data '%1%'") - % additive_projection_data_filename ); + info(boost::format("Reading additive projdata data '%1%'") % additive_projection_data_filename); this->set_additive_proj_data_sptr(ProjData::read_from_file(this->additive_projection_data_filename)); } - if (this->frame_defs_filename.size()!=0) + if (this->frame_defs_filename.size() != 0) { this->frame_defs = TimeFrameDefinitions(this->frame_defs_filename); this->do_time_frame = true; @@ -120,17 +117,16 @@ PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::post_process else { this->frame_defs = TimeFrameDefinitions(); - } + } target_parameter_parser.check_values(); this->already_set_up = false; return false; -} +} template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -set_input_data(const shared_ptr & arg) +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::set_input_data(const shared_ptr& arg) { this->already_set_up = false; try @@ -143,91 +139,81 @@ set_input_data(const shared_ptr & arg) } } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -set_max_segment_num_to_process(const int arg) +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::set_max_segment_num_to_process(const int arg) { this->already_set_up = this->already_set_up && (this->max_segment_num_to_process == arg); this->max_segment_num_to_process = arg; } -template +template int -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -get_max_segment_num_to_process() const +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::get_max_segment_num_to_process() const { return this->max_segment_num_to_process; } template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -set_recompute_cache(bool v) +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::set_recompute_cache(bool v) { this->recompute_cache = v; } template bool -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -get_recompute_cache() const +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::get_recompute_cache() const { return this->recompute_cache; } template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -set_cache_max_size(const unsigned long int arg) +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::set_cache_max_size(const unsigned long int arg) { - cache_size = arg; + cache_size = arg; } - template unsigned long int -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -get_cache_max_size() const +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::get_cache_max_size() const { - return cache_size; + return cache_size; } template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -set_cache_path(const std::string& cache_path_v) +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::set_cache_path(const std::string& cache_path_v) { - cache_path = cache_path_v; + cache_path = cache_path_v; } template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -set_skip_lm_input_file(const bool arg) +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::set_skip_lm_input_file(const bool arg) { - error("set_skip_lm_input_file is not yet supported."); - if(arg && (cache_path.length() > 0)) + error("set_skip_lm_input_file is not yet supported."); + if (arg && (cache_path.length() > 0)) { - skip_lm_input_file = arg; - - std::cout << "PoissonLogLikelihoodWithLinearModelForMeanAndListModeData: Skipping input!" << std::endl; - //!\todo in the future the following statements should be removed. - { - this->set_recompute_sensitivity(!arg); - this->set_use_subset_sensitivities(arg); - this->set_subsensitivity_filenames(cache_path+"sens_%d.hv"); - } - // info(boost::format("Reading sensitivity from '%1%'") % this->get_subsensitivity_filenames()); + skip_lm_input_file = arg; + + std::cout << "PoissonLogLikelihoodWithLinearModelForMeanAndListModeData: Skipping input!" << std::endl; + //!\todo in the future the following statements should be removed. + { + this->set_recompute_sensitivity(!arg); + this->set_use_subset_sensitivities(arg); + this->set_subsensitivity_filenames(cache_path + "sens_%d.hv"); + } + // info(boost::format("Reading sensitivity from '%1%'") % this->get_subsensitivity_filenames()); } - else - error("set_skip_lm_input_file(): First set the cache path!"); + else + error("set_skip_lm_input_file(): First set the cache path!"); } template std::string -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -get_cache_path() const +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::get_cache_path() const { if (this->cache_path.size() > 0) return this->cache_path; @@ -237,8 +223,7 @@ get_cache_path() const template std::string -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -get_cache_filename(unsigned int file_id) const +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::get_cache_filename(unsigned int file_id) const { std::string cache_filename = "my_CACHE" + std::to_string(file_id) + ".bin"; FilePath icache(cache_filename, false); @@ -248,18 +233,16 @@ get_cache_filename(unsigned int file_id) const template const ListModeData& -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -get_input_data() const +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::get_input_data() const { if (is_null_ptr(this->list_mode_data_sptr)) error("get_input_data(): no list mode data set"); return *this->list_mode_data_sptr; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -set_additive_proj_data_sptr(const shared_ptr &arg) +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::set_additive_proj_data_sptr(const shared_ptr& arg) { this->already_set_up = false; try @@ -270,126 +253,111 @@ set_additive_proj_data_sptr(const shared_ptr &arg) { error("set_additive_proj_data_sptr: argument is wrong type. Should be projection data."); } - if (!this->reduce_memory_usage - && is_null_ptr(dynamic_cast(this->additive_proj_data_sptr.get())) - && !this->cache_lm_file - ) + if (!this->reduce_memory_usage && is_null_ptr(dynamic_cast(this->additive_proj_data_sptr.get())) + && !this->cache_lm_file) { this->additive_proj_data_sptr.reset(new ProjDataInMemory(*additive_proj_data_sptr)); } this->has_add = true; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData:: -set_normalisation_sptr(const shared_ptr& arg) +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::set_normalisation_sptr( + const shared_ptr& arg) { this->already_set_up = false; 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_before_sensitivity(shared_ptr const& target_sptr) +PoissonLogLikelihoodWithLinearModelForMeanAndListModeData::set_up_before_sensitivity( + shared_ptr const& target_sptr) { - //if ( base_type::set_up_before_sensitivity(target_sptr) != Succeeded::yes) - // return Succeeded::no; + // if ( base_type::set_up_before_sensitivity(target_sptr) != Succeeded::yes) + // return Succeeded::no; if (is_null_ptr(this->list_mode_data_sptr)) error("No listmode data set"); - this->proj_data_info_sptr = - this->list_mode_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); + this->proj_data_info_sptr = this->list_mode_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); if (this->max_segment_num_to_process > proj_data_info_sptr->get_max_segment_num()) { error("The 'maximum segment number to process' asked for is larger than the number of segments" "in the listmode file. Abort."); } - else if (this->max_segment_num_to_process >= 0 - && max_segment_num_to_process < proj_data_info_sptr->get_max_segment_num()) + else if (this->max_segment_num_to_process >= 0 && max_segment_num_to_process < proj_data_info_sptr->get_max_segment_num()) { - this->proj_data_info_sptr->reduce_segment_range(-max_segment_num_to_process, - max_segment_num_to_process); + this->proj_data_info_sptr->reduce_segment_range(-max_segment_num_to_process, max_segment_num_to_process); } if (this->frame_defs.get_num_frames()) { // check if we need to handle time frame definitions - this->do_time_frame = - (this->num_events_to_use == 0) && - (this->frame_defs.get_start_time(this->current_frame_num) < - this->frame_defs.get_end_time(this->current_frame_num)); + this->do_time_frame = (this->num_events_to_use == 0) + && (this->frame_defs.get_start_time(this->current_frame_num) + < this->frame_defs.get_end_time(this->current_frame_num)); } else { // make a single frame starting from 0. End value will be ignored. - vector > frame_times(1, pair(0,0)); + vector> frame_times(1, pair(0, 0)); this->frame_defs = TimeFrameDefinitions(frame_times); this->do_time_frame = false; } - if(!is_null_ptr(this->additive_proj_data_sptr)) + 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_tof_pos_num() == proj.get_min_tof_pos_num())&& - (add_proj.get_max_tof_pos_num() == proj.get_max_tof_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); - } + 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_tof_pos_num() == proj.get_min_tof_pos_num()) + && (add_proj.get_max_tof_pos_num() == proj.get_max_tof_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) - { - error(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()); - } - } + { + error(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()); + } + } } if (is_null_ptr(this->normalisation_sptr)) { - warning("Invalid normalisation object"); - return Succeeded::no; + warning("Invalid normalisation object"); + return Succeeded::no; } return Succeeded::yes; } -# ifdef _MSC_VER -// prevent warning message on instantiation of abstract class -# pragma warning(disable:4661) -# endif - -template class -PoissonLogLikelihoodWithLinearModelForMeanAndListModeData >; - +#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 b5467eeaa..00a4a3aed 100644 --- a/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.cxx +++ b/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.cxx @@ -11,7 +11,7 @@ /*! \file \ingroup GeneralisedObjectiveFunction - \brief Implementation of class + \brief Implementation of class stir::PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin \author Nikos Efthimiou @@ -19,8 +19,8 @@ \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/ProjDataInfoCylindrical.h" @@ -55,66 +55,61 @@ #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 #ifdef STIR_OPENMP -#include +# include #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(); #if STIR_VERSION < 060000 - this->max_ring_difference_num_to_process =-1; + this->max_ring_difference_num_to_process = -1; #endif - this->PM_sptr.reset(new ProjMatrixByBinUsingRayTracing()); + this->PM_sptr.reset(new ProjMatrixByBinUsingRayTracing()); this->use_tofsens = false; skip_balanced_subsets = false; -} - -template -void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -initialise_keymap() -{ - base_type::initialise_keymap(); - this->parser.add_start_key("PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin Parameters"); +} + +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); #if STIR_VERSION < 060000 -this->parser.add_key("max ring difference num to process", &this->max_ring_difference_num_to_process); + this->parser.add_key("max ring difference num to process", &this->max_ring_difference_num_to_process); #endif - this->parser.add_parsing_key("Matrix type", &this->PM_sptr); + this->parser.add_parsing_key("Matrix type", &this->PM_sptr); - this->parser.add_key("num_events_to_use",&this->num_events_to_use); + this->parser.add_key("num_events_to_use", &this->num_events_to_use); this->parser.add_key("skip checking balanced subsets", &skip_balanced_subsets); -} +} -template -int -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -set_num_subsets(const int new_num_subsets) +template +int +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::set_num_subsets(const int new_num_subsets) { this->already_set_up = this->already_set_up && (this->num_subsets == new_num_subsets); this->num_subsets = new_num_subsets; @@ -123,8 +118,8 @@ set_num_subsets(const int new_num_subsets) template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -set_proj_matrix(const shared_ptr& arg) +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::set_proj_matrix( + const shared_ptr& arg) { this->already_set_up = false; this->PM_sptr = arg; @@ -150,769 +145,741 @@ set_proj_data_info(const ProjData& arg) } #endif -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -set_skip_balanced_subsets(const bool arg) +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::set_skip_balanced_subsets(const bool arg) { skip_balanced_subsets = arg; } #if STIR_VERSION < 060000 -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -set_max_ring_difference(const int arg) +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::set_max_ring_difference(const int arg) { if (is_null_ptr(this->proj_data_info_sptr)) error("set_max_ring_difference can only be called after setting the listmode" " (but is obsolete anyway. Use set_max_segment_num_to_process() instead)."); - auto pdi_cyl_ptr = dynamic_cast(this->proj_data_info_sptr.get()); + auto pdi_cyl_ptr = dynamic_cast(this->proj_data_info_sptr.get()); if (is_null_ptr(pdi_cyl_ptr)) error("set_max_ring_difference can only be called for listmode data with cylindrical proj_data_info" " (but is obsolete anyway. Use set_max_segment_num_to_process() instead)."); - if (pdi_cyl_ptr->get_max_ring_difference(0) != 0 || - pdi_cyl_ptr->get_min_ring_difference(0) != 0) + if (pdi_cyl_ptr->get_max_ring_difference(0) != 0 || pdi_cyl_ptr->get_min_ring_difference(0) != 0) error("set_max_ring_difference can only be called for listmode data with span=1" " (but is obsolete anyway. Use set_max_segment_num_to_process() instead)."); this->set_max_segment_num_to_process(arg); } #endif -template +template bool -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -actual_subsets_are_approximately_balanced(std::string& warning_message) const +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::actual_subsets_are_approximately_balanced( + std::string& warning_message) const { if (this->num_subsets == 1) return true; if (skip_balanced_subsets) { - warning("We skip the check on balanced subsets and presume they are balanced!"); - return true; + warning("We skip the check on balanced subsets and presume they are balanced!"); + return true; } - assert(this->num_subsets>0); - const DataSymmetriesForBins& symmetries = - *this->PM_sptr->get_symmetries_ptr(); + 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); + 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 subset_num = 0; subset_num < this->num_subsets; ++subset_num) + { + for (int segment_num = this->proj_data_info_sptr->get_min_segment_num(); + segment_num <= this->proj_data_info_sptr->get_max_segment_num(); + ++segment_num) { - for (int segment_num = this->proj_data_info_sptr->get_min_segment_num(); - segment_num <= this->proj_data_info_sptr->get_max_segment_num(); ++segment_num) + for (int axial_num = this->proj_data_info_sptr->get_min_axial_pos_num(segment_num); + axial_num < this->proj_data_info_sptr->get_max_axial_pos_num(segment_num); + axial_num++) { - for (int axial_num = this->proj_data_info_sptr->get_min_axial_pos_num(segment_num); - axial_num < this->proj_data_info_sptr->get_max_axial_pos_num(segment_num); - axial_num ++) - { - // For debugging. - // std::cout <proj_data_info_sptr->get_min_tangential_pos_num(); - tang_num < this->proj_data_info_sptr->get_max_tangential_pos_num(); - tang_num ++ ) + for (int tang_num = this->proj_data_info_sptr->get_min_tangential_pos_num(); + tang_num < this->proj_data_info_sptr->get_max_tangential_pos_num(); + tang_num++) + { + for (int view_num = this->proj_data_info_sptr->get_min_view_num() + subset_num; + view_num <= this->proj_data_info_sptr->get_max_view_num(); + view_num += this->num_subsets) { - for(int view_num = this->proj_data_info_sptr->get_min_view_num() + subset_num; - view_num <= this->proj_data_info_sptr->get_max_view_num(); - view_num += this->num_subsets) + for (int timing_pos_num = this->proj_data_info_sptr->get_min_tof_pos_num(); + timing_pos_num <= this->proj_data_info_sptr->get_max_tof_pos_num(); + ++timing_pos_num) { - for (int timing_pos_num = this->proj_data_info_sptr->get_min_tof_pos_num(); - timing_pos_num <= this->proj_data_info_sptr->get_max_tof_pos_num(); - ++timing_pos_num) - { - 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; - - num_bins_in_subset[subset_num] += - symmetries.num_related_bins(tmp_bin); - } + 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; + + num_bins_in_subset[subset_num] += symmetries.num_related_bins(tmp_bin); } } } } } + } - for (int subset_num=1; subset_numnum_subsets; ++subset_num) + for (int subset_num = 1; subset_num < this->num_subsets; ++subset_num) + { + if (num_bins_in_subset[subset_num] != num_bins_in_subset[0]) { - 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" - << this->proj_data_info_sptr->get_num_views() - << "/4 (or if that's not an integer, a divisor of " - << this->proj_data_info_sptr->get_num_views() - << "/2 or " - << this->proj_data_info_sptr->get_num_views() - << ").\n"; - warning_message = str.str(); - return false; - } + 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" + << this->proj_data_info_sptr->get_num_views() << "/4 (or if that's not an integer, a divisor of " + << this->proj_data_info_sptr->get_num_views() << "/2 or " << this->proj_data_info_sptr->get_num_views() << ").\n"; + warning_message = str.str(); + return false; } - return true; + } + return true; } -template -Succeeded -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -set_up_before_sensitivity(shared_ptr const& target_sptr) -{ - if ( base_type::set_up_before_sensitivity(target_sptr) != Succeeded::yes) +template +Succeeded +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::set_up_before_sensitivity( + shared_ptr const& target_sptr) +{ + if (base_type::set_up_before_sensitivity(target_sptr) != Succeeded::yes) return Succeeded::no; #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 - - if (is_null_ptr(this->PM_sptr)) - { error("You need to specify a projection matrix"); } - // set projector to be used for the calculations - this->PM_sptr->set_up(this->proj_data_info_sptr->create_shared_clone(),target_sptr); + if (is_null_ptr(this->PM_sptr)) + { + error("You need to specify a projection matrix"); + } - shared_ptr forward_projector_ptr(new ForwardProjectorByBinUsingProjMatrixByBin(this->PM_sptr)); - shared_ptr back_projector_ptr(new BackProjectorByBinUsingProjMatrixByBin(this->PM_sptr)); + // set projector to be used for the calculations + this->PM_sptr->set_up(this->proj_data_info_sptr->create_shared_clone(), target_sptr); - this->projector_pair_sptr.reset( - new ProjectorByBinPairUsingSeparateProjectors(forward_projector_ptr, back_projector_ptr)); + shared_ptr forward_projector_ptr(new ForwardProjectorByBinUsingProjMatrixByBin(this->PM_sptr)); + shared_ptr back_projector_ptr(new BackProjectorByBinUsingProjMatrixByBin(this->PM_sptr)); - this->projector_pair_sptr->set_up(this->proj_data_info_sptr->create_shared_clone(),target_sptr); + this->projector_pair_sptr.reset(new ProjectorByBinPairUsingSeparateProjectors(forward_projector_ptr, back_projector_ptr)); - if (!this->use_tofsens && (this->proj_data_info_sptr->get_num_tof_poss()>1)) // TODO this check needs to cover the case if we reconstruct only TOF bin 0 - { - // sets non-tof backprojector for sensitivity calculation (clone of the back_projector + set projdatainfo to non-tof) - this->sens_proj_data_info_sptr = this->proj_data_info_sptr->create_non_tof_clone(); - // TODO disable caching of the matrix - this->sens_backprojector_sptr.reset(projector_pair_sptr->get_back_projector_sptr()->clone()); - this->sens_backprojector_sptr->set_up(this->sens_proj_data_info_sptr, target_sptr); - } - else - { - // just use the normal backprojector - this->sens_proj_data_info_sptr = this->proj_data_info_sptr; - this->sens_backprojector_sptr = projector_pair_sptr->get_back_projector_sptr(); - } - if (this->normalisation_sptr->set_up(this->list_mode_data_sptr->get_exam_info_sptr(), - this->sens_proj_data_info_sptr) == Succeeded::no) - { - warning("PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin: " - "set-up of normalisation failed."); - return Succeeded::no; - } + this->projector_pair_sptr->set_up(this->proj_data_info_sptr->create_shared_clone(), target_sptr); + if (!this->use_tofsens + && (this->proj_data_info_sptr->get_num_tof_poss() + > 1)) // TODO this check needs to cover the case if we reconstruct only TOF bin 0 + { + // sets non-tof backprojector for sensitivity calculation (clone of the back_projector + set projdatainfo to non-tof) + this->sens_proj_data_info_sptr = this->proj_data_info_sptr->create_non_tof_clone(); + // TODO disable caching of the matrix + this->sens_backprojector_sptr.reset(projector_pair_sptr->get_back_projector_sptr()->clone()); + this->sens_backprojector_sptr->set_up(this->sens_proj_data_info_sptr, target_sptr); + } + else + { + // just use the normal backprojector + this->sens_proj_data_info_sptr = this->proj_data_info_sptr; + this->sens_backprojector_sptr = projector_pair_sptr->get_back_projector_sptr(); + } + if (this->normalisation_sptr->set_up(this->list_mode_data_sptr->get_exam_info_sptr(), this->sens_proj_data_info_sptr) + == Succeeded::no) + { + warning("PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin: " + "set-up of normalisation failed."); + return Succeeded::no; + } - if (this->current_frame_num<=0) + if (this->current_frame_num <= 0) { - warning("frame_num should be >= 1"); - return Succeeded::no; + 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; - } + 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(this->cache_size > 0 || this->skip_lm_input_file) + if (this->cache_size > 0 || this->skip_lm_input_file) { - this->cache_lm_file = true; - return cache_listmode_file(); + this->cache_lm_file = true; + return cache_listmode_file(); } - else if (this->cache_size == 0 && this->skip_lm_input_file) + else if (this->cache_size == 0 && this->skip_lm_input_file) { - warning("Please set the max cache size for the listmode file"); - this->cache_lm_file = true; - return cache_listmode_file(); + warning("Please set the max cache size for the listmode file"); + this->cache_lm_file = true; + return cache_listmode_file(); } - return Succeeded::yes; -} - - -template -bool -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::post_processing() + return Succeeded::yes; +} + +template +bool +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::post_processing() { if (base_type::post_processing() == true) return true; - - this->proj_data_info_sptr = this->list_mode_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); + + this->proj_data_info_sptr = this->list_mode_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); #if STIR_VERSION < 060000 - if (this->get_max_segment_num_to_process() < 0) - this->set_max_ring_difference(this->max_ring_difference_num_to_process); - else - { - if (this->max_ring_difference_num_to_process >= 0) - warning("You've set \"max_ring_difference_num_to_process\", which is obsolete.\n" - "Replace by \"maximum segment number to process\" for future compatibility and to avoid this warning"); - } + if (this->get_max_segment_num_to_process() < 0) + this->set_max_ring_difference(this->max_ring_difference_num_to_process); + else + { + if (this->max_ring_difference_num_to_process >= 0) + warning("You've set \"max_ring_difference_num_to_process\", which is obsolete.\n" + "Replace by \"maximum segment number to process\" for future compatibility and to avoid this warning"); + } #endif - return false; - + return false; } -template +template Succeeded -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::load_listmode_cache_file(unsigned int file_id) +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::load_listmode_cache_file( + unsigned int file_id) { - FilePath icache(this->get_cache_filename(file_id), false); + FilePath icache(this->get_cache_filename(file_id), false); - record_cache.clear(); + record_cache.clear(); - if (icache.is_regular_file()) + if (icache.is_regular_file()) { - info( boost::format("Loading Listmode cache from disk %1%") % icache.get_as_string()); - std::ifstream fin(icache.get_as_string(), std::ios::in | std::ios::binary - | std::ios::ate); + info(boost::format("Loading Listmode cache from disk %1%") % icache.get_as_string()); + std::ifstream fin(icache.get_as_string(), std::ios::in | std::ios::binary | std::ios::ate); - const std::size_t num_records = fin.tellg()/sizeof (Bin); - try - { - record_cache.reserve(num_records + 1); // add 1 to avoid reallocation when overruning (see below) - } - catch (...) - { - error("Listmode: cannot allocate cache for " + std::to_string(num_records + 1) + " records"); - } - if (!fin) - error("Error opening cache file \"" + icache.get_as_string() + "\" for reading."); + const std::size_t num_records = fin.tellg() / sizeof(Bin); + try + { + record_cache.reserve(num_records + 1); // add 1 to avoid reallocation when overruning (see below) + } + catch (...) + { + error("Listmode: cannot allocate cache for " + std::to_string(num_records + 1) + " records"); + } + if (!fin) + error("Error opening cache file \"" + icache.get_as_string() + "\" for reading."); - fin.clear(); - fin.seekg(0); + fin.clear(); + fin.seekg(0); - while(!fin.eof()) + while (!fin.eof()) { - BinAndCorr tmp; - fin.read((char*)&tmp, sizeof(Bin)); - if (this->has_add) + BinAndCorr tmp; + fin.read((char*)&tmp, sizeof(Bin)); + if (this->has_add) { - tmp.my_corr = tmp.my_bin.get_bin_value(); - tmp.my_bin.set_bin_value(1); + tmp.my_corr = tmp.my_bin.get_bin_value(); + tmp.my_bin.set_bin_value(1); } - record_cache.push_back(tmp); + record_cache.push_back(tmp); } - //The while will push one junk record - record_cache.pop_back(); - fin.close(); + // The while will push one junk record + record_cache.pop_back(); + fin.close(); } - else + else { - error("Cannot find Listmode cache on disk. Please recompute it or do not set the max cache size. Abort."); - return Succeeded::no; + error("Cannot find Listmode cache on disk. Please recompute it or do not set the max cache size. Abort."); + return Succeeded::no; } - info( boost::format("Cached Events: %1% ") % record_cache.size()); - return Succeeded::yes; + info(boost::format("Cached Events: %1% ") % record_cache.size()); + return Succeeded::yes; } -template +template Succeeded -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::write_listmode_cache_file(unsigned int file_id) const +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::write_listmode_cache_file( + unsigned int file_id) const { - const auto cache_filename = this->get_cache_filename(file_id); - const bool with_add = !is_null_ptr(this->additive_proj_data_sptr); + const auto cache_filename = this->get_cache_filename(file_id); + const bool with_add = !is_null_ptr(this->additive_proj_data_sptr); - { - info("Storing Listmode cache to file \"" + cache_filename + "\"."); - // open the file, overwriting whatever was there before - std::ofstream fout(cache_filename, std::ios::out | std::ios::binary | std::ios::trunc); - if (!fout) - error("Error opening cache file \"" + cache_filename + "\" for writing."); + { + info("Storing Listmode cache to file \"" + cache_filename + "\"."); + // open the file, overwriting whatever was there before + std::ofstream fout(cache_filename, std::ios::out | std::ios::binary | std::ios::trunc); + if (!fout) + error("Error opening cache file \"" + cache_filename + "\" for writing."); - for(unsigned long int ie = 0; ie < record_cache.size(); ++ie) - { - Bin tmp = record_cache[ie].my_bin; - if(with_add) - tmp.set_bin_value(record_cache[ie].my_corr); - fout.write((char*)&tmp, sizeof(Bin)); - } - if (!fout) - error("Error writing to cache file \"" + cache_filename + "\"."); + for (unsigned long int ie = 0; ie < record_cache.size(); ++ie) + { + Bin tmp = record_cache[ie].my_bin; + if (with_add) + tmp.set_bin_value(record_cache[ie].my_corr); + fout.write((char*)&tmp, sizeof(Bin)); + } + if (!fout) + error("Error writing to cache file \"" + cache_filename + "\"."); - fout.close(); - } + fout.close(); + } - return Succeeded::yes; + return Succeeded::yes; } -template +template Succeeded PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::cache_listmode_file() { - if(!this->recompute_cache && this->cache_lm_file) - { - warning("Looking for existing cache files such as \"" - + this->get_cache_filename(0) + "\".\n" - + "We will be ignoring any time frame definitions as well as num_events_to_use!"); - // find how many cache files there are - this->num_cache_files = 0; - while (true) - { - if (!FilePath::exists(this->get_cache_filename(this->num_cache_files))) - break; - ++this->num_cache_files; - } - if (!this->num_cache_files) - error("No cache files found."); - return Succeeded::yes; // Stop here!!! + if (!this->recompute_cache && this->cache_lm_file) + { + warning("Looking for existing cache files such as \"" + this->get_cache_filename(0) + "\".\n" + + "We will be ignoring any time frame definitions as well as num_events_to_use!"); + // find how many cache files there are + this->num_cache_files = 0; + while (true) + { + if (!FilePath::exists(this->get_cache_filename(this->num_cache_files))) + break; + ++this->num_cache_files; + } + if (!this->num_cache_files) + error("No cache files found."); + return Succeeded::yes; // Stop here!!! } - this->num_cache_files = 0; - if(this->cache_lm_file) - { - info("Listmode reconstruction: Creating cache...", 2); + this->num_cache_files = 0; + if (this->cache_lm_file) + { + info("Listmode reconstruction: Creating cache...", 2); - record_cache.clear(); - try - { - record_cache.reserve(this->cache_size); - } - catch (...) - { - error("Listmode: cannot allocate cache for " + std::to_string(this->cache_size) + " records. Reduce cache size."); - } + record_cache.clear(); + try + { + record_cache.reserve(this->cache_size); + } + catch (...) + { + error("Listmode: cannot allocate cache for " + std::to_string(this->cache_size) + " records. Reduce cache size."); + } - this->list_mode_data_sptr->reset(); - const shared_ptr record_sptr = this->list_mode_data_sptr->get_empty_record_sptr(); + this->list_mode_data_sptr->reset(); + const shared_ptr record_sptr = this->list_mode_data_sptr->get_empty_record_sptr(); - 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); - double current_time = 0.; - unsigned long int cached_events = 0; + 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); + double current_time = 0.; + unsigned long int cached_events = 0; - bool stop_caching = false; - record_cache.reserve(this->cache_size); + bool stop_caching = false; + record_cache.reserve(this->cache_size); - while(true) //keep caching across multiple files. + while (true) // keep caching across multiple files. { - record_cache.clear(); + record_cache.clear(); - while (true) // Start for the current cache + while (true) // Start for the current cache { - if(this->list_mode_data_sptr->get_next_record(*record_sptr) == Succeeded::no) + if (this->list_mode_data_sptr->get_next_record(*record_sptr) == Succeeded::no) { - stop_caching = true; - break; + stop_caching = true; + break; } - if (record_sptr->is_time()) - { - current_time = record_sptr->time().get_time_in_secs(); - if (this->do_time_frame && current_time >= end_time) - { - stop_caching = true; - break; // get out of while loop - } + if (record_sptr->is_time()) + { + current_time = record_sptr->time().get_time_in_secs(); + if (this->do_time_frame && current_time >= end_time) + { + stop_caching = true; + break; // get out of while loop + } } - if (current_time < start_time) - continue; - if (record_sptr->is_event() && record_sptr->event().is_prompt()) + if (current_time < start_time) + continue; + if (record_sptr->is_event() && record_sptr->event().is_prompt()) { - BinAndCorr tmp; - tmp.my_bin.set_bin_value(1.0); - record_sptr->event().get_bin(tmp.my_bin, *this->proj_data_info_sptr); - - if (tmp.my_bin.get_bin_value() != 1.0f - || tmp.my_bin.segment_num() < this->proj_data_info_sptr->get_min_segment_num() - || tmp.my_bin.segment_num() > this->proj_data_info_sptr->get_max_segment_num() - || tmp.my_bin.tangential_pos_num() < this->proj_data_info_sptr->get_min_tangential_pos_num() - || tmp.my_bin.tangential_pos_num() > this->proj_data_info_sptr->get_max_tangential_pos_num() - || tmp.my_bin.axial_pos_num() < this->proj_data_info_sptr->get_min_axial_pos_num(tmp.my_bin.segment_num()) - || tmp.my_bin.axial_pos_num() > this->proj_data_info_sptr->get_max_axial_pos_num(tmp.my_bin.segment_num()) - || tmp.my_bin.timing_pos_num() < this->proj_data_info_sptr->get_min_tof_pos_num() - || tmp.my_bin.timing_pos_num() > this->proj_data_info_sptr->get_max_tof_pos_num() - ) + BinAndCorr tmp; + tmp.my_bin.set_bin_value(1.0); + record_sptr->event().get_bin(tmp.my_bin, *this->proj_data_info_sptr); + + if (tmp.my_bin.get_bin_value() != 1.0f + || tmp.my_bin.segment_num() < this->proj_data_info_sptr->get_min_segment_num() + || tmp.my_bin.segment_num() > this->proj_data_info_sptr->get_max_segment_num() + || tmp.my_bin.tangential_pos_num() < this->proj_data_info_sptr->get_min_tangential_pos_num() + || tmp.my_bin.tangential_pos_num() > this->proj_data_info_sptr->get_max_tangential_pos_num() + || tmp.my_bin.axial_pos_num() < this->proj_data_info_sptr->get_min_axial_pos_num(tmp.my_bin.segment_num()) + || tmp.my_bin.axial_pos_num() > this->proj_data_info_sptr->get_max_axial_pos_num(tmp.my_bin.segment_num()) + || tmp.my_bin.timing_pos_num() < this->proj_data_info_sptr->get_min_tof_pos_num() + || tmp.my_bin.timing_pos_num() > this->proj_data_info_sptr->get_max_tof_pos_num()) { - continue; + continue; + } + try + { + record_cache.push_back(tmp); + ++cached_events; + } + catch (...) + { + // should never get here due to `reserve` statement above, but best to check... + error("Listmode: running out of memory for cache. Current size: " + + std::to_string(this->record_cache.size()) + " records"); } - try - { - record_cache.push_back(tmp); - ++cached_events; - } - catch (...) - { - // should never get here due to `reserve` statement above, but best to check... - error("Listmode: running out of memory for cache. Current size: " + std::to_string(this->record_cache.size()) + " records"); - } - - if (record_cache.size() > 1 && record_cache.size()%500000L==0) - info( boost::format("Cached Prompt Events (this cache): %1% ") % record_cache.size()); + if (record_cache.size() > 1 && record_cache.size() % 500000L == 0) + info(boost::format("Cached Prompt Events (this cache): %1% ") % record_cache.size()); - if(this->num_events_to_use > 0) - if (cached_events >= static_cast(this->num_events_to_use)) - { - stop_caching = true; - break; - } + if (this->num_events_to_use > 0) + if (cached_events >= static_cast(this->num_events_to_use)) + { + stop_caching = true; + break; + } - if (record_cache.size() == this->cache_size) - break; // cache is full. go to next cache. + if (record_cache.size() == this->cache_size) + break; // cache is full. go to next cache. } } - // add additive term to current cache - if(this->has_add) - { - info( boost::format("Caching Additive corrections for : %1% events.") % record_cache.size()); + // add additive term to current cache + if (this->has_add) + { + info(boost::format("Caching Additive corrections for : %1% events.") % record_cache.size()); #ifdef STIR_OPENMP -#pragma omp parallel +# pragma omp parallel + { +# pragma omp single { -#pragma omp single - { - info("Caching add background with " + std::to_string(omp_get_num_threads()) + " threads", 2); - } + info("Caching add background with " + std::to_string(omp_get_num_threads()) + " threads", 2); } + } #endif #ifdef STIR_OPENMP -#if _OPENMP <201107 - #pragma omp parallel for schedule(dynamic) -#else - #pragma omp parallel for collapse(2) schedule(dynamic) -#endif +# if _OPENMP < 201107 +# pragma omp parallel for schedule(dynamic) +# else +# pragma omp parallel for collapse(2) schedule(dynamic) +# endif #endif - for (int seg = this->additive_proj_data_sptr->get_min_segment_num(); - seg <= this->additive_proj_data_sptr->get_max_segment_num(); - ++seg) - for (int timing_pos_num = this->additive_proj_data_sptr->get_min_tof_pos_num(); - timing_pos_num <= this->additive_proj_data_sptr->get_max_tof_pos_num(); - ++timing_pos_num) + for (int seg = this->additive_proj_data_sptr->get_min_segment_num(); + seg <= this->additive_proj_data_sptr->get_max_segment_num(); + ++seg) + for (int timing_pos_num = this->additive_proj_data_sptr->get_min_tof_pos_num(); + timing_pos_num <= this->additive_proj_data_sptr->get_max_tof_pos_num(); + ++timing_pos_num) { const auto segment(this->additive_proj_data_sptr->get_segment_by_view(seg, timing_pos_num)); - for (BinAndCorr &cur_bin : record_cache) + for (BinAndCorr& cur_bin : record_cache) { if (cur_bin.my_bin.segment_num() == seg) { #ifdef STIR_OPENMP -# if _OPENMP >=201012 -# pragma omp atomic write -# else -# pragma omp critical(PLogLikListModePMBAddSinoCaching) -# endif +# if _OPENMP >= 201012 +# pragma omp atomic write +# else +# pragma omp critical(PLogLikListModePMBAddSinoCaching) +# endif #endif - cur_bin.my_corr = segment[cur_bin.my_bin.view_num()][cur_bin.my_bin.axial_pos_num()][cur_bin.my_bin.tangential_pos_num()]; + cur_bin.my_corr = segment[cur_bin.my_bin.view_num()][cur_bin.my_bin.axial_pos_num()] + [cur_bin.my_bin.tangential_pos_num()]; } } } - } // end additive correction + } // end additive correction - if (write_listmode_cache_file(this->num_cache_files) == Succeeded::no) - { - error("Error writing cache file!"); - } - ++this->num_cache_files; + if (write_listmode_cache_file(this->num_cache_files) == Succeeded::no) + { + error("Error writing cache file!"); + } + ++this->num_cache_files; - if(stop_caching) - break; - } - info( boost::format("Cached Events: %1% ") % cached_events); + if (stop_caching) + break; + } + info(boost::format("Cached Events: %1% ") % cached_events); return Succeeded::yes; } return Succeeded::no; } -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 { // TODO replace with call to distributable function - const int min_segment_num = this->proj_data_info_sptr->get_min_segment_num(); - const int max_segment_num = this->proj_data_info_sptr->get_max_segment_num(); + const int min_segment_num = this->proj_data_info_sptr->get_min_segment_num(); + const int max_segment_num = this->proj_data_info_sptr->get_max_segment_num(); - info(boost::format("Calculating sensitivity for subset %1%") %subset_num); + info(boost::format("Calculating sensitivity for subset %1%") % subset_num); - 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; - if (min_timing_pos_num<0 || max_timing_pos_num>0) - error("TOF code for sensitivity needs work"); + 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; + if (min_timing_pos_num < 0 || max_timing_pos_num > 0) + error("TOF code for sensitivity needs work"); - this->sens_backprojector_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 + // warning: has to be same as subset scheme used as in distributable_computation #ifdef STIR_OPENMP -#if _OPENMP <201107 - #pragma omp parallel for schedule(dynamic) -#else - #pragma omp parallel for collapse(2) schedule(dynamic) -#endif +# if _OPENMP < 201107 +# pragma omp parallel for schedule(dynamic) +# else +# pragma omp parallel for collapse(2) schedule(dynamic) +# endif #endif - 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) { for (int view = this->sens_proj_data_info_sptr->get_min_view_num() + subset_num; - view <= this->sens_proj_data_info_sptr->get_max_view_num(); - view += this->num_subsets) - { + view <= this->sens_proj_data_info_sptr->get_max_view_num(); + view += this->num_subsets) + { const ViewSegmentNumbers view_segment_num(view, segment_num); - if (! this->sens_backprojector_sptr->get_symmetries_used()->is_basic(view_segment_num)) + if (!this->sens_backprojector_sptr->get_symmetries_used()->is_basic(view_segment_num)) continue; - //for (int timing_pos_num = min_timing_pos_num; timing_pos_num <= max_timing_pos_num; ++timing_pos_num) + // for (int timing_pos_num = min_timing_pos_num; timing_pos_num <= max_timing_pos_num; ++timing_pos_num) { - shared_ptr symmetries_used - (this->sens_backprojector_sptr->get_symmetries_used()->clone()); + shared_ptr symmetries_used( + this->sens_backprojector_sptr->get_symmetries_used()->clone()); - RelatedViewgrams viewgrams = - this->sens_proj_data_info_sptr->get_empty_related_viewgrams( - view_segment_num, symmetries_used, false);//, timing_pos_num); + RelatedViewgrams viewgrams = this->sens_proj_data_info_sptr->get_empty_related_viewgrams( + view_segment_num, symmetries_used, false); //, timing_pos_num); - viewgrams.fill(1.F); - // find efficiencies - { - this->normalisation_sptr->undo(viewgrams); - } - // 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->sens_backprojector_sptr-> - back_project(viewgrams, - min_ax_pos_num, max_ax_pos_num); - } + viewgrams.fill(1.F); + // find efficiencies + { + this->normalisation_sptr->undo(viewgrams); + } + // 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->sens_backprojector_sptr->back_project(viewgrams, min_ax_pos_num, max_ax_pos_num); + } } - } + } } - this->sens_backprojector_sptr-> - get_output(sensitivity); + this->sens_backprojector_sptr->get_output(sensitivity); } -template - std::unique_ptr - PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: - get_exam_info_uptr_for_target() const +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; + 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 -TargetT * -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -construct_target_ptr() const -{ - return - this->target_parameter_parser.create(this->get_input_data()); -} - template void -PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin:: -actual_compute_subset_gradient_without_penalty(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num, - const bool add_sensitivity) +PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin< + TargetT>::actual_compute_subset_gradient_without_penalty(TargetT& gradient, + const TargetT& current_estimate, + const int subset_num, + const bool add_sensitivity) { - assert(subset_num>=0); - assert(subset_numnum_subsets); - if (!add_sensitivity && !this->get_use_subset_sensitivities() && this->num_subsets>1) - error("PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::" - "actual_compute_subset_gradient_without_penalty(): cannot subtract subset sensitivity because " - "use_subset_sensitivities is false. This will result in an error in the gradient computation."); - - if (this->cache_lm_file) - { - for (unsigned int icache = 0; icache < this->num_cache_files; ++icache) - { - load_listmode_cache_file(icache); - LM_distributable_computation(this->PM_sptr, - this->proj_data_info_sptr, - &gradient, ¤t_estimate, - record_cache, - subset_num, this->num_subsets, - this->has_add, - /* accumulate = */ icache != 0); - } - } - else + assert(subset_num >= 0); + assert(subset_num < this->num_subsets); + if (!add_sensitivity && !this->get_use_subset_sensitivities() && this->num_subsets > 1) + error("PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin::" + "actual_compute_subset_gradient_without_penalty(): cannot subtract subset sensitivity because " + "use_subset_sensitivities is false. This will result in an error in the gradient computation."); + + if (this->cache_lm_file) + { + for (unsigned int icache = 0; icache < this->num_cache_files; ++icache) + { + load_listmode_cache_file(icache); + LM_distributable_computation(this->PM_sptr, + this->proj_data_info_sptr, + &gradient, + ¤t_estimate, + record_cache, + subset_num, + this->num_subsets, + this->has_add, + /* accumulate = */ icache != 0); + } + } + else { - // list_mode_data_sptr->set_get_position(start_time); - // TODO implement function that will do this for a random time + // 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(); - 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); + 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; + long num_used_events = 0; + const float max_quotient = 10000.F; - double current_time = 0.; + double current_time = 0.; - // need get_bin_value(), so currently need to cast to either of the 2 below (ugly. TODO) - shared_ptr add_from_stream_sptr; - shared_ptr add_in_mem_sptr; + // need get_bin_value(), so currently need to cast to either of the 2 below (ugly. TODO) + shared_ptr add_from_stream_sptr; + shared_ptr add_in_mem_sptr; - if (!is_null_ptr(this->additive_proj_data_sptr)) - { - add_in_mem_sptr = std::dynamic_pointer_cast(this->additive_proj_data_sptr); - if (is_null_ptr(add_in_mem_sptr)) - { - add_from_stream_sptr = std::dynamic_pointer_cast(this->additive_proj_data_sptr); - // TODO could create a ProjDataInMemory instead, but for now we give up. - if (is_null_ptr(add_from_stream_sptr)) - error("Additive projection data is in unsupported file format. You need to create an Interfile copy. sorry."); - } - } + if (!is_null_ptr(this->additive_proj_data_sptr)) + { + add_in_mem_sptr = std::dynamic_pointer_cast(this->additive_proj_data_sptr); + if (is_null_ptr(add_in_mem_sptr)) + { + add_from_stream_sptr = std::dynamic_pointer_cast(this->additive_proj_data_sptr); + // TODO could create a ProjDataInMemory instead, but for now we give up. + if (is_null_ptr(add_from_stream_sptr)) + error("Additive projection data is in unsupported file format. You need to create an Interfile copy. sorry."); + } + } - ProjMatrixElemsForOneBin proj_matrix_row; - gradient.fill(0); - shared_ptr record_sptr = this->list_mode_data_sptr->get_empty_record_sptr(); - ListRecord& record = *record_sptr; + 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())); + VectorWithOffset frame_start_positions(1, static_cast(this->frame_defs.get_num_frames())); - while (true) - { + while (true) + { + + if (this->list_mode_data_sptr->get_next_record(record) == Succeeded::no) + { + info("End of listmode file!", 2); + break; // get out of while loop + } + + if (record.is_time()) + { + current_time = record.time().get_time_in_secs(); + if (this->do_time_frame && current_time >= end_time) + { + break; // get out of while loop + } + } - if (this->list_mode_data_sptr->get_next_record(record) == Succeeded::no) - { - info("End of listmode file!", 2); - break; //get out of while loop - } - - if(record.is_time()) - { - 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()) - { - Bin measured_bin; - measured_bin.set_bin_value(1.0f); - record.event().get_bin(measured_bin, *this->proj_data_info_sptr); - - if (measured_bin.get_bin_value() != 1.0f - || measured_bin.segment_num() < this->proj_data_info_sptr->get_min_segment_num() - || measured_bin.segment_num() > this->proj_data_info_sptr->get_max_segment_num() - || measured_bin.tangential_pos_num() < this->proj_data_info_sptr->get_min_tangential_pos_num() - || measured_bin.tangential_pos_num() > this->proj_data_info_sptr->get_max_tangential_pos_num() - || measured_bin.axial_pos_num() < this->proj_data_info_sptr->get_min_axial_pos_num(measured_bin.segment_num()) - || measured_bin.axial_pos_num() > this->proj_data_info_sptr->get_max_axial_pos_num(measured_bin.segment_num()) - || measured_bin.timing_pos_num() < this->proj_data_info_sptr->get_min_tof_pos_num() - || measured_bin.timing_pos_num() > this->proj_data_info_sptr->get_max_tof_pos_num()) - { - continue; - } - - measured_bin.set_bin_value(1.0f); - // If more than 1 subsets, check if the current bin belongs to the current. - bool in_subset = true; - if (this->num_subsets > 1) - { - Bin basic_bin = measured_bin; - this->PM_sptr->get_symmetries_ptr()->find_basic_bin(basic_bin); - in_subset = (subset_num == static_cast(basic_bin.view_num() % this->num_subsets)); - } - if (in_subset) - { - this->PM_sptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, measured_bin); - 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)) - { - // TODO simplify once we don't need the casting for get_bin_value() anymore - const float add_value = add_in_mem_sptr ? add_in_mem_sptr->get_bin_value(measured_bin) : - add_from_stream_sptr->get_bin_value(measured_bin); - const float value= fwd_bin.get_bin_value()+add_value; - fwd_bin.set_bin_value(value); - } - - if ( measured_bin.get_bin_value() <= max_quotient *fwd_bin.get_bin_value()) - { - const float measured_div_fwd = 1.0f /fwd_bin.get_bin_value(); - measured_bin.set_bin_value(measured_div_fwd); - proj_matrix_row.back_project(gradient, measured_bin); - } - } - - ++num_used_events; - - if (num_used_events%200000L==0) - info( boost::format("Used Events: %1% ") % num_used_events); - - // if we use event-count-based processing, see if we need to stop - if(this->num_events_to_use > 0) - if (num_used_events >= this->num_events_to_use) - break; - } - } - info(boost::format("Number of used events (for all subsets): %1%") % num_used_events); + if (current_time < start_time) + continue; + + if (record.is_event() && record.event().is_prompt()) + { + Bin measured_bin; + measured_bin.set_bin_value(1.0f); + record.event().get_bin(measured_bin, *this->proj_data_info_sptr); + + if (measured_bin.get_bin_value() != 1.0f + || measured_bin.segment_num() < this->proj_data_info_sptr->get_min_segment_num() + || measured_bin.segment_num() > this->proj_data_info_sptr->get_max_segment_num() + || measured_bin.tangential_pos_num() < this->proj_data_info_sptr->get_min_tangential_pos_num() + || measured_bin.tangential_pos_num() > this->proj_data_info_sptr->get_max_tangential_pos_num() + || measured_bin.axial_pos_num() < this->proj_data_info_sptr->get_min_axial_pos_num(measured_bin.segment_num()) + || measured_bin.axial_pos_num() > this->proj_data_info_sptr->get_max_axial_pos_num(measured_bin.segment_num()) + || measured_bin.timing_pos_num() < this->proj_data_info_sptr->get_min_tof_pos_num() + || measured_bin.timing_pos_num() > this->proj_data_info_sptr->get_max_tof_pos_num()) + { + continue; + } + + measured_bin.set_bin_value(1.0f); + // If more than 1 subsets, check if the current bin belongs to the current. + bool in_subset = true; + if (this->num_subsets > 1) + { + Bin basic_bin = measured_bin; + this->PM_sptr->get_symmetries_ptr()->find_basic_bin(basic_bin); + in_subset = (subset_num == static_cast(basic_bin.view_num() % this->num_subsets)); + } + if (in_subset) + { + this->PM_sptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, measured_bin); + 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)) + { + // TODO simplify once we don't need the casting for get_bin_value() anymore + const float add_value = add_in_mem_sptr ? add_in_mem_sptr->get_bin_value(measured_bin) + : add_from_stream_sptr->get_bin_value(measured_bin); + const float value = fwd_bin.get_bin_value() + add_value; + fwd_bin.set_bin_value(value); + } + + if (measured_bin.get_bin_value() <= max_quotient * fwd_bin.get_bin_value()) + { + const float measured_div_fwd = 1.0f / fwd_bin.get_bin_value(); + measured_bin.set_bin_value(measured_div_fwd); + proj_matrix_row.back_project(gradient, measured_bin); + } + } + + ++num_used_events; + + if (num_used_events % 200000L == 0) + info(boost::format("Used Events: %1% ") % num_used_events); + // if we use event-count-based processing, see if we need to stop + if (this->num_events_to_use > 0) + if (num_used_events >= this->num_events_to_use) + break; + } + } + info(boost::format("Number of used events (for all subsets): %1%") % num_used_events); } - if (!add_sensitivity) + if (!add_sensitivity) { // subtract the subset sensitivity // 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(); + 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; - } + { + *gradient_iter -= (*sensitivity_iter); + ++gradient_iter; + ++sensitivity_iter; + } } } -# 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 179149bd8..3cbd5832a 100644 --- a/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.cxx +++ b/src/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.cxx @@ -36,18 +36,18 @@ #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/ProjMatrixByBinUsingRayTracing.h" +# include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" +# include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" #endif #include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" #include "stir/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.h" @@ -64,7 +64,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" @@ -75,62 +75,56 @@ using std::pair; using std::ends; using std::max; - 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->max_timing_pos_num_to_process=0; + 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 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; @@ -139,18 +133,17 @@ 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("use time-of-flight sensitivities", &this->use_tofsens); - this->parser.add_key("input file",&this->input_filename); + 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); @@ -158,14 +151,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); @@ -174,51 +167,49 @@ 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)) + 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; + 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") - { - 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); - }; + { + 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); + }; - // 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 + else { // 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); - } + } #ifndef STIR_MPI -#if 0 +# if 0 //check caching enabled value if (this->distributed_cache_enabled==true) { @@ -231,316 +222,305 @@ 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 +TargetT* +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::construct_target_ptr() const { - return - target_parameter_parser.create(this->get_input_data()); + 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 int -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_max_timing_pos_num_to_process() const -{ return this->max_timing_pos_num_to_process; } +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_max_timing_pos_num_to_process() const +{ + return this->max_timing_pos_num_to_process; +} template -const bool -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_zero_seg0_end_planes() const -{ return this->zero_seg0_end_planes; } +const bool +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_zero_seg0_end_planes() const +{ + return this->zero_seg0_end_planes; +} template -const ProjData& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_additive_proj_data() const -{ return *this->additive_proj_data_sptr; } +const ProjData& +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_additive_proj_data() const +{ + return *this->additive_proj_data_sptr; +} template -const shared_ptr& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_additive_proj_data_sptr() const -{ return this->additive_proj_data_sptr; } +const shared_ptr& +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_additive_proj_data_sptr() const +{ + return this->additive_proj_data_sptr; +} template -const ProjectorByBinPair& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_projector_pair() const -{ return *this->projector_pair_ptr; } +const ProjectorByBinPair& +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_projector_pair() const +{ + return *this->projector_pair_ptr; +} template -const shared_ptr& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_projector_pair_sptr() const -{ return this->projector_pair_ptr; } +const shared_ptr& +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_projector_pair_sptr() const +{ + return this->projector_pair_ptr; +} template -const int -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_time_frame_num() const -{ return this->frame_num; } +const int +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_time_frame_num() const +{ + return this->frame_num; +} template -const TimeFrameDefinitions& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_time_frame_definitions() const -{ return this->frame_defs; } +const TimeFrameDefinitions& +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::get_time_frame_definitions() const +{ + return this->frame_defs; +} template -const BinNormalisation& -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -get_normalisation() 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; } - +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) +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_num_subsets(const int new_num_subsets) { this->already_set_up = this->already_set_up && (this->num_subsets == new_num_subsets); - this->num_subsets = std::max(new_num_subsets,1); + 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->already_set_up = false; 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->already_set_up = this->already_set_up && (this->max_segment_num_to_process == arg); this->max_segment_num_to_process = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_max_timing_pos_num_to_process(const int arg) +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_max_timing_pos_num_to_process(const int arg) { this->already_set_up = this->already_set_up && (this->max_timing_pos_num_to_process == 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->already_set_up = this->already_set_up && (this->zero_seg0_end_planes == arg); this->zero_seg0_end_planes = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_additive_proj_data_sptr(const shared_ptr &arg) +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_additive_proj_data_sptr(const shared_ptr& arg) { this->already_set_up = false; 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->already_set_up = false; this->projector_pair_ptr = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_frame_num(const int arg) +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_frame_num(const int arg) { this->already_set_up = this->already_set_up && (this->frame_num == arg); this->frame_num = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_frame_definitions(const TimeFrameDefinitions& arg) +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_frame_definitions(const TimeFrameDefinitions& arg) { this->already_set_up = this->already_set_up && (this->frame_defs == 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->already_set_up = false; this->normalisation_sptr = arg; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -set_input_data(const shared_ptr & arg) +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::set_input_data(const shared_ptr& arg) { this->already_set_up = false; 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 +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(); + assert(this->num_subsets > 0); + const DataSymmetriesForViewSegmentNumbers& symmetries + = *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 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 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) + for (int subset_num = 1; subset_num < this->num_subsets; ++subset_num) { - if(num_vs_in_subset[subset_num] != num_vs_in_subset[0]) - { + 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" + 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"; + "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; } @@ -548,10 +528,9 @@ actual_subsets_are_approximately_balanced(std::string& warning_message) const return true; } -template +template bool -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -sensitivity_uses_same_projector() const +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::sensitivity_uses_same_projector() const { return !this->proj_data_sptr->get_proj_data_info_sptr()->is_tof_data() || this->use_tofsens; } @@ -559,10 +538,9 @@ sensitivity_uses_same_projector() const /*************************************************************** set_up() ***************************************************************/ -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -ensure_norm_is_set_up(bool for_original_data) const +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::ensure_norm_is_set_up(bool for_original_data) const { for_original_data = for_original_data || this->sensitivity_uses_same_projector(); @@ -570,7 +548,9 @@ ensure_norm_is_set_up(bool for_original_data) const { if (!this->norm_already_setup || !this->latest_setup_norm_was_with_orig_data) { - if (this->normalisation_sptr->set_up(proj_data_sptr->get_exam_info_sptr(), this->proj_data_sptr->get_proj_data_info_sptr()) == Succeeded::no) + if (this->normalisation_sptr->set_up(proj_data_sptr->get_exam_info_sptr(), + this->proj_data_sptr->get_proj_data_info_sptr()) + == Succeeded::no) error("Set_up of norm with original data failed."); } } @@ -578,7 +558,8 @@ ensure_norm_is_set_up(bool for_original_data) const { if (!this->norm_already_setup || this->latest_setup_norm_was_with_orig_data) { - if (this->normalisation_sptr->set_up(proj_data_sptr->get_exam_info_sptr(), this->sens_proj_data_info_sptr) == Succeeded::no) + if (this->normalisation_sptr->set_up(proj_data_sptr->get_exam_info_sptr(), this->sens_proj_data_info_sptr) + == Succeeded::no) error("Set_up of norm with non-TOF data failed.\n" "If your norm is TOF, set \"use time-of-flight sensitivities\" to true."); } @@ -587,35 +568,31 @@ ensure_norm_is_set_up(bool for_original_data) const this->latest_setup_norm_was_with_orig_data = for_original_data; } -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -ensure_norm_is_set_up_for_sensitivity() const +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::ensure_norm_is_set_up_for_sensitivity() const { this->ensure_norm_is_set_up(false); } -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"); - 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); + 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(); + 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()); @@ -626,25 +603,28 @@ set_up_before_sensitivity(shared_ptr const& target_sptr) +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; } + { + error("You need to specify a projector pair"); + return Succeeded::no; + } #ifdef STIR_MPI - //set up distributed caching object - if (distributed_cache_enabled) + // 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 + 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); // 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)) { @@ -671,7 +651,8 @@ set_up_before_sensitivity(shared_ptr const& target_sptr) auto pdi_non_tof_sptr = proj_data_info_sptr->create_non_tof_clone(); this->sens_proj_data_info_sptr = pdi_non_tof_sptr; this->sens_backprojector_sptr.reset(projector_pair_ptr->get_back_projector_sptr()->clone()); - if (auto sens_bp_pm_sptr = std::dynamic_pointer_cast(this->sens_backprojector_sptr)) + if (auto sens_bp_pm_sptr + = std::dynamic_pointer_cast(this->sens_backprojector_sptr)) { // There is no point caching the projection matrix as we will use it only once // Furthermore, disabling the cache will mean less memory used @@ -683,16 +664,15 @@ set_up_before_sensitivity(shared_ptr const& target_sptr) } } - if (frame_num<=0) + if (frame_num <= 0) { error("frame_num should be >= 1"); return Succeeded::no; } - if (static_cast(frame_num)> frame_defs.get_num_frames()) + 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()); + 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; } @@ -703,16 +683,13 @@ set_up_before_sensitivity(shared_ptr const& target_sptr) functions that compute the value/gradient of the objective function etc ***************************************************************/ -template +template void -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -actual_compute_subset_gradient_without_penalty(TargetT& gradient, - const TargetT ¤t_estimate, - const int subset_num, - const bool add_sensitivity) +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::actual_compute_subset_gradient_without_penalty( + TargetT& gradient, const TargetT& current_estimate, const int subset_num, const bool add_sensitivity) { - assert(subset_num>=0); - assert(subset_numnum_subsets); + assert(subset_num >= 0); + assert(subset_num < this->num_subsets); if (!this->distributable_computation_already_setup || !this->latest_setup_distributable_computation_was_with_orig_projectors) { @@ -727,35 +704,34 @@ actual_compute_subset_gradient_without_penalty(TargetT& gradient, this->latest_setup_distributable_computation_was_with_orig_projectors = true; } if (!this->distributable_computation_already_setup) - error("PoissonLogLikelihoodWithLinearModelForMeanAndProjData internal error: setup_distributable_computation not called (gradient calculation)"); + error("PoissonLogLikelihoodWithLinearModelForMeanAndProjData internal error: setup_distributable_computation not called " + "(gradient calculation)"); if (add_sensitivity) this->ensure_norm_is_set_up(); - distributable_compute_gradient(this->projector_pair_ptr->get_forward_projector_sptr(), - this->projector_pair_ptr->get_back_projector_sptr(), + 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, + 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, + this->zero_seg0_end_planes != 0, NULL, this->additive_proj_data_sptr, this->normalisation_sptr, caching_info_ptr, - -this->max_timing_pos_num_to_process, - this->max_timing_pos_num_to_process, + -this->max_timing_pos_num_to_process, + this->max_timing_pos_num_to_process, add_sensitivity); } - -template -double -PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: -actual_compute_objective_function_without_penalty(const TargetT& current_estimate, - const int subset_num) +template +double +PoissonLogLikelihoodWithLinearModelForMeanAndProjData::actual_compute_objective_function_without_penalty( + const TargetT& current_estimate, const int subset_num) { if (this->distributable_computation_already_setup || !this->latest_setup_distributable_computation_was_with_orig_projectors) { @@ -770,30 +746,31 @@ actual_compute_objective_function_without_penalty(const TargetT& current_estimat this->latest_setup_distributable_computation_was_with_orig_projectors = true; } if (!this->distributable_computation_already_setup) - error("PoissonLogLikelihoodWithLinearModelForMeanAndProjData internal error: setup_distributable_computation not called (function calculation)"); + error("PoissonLogLikelihoodWithLinearModelForMeanAndProjData internal error: setup_distributable_computation not called " + "(function calculation)"); this->ensure_norm_is_set_up(); - double accum=0.; - - distributable_accumulate_loglikelihood(this->projector_pair_ptr->get_forward_projector_sptr(), - this->projector_pair_ptr->get_back_projector_sptr(), + 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, + 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->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 - ); - - + -this->max_timing_pos_num_to_process, + this->max_timing_pos_num_to_process); + return accum; } @@ -840,328 +817,329 @@ 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; - 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 - auto sens_proj_data_sptr = std::make_shared(this->proj_data_sptr->get_exam_info_sptr(), this->sens_proj_data_info_sptr); - sens_proj_data_sptr->fill(1.0F); - - if (this->sensitivity_uses_same_projector() && (!this->distributable_computation_already_setup || !this->latest_setup_distributable_computation_was_with_orig_projectors)) - { - // set TOF projectors to be used for the calculations - setup_distributable_computation(this->projector_pair_ptr, - this->proj_data_sptr->get_exam_info_sptr(), - sens_proj_data_sptr->get_proj_data_info_sptr(), - std::shared_ptr(sensitivity.clone()), - zero_seg0_end_planes, - distributed_cache_enabled); - this->distributable_computation_already_setup = true; - this->latest_setup_distributable_computation_was_with_orig_projectors = true; - } - else if (!this->sensitivity_uses_same_projector() && (!this->distributable_computation_already_setup || this->latest_setup_distributable_computation_was_with_orig_projectors)) - { - // set non-TOF projector to be used for the calculations - shared_ptr dummy_sptr; - auto sens_projector_pair_sptr = std::make_shared(dummy_sptr, this->sens_backprojector_sptr); - setup_distributable_computation(sens_projector_pair_sptr, - this->proj_data_sptr->get_exam_info_sptr(), - sens_proj_data_sptr->get_proj_data_info_sptr(), - std::shared_ptr(sensitivity.clone()), - zero_seg0_end_planes, - distributed_cache_enabled); - this->distributable_computation_already_setup = true; - this->latest_setup_distributable_computation_was_with_orig_projectors = false; - } - if (!this->distributable_computation_already_setup) - error("PoissonLogLikelihoodWithLinearModelForMeanAndProjData internal error: setup_distributable_computation not called (sensitivity calculation)"); - - this->ensure_norm_is_set_up_for_sensitivity(); - - distributable_sensitivity_computation( - this->sens_backprojector_sptr, - this->sens_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()); + 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 + auto sens_proj_data_sptr + = std::make_shared(this->proj_data_sptr->get_exam_info_sptr(), this->sens_proj_data_info_sptr); + sens_proj_data_sptr->fill(1.0F); + + if (this->sensitivity_uses_same_projector() + && (!this->distributable_computation_already_setup + || !this->latest_setup_distributable_computation_was_with_orig_projectors)) + { + // set TOF projectors to be used for the calculations + setup_distributable_computation(this->projector_pair_ptr, + this->proj_data_sptr->get_exam_info_sptr(), + sens_proj_data_sptr->get_proj_data_info_sptr(), + std::shared_ptr(sensitivity.clone()), + zero_seg0_end_planes, + distributed_cache_enabled); + this->distributable_computation_already_setup = true; + this->latest_setup_distributable_computation_was_with_orig_projectors = true; + } + else if (!this->sensitivity_uses_same_projector() + && (!this->distributable_computation_already_setup + || this->latest_setup_distributable_computation_was_with_orig_projectors)) + { + // set non-TOF projector to be used for the calculations + shared_ptr dummy_sptr; + auto sens_projector_pair_sptr + = std::make_shared(dummy_sptr, this->sens_backprojector_sptr); + setup_distributable_computation(sens_projector_pair_sptr, + this->proj_data_sptr->get_exam_info_sptr(), + sens_proj_data_sptr->get_proj_data_info_sptr(), + std::shared_ptr(sensitivity.clone()), + zero_seg0_end_planes, + distributed_cache_enabled); + this->distributable_computation_already_setup = true; + this->latest_setup_distributable_computation_was_with_orig_projectors = false; + } + if (!this->distributable_computation_already_setup) + error("PoissonLogLikelihoodWithLinearModelForMeanAndProjData internal error: setup_distributable_computation not called " + "(sensitivity calculation)"); + + this->ensure_norm_is_set_up_for_sensitivity(); + + distributable_sensitivity_computation(this->sens_backprojector_sptr, + this->sens_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()); } -template - std::unique_ptr - PoissonLogLikelihoodWithLinearModelForMeanAndProjData:: - get_exam_info_uptr_for_target() const +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; + 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)) + 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()); + "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; } - } + } this->ensure_norm_is_set_up(); - 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()); info("Forward projecting input image.", 2); #ifdef STIR_OPENMP -#pragma omp parallel for schedule(dynamic) +# pragma omp parallel for schedule(dynamic) #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); + // TODO add 1 for 1/(y+1) approximation - this->get_normalisation().apply(viewgrams); + this->get_normalisation().apply(viewgrams); - // smooth TODO + // smooth TODO - this->get_normalisation().apply(viewgrams); + this->get_normalisation().apply(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); - } + 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); + } - // 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 + } // 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::minus()); + std::transform(output.begin_all(), + output.end_all(), + tmp->begin_all(), + output.begin_all(), + std::minus()); 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)) - { - error("PoissonLogLikelihoodWithLinearModelForMeanAndProjData:\n" - "sensitivity and output for add_multiplication_with_approximate_Hessian_without_penalty\n" - "should have the same characteristics.\n%s", - explanation.c_str()); - return Succeeded::no; - } + 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", + 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; - } + 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 (!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", - explanation.c_str()); - return Succeeded::no; - } + 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", + 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()); 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) - { - 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)); - } - + 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(dynamic) +# pragma omp parallel for schedule(dynamic) #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); + 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 - 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]); - } - - + 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(dynamic) +# pragma omp parallel for schedule(dynamic) #endif 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 - // Compute ybar_sq_viewgram = [ F(current_image_est) + additive ]^2 - RelatedViewgrams ybar_sq_viewgram; - { - 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 - 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 - ybar_sq_viewgram *= ybar_sq_viewgram; - } + // Compute ybar_sq_viewgram = [ F(current_image_est) + additive ]^2 + RelatedViewgrams ybar_sq_viewgram; + { + 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 + 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 + ybar_sq_viewgram *= ybar_sq_viewgram; + } - // Compute: final_viewgram * F(input) / ybar_sq_viewgram - // final_viewgram starts as measured data - RelatedViewgrams final_viewgram = this->get_proj_data().get_related_viewgrams(vs_nums_to_process[i], symmetries_sptr); - { - // Mult input_viewgram - final_viewgram *= input_viewgrams_vec[i]; - 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); - } + // Compute: final_viewgram * F(input) / ybar_sq_viewgram + // final_viewgram starts as measured data + RelatedViewgrams final_viewgram + = this->get_proj_data().get_related_viewgrams(vs_nums_to_process[i], symmetries_sptr); + { + // Mult input_viewgram + final_viewgram *= input_viewgrams_vec[i]; + 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); + // back-project final_viewgram + this->get_projector_pair().get_back_projector_sptr()->back_project(final_viewgram); - } // end of loop over view/segments + } // 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::minus()); return Succeeded::yes; @@ -1174,7 +1152,8 @@ actual_accumulate_sub_Hessian_times_input_without_penalty(TargetT& output, // make call-backs public for the moment //! Call-back function for compute_gradient -template static RPC_process_related_viewgrams_type RPC_process_related_viewgrams_gradient; +template +static RPC_process_related_viewgrams_type RPC_process_related_viewgrams_gradient; //! Call-back function for accumulate_loglikelihood RPC_process_related_viewgrams_type RPC_process_related_viewgrams_accumulate_loglikelihood; @@ -1182,9 +1161,10 @@ 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 -template static RPC_process_related_viewgrams_type RPC_process_related_viewgrams_gradient; +template +static RPC_process_related_viewgrams_type RPC_process_related_viewgrams_gradient; //! Call-back function for accumulate_loglikelihood static RPC_process_related_viewgrams_type RPC_process_related_viewgrams_accumulate_loglikelihood; @@ -1193,156 +1173,184 @@ 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, - shared_ptr const& normalisation_sptr, - DistributedCachingInformation* caching_info_ptr, - int min_timing_pos_num, int max_timing_pos_num, - const bool add_sensitivity - ) +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, + shared_ptr const& normalisation_sptr, + DistributedCachingInformation* caching_info_ptr, + int min_timing_pos_num, + int max_timing_pos_num, + const bool add_sensitivity) { - if (add_sensitivity){ - // Within the RPC process, subtract ones before to back projection ( backproj[ y/ybar - 1] ) - 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 - ); - } else if (!add_sensitivity){ - // Within the RPC process, only do div/truncate ( backproj[ y/ybar ] ) - 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_sptr, 0., 0., - &RPC_process_related_viewgrams_gradient, - caching_info_ptr, - min_timing_pos_num, max_timing_pos_num - ); - } + if (add_sensitivity) + { + // Within the RPC process, subtract ones before to back projection ( backproj[ y/ybar - 1] ) + 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); + } + else if (!add_sensitivity) + { + // Within the RPC process, only do div/truncate ( backproj[ y/ybar ] ) + 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_sptr, + 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, - int min_timing_pos_num, int max_timing_pos_num - ) - { - 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 - ); + 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& 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 - ) +void +distributable_sensitivity_computation(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(0, - 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 - ); - + distributable_computation(0, + 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 template -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); 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(); @@ -1350,9 +1358,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++; } @@ -1371,29 +1379,33 @@ void RPC_process_related_viewgrams_gradient( // adding the sensitivity: backproj[y/ybar] * // not adding the sensitivity computes the gradient: backproj[y/ybar - 1] * // * ignoring normalisation * - if (!add_sensitivity){ - if (mult_viewgrams_ptr) + if (!add_sensitivity) { - // subtract normalised ones from the data [y/ybar - 1/N] - *measured_viewgrams_ptr -= *mult_viewgrams_ptr; - } else { - // No mult_viewgrams_ptr, subtract ones [y/ybar - 1] - *measured_viewgrams_ptr -= 1; + if (mult_viewgrams_ptr) + { + // subtract normalised ones from the data [y/ybar - 1/N] + *measured_viewgrams_ptr -= *mult_viewgrams_ptr; + } + else + { + // No mult_viewgrams_ptr, subtract ones [y/ybar - 1] + *measured_viewgrams_ptr -= 1; + } } - } // back project 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); @@ -1401,56 +1413,51 @@ void RPC_process_related_viewgrams_accumulate_loglikelihood( RelatedViewgrams estimated_viewgrams = measured_viewgrams_ptr->get_empty_copy(); forward_projector_sptr->forward_project(estimated_viewgrams); - + if (additive_binwise_correction_ptr != NULL) - { - estimated_viewgrams += (*additive_binwise_correction_ptr); - }; - + { + estimated_viewgrams += (*additive_binwise_correction_ptr); + }; + if (mult_viewgrams_ptr != NULL) - { - estimated_viewgrams *= (*mult_viewgrams_ptr); - } + { + 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 ) - { - back_projector_sptr->back_project(*mult_viewgrams_ptr); - } + if (mult_viewgrams_ptr) + { + back_projector_sptr->back_project(*mult_viewgrams_ptr); + } else - { - back_projector_sptr->back_project(*measured_viewgrams_ptr); - } - + { + 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 1281ccedc..6dbba417a 100644 --- a/src/recon_buildblock/PostsmoothingBackProjectorByBin.cxx +++ b/src/recon_buildblock/PostsmoothingBackProjectorByBin.cxx @@ -25,22 +25,17 @@ #include "stir/warning.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"); @@ -49,19 +44,17 @@ initialise_keymap() } bool -PostsmoothingBackProjectorByBin:: -post_processing() +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; - } + { + warning("Pre Smoothing Back Projector: original back projector needs to be set"); + return true; + } return false; } -PostsmoothingBackProjectorByBin:: - PostsmoothingBackProjectorByBin() +PostsmoothingBackProjectorByBin::PostsmoothingBackProjectorByBin() { set_defaults(); } @@ -69,82 +62,75 @@ PostsmoothingBackProjectorByBin:: BackProjectorByBin* PostsmoothingBackProjectorByBin::get_original_back_projector_ptr() const { - return original_back_projector_ptr.get(); + 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; + PostsmoothingBackProjectorByBin* sptr(new PostsmoothingBackProjectorByBin(*this)); + // sptr->original_back_projector_ptr.reset(this->original_back_projector_ptr->clone()); + return sptr; } -PostsmoothingBackProjectorByBin:: -PostsmoothingBackProjectorByBin( - const shared_ptr& original_back_projector_ptr, - const shared_ptr > >& image_processor_ptr) - : original_back_projector_ptr(original_back_projector_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; + _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) +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()); + 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); + 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); + 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) +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); + 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 335a56bfc..5360e0b16 100644 --- a/src/recon_buildblock/PresmoothingForwardProjectorByBin.cxx +++ b/src/recon_buildblock/PresmoothingForwardProjectorByBin.cxx @@ -26,22 +26,17 @@ #include "stir/warning.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"); @@ -50,86 +45,79 @@ initialise_keymap() } bool -PresmoothingForwardProjectorByBin:: -post_processing() +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; - } + { + warning("Pre Smoothing Forward Projector: original forward projector needs to be set\n"); + return true; + } return false; } -PresmoothingForwardProjectorByBin:: - PresmoothingForwardProjectorByBin() +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) +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; + _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(); } #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) +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()); + 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); + 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); + 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); + // 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 diff --git a/src/recon_buildblock/ProjDataRebinning.cxx b/src/recon_buildblock/ProjDataRebinning.cxx index f27835fbe..e38a30969 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 @@ -25,45 +25,46 @@ using std::string; START_NAMESPACE_STIR -void -ProjDataRebinning:: -set_defaults() +void +ProjDataRebinning::set_defaults() { - output_filename_prefix=""; - input_filename=""; - max_segment_num_to_process=-1; + output_filename_prefix = ""; + input_filename = ""; + max_segment_num_to_process = -1; } -void -ProjDataRebinning:: -initialise_keymap() +void +ProjDataRebinning::initialise_keymap() { - parser.add_key("input file",&input_filename); - //parser.add_key("mash x views", &num_views_to_add); + 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() +bool +ProjDataRebinning::post_processing() { if (output_filename_prefix.length() == 0) - { warning("You need to specify an output prefix\n"); return true; } + { + 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; } + { + 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 @@ -94,69 +95,66 @@ else } #endif - + Succeeded -ProjDataRebinning:: -set_up() +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()) - { + 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); + "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 +void ProjDataRebinning::set_output_filename_prefix(const string& s) { output_filename_prefix = s; } -string +string ProjDataRebinning::get_output_filename_prefix() const { return output_filename_prefix; } - -shared_ptr -ProjDataRebinning:: -get_proj_data_sptr() +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 + /* 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 4c9af6ca2..16a0987db 100644 --- a/src/recon_buildblock/ProjMatrixByBin.cxx +++ b/src/recon_buildblock/ProjMatrixByBin.cxx @@ -2,8 +2,8 @@ \file \ingroup projection - - \brief implementation of the stir::ProjMatrixByBin class + + \brief implementation of the stir::ProjMatrixByBin class \author Nikos Efthimiou \author Mustapha Sadki @@ -24,22 +24,22 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/ProjMatrixByBin.h" #include "stir/recon_buildblock/ProjMatrixElemsForOneBin.h" #include "stir/TOF_conversions.h" START_NAMESPACE_STIR -void ProjMatrixByBin::set_defaults() +void +ProjMatrixByBin::set_defaults() { - cache_disabled=false; - cache_stores_only_basic_bins=true; + cache_disabled = false; + cache_stores_only_basic_bins = true; gauss_sigma_in_mm = 0.f; r_sqrt2_gauss_sigma = 0.f; } -void +void ProjMatrixByBin::initialise_keymap() { parser.add_key("disable caching", &cache_disabled); @@ -53,56 +53,54 @@ ProjMatrixByBin::post_processing() } ProjMatrixByBin::ProjMatrixByBin() -{ +{ set_defaults(); } - -void -ProjMatrixByBin:: -enable_cache(const bool v) -{ cache_disabled = !v;} void -ProjMatrixByBin:: -enable_tof(const shared_ptr& _proj_data_info_sptr, const bool v) +ProjMatrixByBin::enable_cache(const bool v) { - if (v) + cache_disabled = !v; +} + +void +ProjMatrixByBin::enable_tof(const shared_ptr& _proj_data_info_sptr, const bool v) +{ + if (v) { - tof_enabled = true; - gauss_sigma_in_mm = 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))); + tof_enabled = true; + gauss_sigma_in_mm = 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))); } } -void -ProjMatrixByBin:: -store_only_basic_bins_in_cache(const bool v) -{ cache_stores_only_basic_bins=v;} +void +ProjMatrixByBin::store_only_basic_bins_in_cache(const bool v) +{ + cache_stores_only_basic_bins = v; +} -bool -ProjMatrixByBin:: -is_cache_enabled() const -{ return !cache_disabled; } +bool +ProjMatrixByBin::is_cache_enabled() const +{ + return !cache_disabled; +} -bool -ProjMatrixByBin:: -does_cache_store_only_basic_bins() const -{ return cache_stores_only_basic_bins; } +bool +ProjMatrixByBin::does_cache_store_only_basic_bins() const +{ + return cache_stores_only_basic_bins; +} -void -ProjMatrixByBin:: -clear_cache() const +void +ProjMatrixByBin::clear_cache() 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 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) + 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(); } @@ -110,7 +108,7 @@ clear_cache() const } /* -void +void ProjMatrixByBin:: reserve_num_elements_in_cache(const std::size_t num_elems) { @@ -121,28 +119,27 @@ reserve_num_elements_in_cache(const std::size_t num_elems) */ void -ProjMatrixByBin:: -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(const shared_ptr& proj_data_info_sptr_v, + const shared_ptr>& density_info_sptr_v // TODO should be Info only +) { this->proj_data_info_sptr = proj_data_info_sptr_v; - this->image_info_sptr.reset( - dynamic_cast* > (density_info_sptr_v->clone() )); + this->image_info_sptr.reset(dynamic_cast*>(density_info_sptr_v->clone())); if (is_cache_enabled()) { - const int max_abs_tangential_pos_num = - std::max(-proj_data_info_sptr->get_min_tangential_pos_num(), proj_data_info_sptr->get_max_tangential_pos_num()); + const int max_abs_tangential_pos_num + = std::max(-proj_data_info_sptr->get_min_tangential_pos_num(), proj_data_info_sptr->get_max_tangential_pos_num()); // next isn't strictly speaking the max, as it could be larger for other segments, but that's pretty unlikely - const int max_abs_axial_pos_num = - std::max(-proj_data_info_sptr->get_min_axial_pos_num(0), proj_data_info_sptr->get_max_axial_pos_num(0)); - const int max_abs_timing_pos_num = std::max(-proj_data_info_sptr->get_min_tof_pos_num(), proj_data_info_sptr->get_max_tof_pos_num()); - - if ((static_cast(max_abs_axial_pos_num) >= (static_cast(1) << axial_pos_bits)) || - (static_cast(max_abs_tangential_pos_num) >= (static_cast(1) << tang_pos_bits)) || - (static_cast(max_abs_timing_pos_num) >= (static_cast(1) << timing_pos_bits))) - error("ProjMatrixByBin: not enough bits reserved for this data in the caching mechanism. You will have to switch caching off. Sorry."); + const int max_abs_axial_pos_num + = std::max(-proj_data_info_sptr->get_min_axial_pos_num(0), proj_data_info_sptr->get_max_axial_pos_num(0)); + const int max_abs_timing_pos_num + = std::max(-proj_data_info_sptr->get_min_tof_pos_num(), proj_data_info_sptr->get_max_tof_pos_num()); + + if ((static_cast(max_abs_axial_pos_num) >= (static_cast(1) << axial_pos_bits)) + || (static_cast(max_abs_tangential_pos_num) >= (static_cast(1) << tang_pos_bits)) + || (static_cast(max_abs_timing_pos_num) >= (static_cast(1) << timing_pos_bits))) + error("ProjMatrixByBin: not enough bits reserved for this data in the caching mechanism. You will have to switch caching " + "off. Sorry."); } const int min_view_num = proj_data_info_sptr->get_min_view_num(); @@ -151,11 +148,11 @@ set_up( 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); + enable_tof(proj_data_info_sptr, true); else - { - tof_enabled = false; - } + { + tof_enabled = false; + } this->cache_collection.recycle(); this->cache_collection.resize(min_view_num, max_view_num); @@ -164,22 +161,21 @@ 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) + 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) + 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 } // Setup the custom erf code - erf_interpolation.set_num_samples(200000); //200,000 =~12.8MB + erf_interpolation.set_num_samples(200000); // 200,000 =~12.8MB erf_interpolation.set_up(); } - /*! \warning Preconditions
    • abs(axial_pos_num) fits in 13 (4095) bits @@ -194,92 +190,82 @@ ProjMatrixByBin::cache_key(const Bin& bin) const assert(static_cast(abs(bin.timing_pos_num())) < (static_cast(1) << timing_pos_bits)); return static_cast( - (static_cast(bin.axial_pos_num()>=0?0:1) << (timing_pos_bits + tang_pos_bits + axial_pos_bits + 2)) - | (static_cast(abs(bin.axial_pos_num())) << (timing_pos_bits + tang_pos_bits + 2)) - | (static_cast(bin.tangential_pos_num()>=0?0:1) << (timing_pos_bits + tang_pos_bits + 1)) - | (static_cast(abs(bin.tangential_pos_num())) << (timing_pos_bits+1)) - | (static_cast(bin.timing_pos_num()>=0?0:1) << timing_pos_bits) - | (static_cast(abs(bin.timing_pos_num())))); -} + (static_cast(bin.axial_pos_num() >= 0 ? 0 : 1) << (timing_pos_bits + tang_pos_bits + axial_pos_bits + 2)) + | (static_cast(abs(bin.axial_pos_num())) << (timing_pos_bits + tang_pos_bits + 2)) + | (static_cast(bin.tangential_pos_num() >= 0 ? 0 : 1) << (timing_pos_bits + tang_pos_bits + 1)) + | (static_cast(abs(bin.tangential_pos_num())) << (timing_pos_bits + 1)) + | (static_cast(bin.timing_pos_num() >= 0 ? 0 : 1) << timing_pos_bits) + | (static_cast(abs(bin.timing_pos_num())))); +} +void +ProjMatrixByBin::cache_proj_matrix_elems_for_one_bin(const ProjMatrixElemsForOneBin& probabilities) const +{ + if (cache_disabled) + return; -void -ProjMatrixByBin:: -cache_proj_matrix_elems_for_one_bin( - const ProjMatrixElemsForOneBin& probabilities) 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) - { - // Check that this is a 'basic' coordinate - Bin bin_copy = bin; - assert ( symmetries_sptr->find_basic_bin(bin_copy) == 0); - } -#endif - - bool found=false; + { + // Check that this is a 'basic' coordinate + Bin bin_copy = bin; + assert(symmetries_sptr->find_basic_bin(bin_copy) == 0); + } +#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; + return Succeeded::yes; else { - //cout << " This entry is not in the cache :" << Key << endl; + // 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 @@ -330,8 +316,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 68bb719a8..b508b0f1a 100644 --- a/src/recon_buildblock/ProjMatrixByBinFromFile.cxx +++ b/src/recon_buildblock/ProjMatrixByBinFromFile.cxx @@ -45,20 +45,15 @@ using std::string; START_NAMESPACE_STIR +const char* const ProjMatrixByBinFromFile::registered_name = "From File"; -const char * const -ProjMatrixByBinFromFile::registered_name = -"From File"; - -ProjMatrixByBinFromFile:: -ProjMatrixByBinFromFile() +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(); @@ -68,28 +63,27 @@ 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() { 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; @@ -98,7 +92,6 @@ ProjMatrixByBinFromFile::set_defaults() do_symmetry_shift_z = true; } - bool ProjMatrixByBinFromFile::post_processing() { @@ -106,63 +99,59 @@ ProjMatrixByBinFromFile::post_processing() 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 (template_density_filename.size()==0) + if (template_density_filename.size() == 0) { warning("template_density_filename has to be specified.\n"); return true; } - if (template_proj_data_filename.size()==0) + if (template_proj_data_filename.size() == 0) { warning("template_proj_data_filename has to be specified.\n"); return true; } - if (data_filename.size()==0) + 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)); + 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") { @@ -176,17 +165,13 @@ ProjMatrixByBinFromFile::post_processing() 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"); @@ -202,7 +187,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 @@ -210,153 +195,161 @@ 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); + return new ProjMatrixByBinFromFile(*this); } // anonymous namespace for local functions -namespace { +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)); - } +// 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::uint32_t c= static_cast(lor.size()); - fst.write( (char*)&c , sizeof(boost::uint32_t)); + 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; } - 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 + return Succeeded::yes; +} + +// return type for read_lor() +class readReturnType +{ +public: + enum value { - 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; + 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(); - // 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; + } - { - 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()); + 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 (!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); } - boost::uint32_t count; - fst.read ( (char*)&count, sizeof(boost::uint32_t)); - - 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; - } + 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) +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"; + string template_density_filename = output_filename_prefix + "_template_density"; { - if (OutputFileFormat >::default_sptr()-> - write_to_file(template_density_filename, - template_density) != Succeeded::yes) + if (OutputFileFormat>::default_sptr()->write_to_file(template_density_filename, template_density) + != Succeeded::yes) { - warning("Error writing template image"); - return Succeeded::no; + 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; @@ -368,20 +361,18 @@ 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; + 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()))) + if (!is_null_ptr(dynamic_cast(proj_matrix.get_symmetries_ptr()))) { - const DataSymmetriesForBins_PET_CartesianGrid& symmetries = - 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' @@ -391,7 +382,7 @@ write_to_file(const std::string& output_filename_prefix, << " 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()))) + else if (!is_null_ptr(dynamic_cast(proj_matrix.get_symmetries_ptr()))) { header << "symmetries type := none\n"; } @@ -401,7 +392,6 @@ write_to_file(const std::string& output_filename_prefix, return Succeeded::no; } - header << "template proj data filename:=" << template_proj_data_filename << '\n'; header << "template density filename:=" << template_density_filename << '\n'; @@ -412,7 +402,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 +411,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 +423,28 @@ 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 +452,67 @@ 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()) + while (!fst.eof()) { - readReturnType return_value=read_lor(fst, lor); + readReturnType return_value = read_lor(fst, lor); if (return_value == readReturnType::problem) - return Succeeded::no; + return Succeeded::no; if (return_value == readReturnType::eof) - return Succeeded::yes; + 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 +void +ProjMatrixByBinFromFile::calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { - //error("ProjMatrixByBinFromFile element not found in cache (and hence file)"); + // error("ProjMatrixByBinFromFile element not found in cache (and hence file)"); lor.erase(); } END_NAMESPACE_STIR - diff --git a/src/recon_buildblock/ProjMatrixByBinPinholeSPECTUB.cxx b/src/recon_buildblock/ProjMatrixByBinPinholeSPECTUB.cxx index 289666830..7ac5e7415 100644 --- a/src/recon_buildblock/ProjMatrixByBinPinholeSPECTUB.cxx +++ b/src/recon_buildblock/ProjMatrixByBinPinholeSPECTUB.cxx @@ -4,17 +4,17 @@ Copyright (C) 2014, 2021, University College London This file is part of STIR. - 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. See STIR/LICENSE.txt for details */ @@ -29,7 +29,7 @@ \author Kris Thielemans */ -//system libraries +// system libraries #include #include #include @@ -42,7 +42,7 @@ #include #include -//user defined libraries +// user defined libraries //#include "stir/ProjDataInterfile.h" #include "stir/recon_buildblock/ProjMatrixByBinPinholeSPECTUB.h" #include "stir/recon_buildblock/TrivialDataSymmetriesForBins.h" @@ -58,7 +58,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" @@ -67,8 +67,8 @@ #include #include -//using namespace std; -//using std::string; +// using namespace std; +// using std::string; //... user defined libraries ............................................................. @@ -77,9 +77,9 @@ //... functions from wm_SPECT.2.0............................ -//void error_wm_SPECT_mph( int nerr, string txt); //list of error messages -//void wm_inputs_mph( char ** argv, int argc ); -//void read_inputs_mph( vector param ); +// void error_wm_SPECT_mph( int nerr, string txt); //list of error messages +// void wm_inputs_mph( char ** argv, int argc ); +// void read_inputs_mph( vector param ); using namespace std; using namespace SPECTUB_mph; @@ -87,90 +87,85 @@ using std::string; START_NAMESPACE_STIR -const char * const -ProjMatrixByBinPinholeSPECTUB::registered_name = -"Pinhole SPECT UB"; +const char* const ProjMatrixByBinPinholeSPECTUB::registered_name = "Pinhole SPECT UB"; -ProjMatrixByBinPinholeSPECTUB:: -ProjMatrixByBinPinholeSPECTUB() +ProjMatrixByBinPinholeSPECTUB::ProjMatrixByBinPinholeSPECTUB() { - set_defaults(); + set_defaults(); } -void -ProjMatrixByBinPinholeSPECTUB:: -initialise_keymap() +void +ProjMatrixByBinPinholeSPECTUB::initialise_keymap() { - parser.add_start_key("Projection Matrix By Bin Pinhole SPECT UB Parameters"); - ProjMatrixByBin::initialise_keymap(); - - // no longer parse this - // parser.add_key("minimum weight", &minimum_weight); - parser.add_key("maximum number of sigmas", &maximum_number_of_sigmas); - parser.add_key("spatial resolution PSF", &spatial_resolution_PSF); - parser.add_key("subsampling factor PSF", &subsampling_factor_PSF); - parser.add_key("detector file", &detector_file); - parser.add_key("collimator file", &collimator_file); - parser.add_key("psf correction", &psf_correction); - parser.add_key("doi correction", &doi_correction); - parser.add_key("attenuation type", &attenuation_type); - parser.add_key("attenuation map", &attenuation_map); - parser.add_key("object radius (cm)", &object_radius); - // no longer parse this - // parser.add_key("mask type", &mask_type); - parser.add_key("mask file", &mask_file); - parser.add_key("mask from attenuation map", &mask_from_attenuation_map); - parser.add_key("keep all views in cache", &keep_all_views_in_cache); - - parser.add_stop_key("End Projection Matrix By Bin Pinhole SPECT UB Parameters"); + parser.add_start_key("Projection Matrix By Bin Pinhole SPECT UB Parameters"); + ProjMatrixByBin::initialise_keymap(); + + // no longer parse this + // parser.add_key("minimum weight", &minimum_weight); + parser.add_key("maximum number of sigmas", &maximum_number_of_sigmas); + parser.add_key("spatial resolution PSF", &spatial_resolution_PSF); + parser.add_key("subsampling factor PSF", &subsampling_factor_PSF); + parser.add_key("detector file", &detector_file); + parser.add_key("collimator file", &collimator_file); + parser.add_key("psf correction", &psf_correction); + parser.add_key("doi correction", &doi_correction); + parser.add_key("attenuation type", &attenuation_type); + parser.add_key("attenuation map", &attenuation_map); + parser.add_key("object radius (cm)", &object_radius); + // no longer parse this + // parser.add_key("mask type", &mask_type); + parser.add_key("mask file", &mask_file); + parser.add_key("mask from attenuation map", &mask_from_attenuation_map); + parser.add_key("keep all views in cache", &keep_all_views_in_cache); + + parser.add_stop_key("End Projection Matrix By Bin Pinhole SPECT UB Parameters"); } - void ProjMatrixByBinPinholeSPECTUB::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.001; - subsampling_factor_PSF= 1; - detector_file= ""; - collimator_file= ""; - psf_correction= "no"; - doi_correction= "no"; - attenuation_type= "no"; - attenuation_map= ""; - object_radius= 0.0; - // mask_type= "no"; - mask_file= ""; - mask_from_attenuation_map= false; + 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.001; + subsampling_factor_PSF = 1; + detector_file = ""; + collimator_file = ""; + psf_correction = "no"; + doi_correction = "no"; + attenuation_type = "no"; + attenuation_map = ""; + object_radius = 0.0; + // mask_type= "no"; + mask_file = ""; + mask_from_attenuation_map = false; } bool ProjMatrixByBinPinholeSPECTUB::post_processing() { - if (ProjMatrixByBin::post_processing() == true) - return true; + if (ProjMatrixByBin::post_processing() == true) + return true; - this->set_attenuation_type(this->attenuation_type); - - if (!this->attenuation_map.empty()) - this->set_attenuation_image_sptr(this->attenuation_map); - else - this->attenuation_image_sptr.reset(); - - if (!this->mask_file.empty()) - this->set_mask_image_sptr(this->mask_file); - else - this->mask_image_sptr.reset(); + this->set_attenuation_type(this->attenuation_type); + + if (!this->attenuation_map.empty()) + this->set_attenuation_image_sptr(this->attenuation_map); + else + this->attenuation_image_sptr.reset(); + + if (!this->mask_file.empty()) + this->set_mask_image_sptr(this->mask_file); + else + this->mask_image_sptr.reset(); - this->already_setup= false; + this->already_setup = false; - return false; + return false; } //******************** get/set pairs ************* @@ -183,7 +178,7 @@ get_minimum_weight() const return this->minimum_weight; } -void +void ProjMatrixByBinPinholeSPECTUB:: set_minimum_weight( const float value ) { @@ -197,58 +192,52 @@ set_minimum_weight( const float value ) //! Maximum number of sigmas float -ProjMatrixByBinPinholeSPECTUB:: -get_maximum_number_of_sigmas() const +ProjMatrixByBinPinholeSPECTUB::get_maximum_number_of_sigmas() const { - return this->maximum_number_of_sigmas; + return this->maximum_number_of_sigmas; } -void -ProjMatrixByBinPinholeSPECTUB:: -set_maximum_number_of_sigmas( const float value ) +void +ProjMatrixByBinPinholeSPECTUB::set_maximum_number_of_sigmas(const float value) { - if (this->maximum_number_of_sigmas != value) + if (this->maximum_number_of_sigmas != value) { - this->maximum_number_of_sigmas = value; - this->already_setup = false; + this->maximum_number_of_sigmas = value; + this->already_setup = false; } } - + //! Spatial resolution PSF float -ProjMatrixByBinPinholeSPECTUB:: -get_spatial_resolution_PSF() const +ProjMatrixByBinPinholeSPECTUB::get_spatial_resolution_PSF() const { - return this->spatial_resolution_PSF; + return this->spatial_resolution_PSF; } -void -ProjMatrixByBinPinholeSPECTUB:: -set_spatial_resolution_PSF( const float value ) +void +ProjMatrixByBinPinholeSPECTUB::set_spatial_resolution_PSF(const float value) { - if (this->spatial_resolution_PSF != value) + if (this->spatial_resolution_PSF != value) { - this->spatial_resolution_PSF = value; - this->already_setup = false; + this->spatial_resolution_PSF = value; + this->already_setup = false; } } //! Subsampling factor PSF int -ProjMatrixByBinPinholeSPECTUB:: -get_subsampling_factor_PSF() const +ProjMatrixByBinPinholeSPECTUB::get_subsampling_factor_PSF() const { - return this->subsampling_factor_PSF; + return this->subsampling_factor_PSF; } -void -ProjMatrixByBinPinholeSPECTUB:: -set_subsampling_factor_PSF( const int value ) +void +ProjMatrixByBinPinholeSPECTUB::set_subsampling_factor_PSF(const int value) { - if (this->subsampling_factor_PSF != value) + if (this->subsampling_factor_PSF != value) { - this->subsampling_factor_PSF = value; - this->already_setup = false; + this->subsampling_factor_PSF = value; + this->already_setup = false; } } @@ -262,14 +251,13 @@ get_detector_file() const } */ -void -ProjMatrixByBinPinholeSPECTUB:: -set_detector_file( const string& value ) +void +ProjMatrixByBinPinholeSPECTUB::set_detector_file(const string& value) { - if (this->detector_file != value) + if (this->detector_file != value) { - this->detector_file = value; - this->already_setup = false; + this->detector_file = value; + this->already_setup = false; } } @@ -283,743 +271,755 @@ get_collimator_file() const } */ -void -ProjMatrixByBinPinholeSPECTUB:: -set_collimator_file( const string& value ) +void +ProjMatrixByBinPinholeSPECTUB::set_collimator_file(const string& value) { - if (this->collimator_file != value) + if (this->collimator_file != value) { - this->collimator_file = value; - this->already_setup = false; + this->collimator_file = value; + this->already_setup = false; } } - + //! PSF correction string -ProjMatrixByBinPinholeSPECTUB:: -get_psf_correction() const +ProjMatrixByBinPinholeSPECTUB::get_psf_correction() const { - return this->psf_correction; + return this->psf_correction; } -void -ProjMatrixByBinPinholeSPECTUB:: -set_psf_correction( const string& value ) +void +ProjMatrixByBinPinholeSPECTUB::set_psf_correction(const string& value) { - if (this->psf_correction != boost::algorithm::to_lower_copy(value)) + if (this->psf_correction != boost::algorithm::to_lower_copy(value)) { - this->psf_correction = boost::algorithm::to_lower_copy(value); - if ( this->psf_correction != "yes" && this->psf_correction != "no" ) - error("psf_correction has to be Yes or No"); - this->already_setup = false; + this->psf_correction = boost::algorithm::to_lower_copy(value); + if (this->psf_correction != "yes" && this->psf_correction != "no") + error("psf_correction has to be Yes or No"); + this->already_setup = false; } } //! Set DOI correction string -ProjMatrixByBinPinholeSPECTUB:: -get_doi_correction() const +ProjMatrixByBinPinholeSPECTUB::get_doi_correction() const { - return this->doi_correction; + return this->doi_correction; } -void -ProjMatrixByBinPinholeSPECTUB:: -set_doi_correction( const string& value ) +void +ProjMatrixByBinPinholeSPECTUB::set_doi_correction(const string& value) { - if (this->doi_correction != boost::algorithm::to_lower_copy(value)) + if (this->doi_correction != boost::algorithm::to_lower_copy(value)) { - this->doi_correction = boost::algorithm::to_lower_copy(value); - if ( this->doi_correction != "yes" && this->doi_correction != "no" ) - error("doi_correction has to be Yes or No"); - this->already_setup = false; + this->doi_correction = boost::algorithm::to_lower_copy(value); + if (this->doi_correction != "yes" && this->doi_correction != "no") + error("doi_correction has to be Yes or No"); + this->already_setup = false; } } //! Attenuation image string -ProjMatrixByBinPinholeSPECTUB:: -get_attenuation_type() const +ProjMatrixByBinPinholeSPECTUB::get_attenuation_type() const { - return this->attenuation_type; + return this->attenuation_type; } void -ProjMatrixByBinPinholeSPECTUB:: -set_attenuation_type(const string& value) +ProjMatrixByBinPinholeSPECTUB::set_attenuation_type(const string& value) { - if (this->attenuation_type != boost::algorithm::to_lower_copy(value)) + if (this->attenuation_type != boost::algorithm::to_lower_copy(value)) { - this->attenuation_type = boost::algorithm::to_lower_copy(value); - if ( this->attenuation_type != "simple" && this->attenuation_type != "full" && this->attenuation_type != "no" ) - error("attenuation_type has to be Simple, Full, or No"); - this->already_setup = false; + this->attenuation_type = boost::algorithm::to_lower_copy(value); + if (this->attenuation_type != "simple" && this->attenuation_type != "full" && this->attenuation_type != "no") + error("attenuation_type has to be Simple, Full, or No"); + this->already_setup = false; } } -shared_ptr< const DiscretisedDensity<3,float> > -ProjMatrixByBinPinholeSPECTUB:: -get_attenuation_image_sptr() const +shared_ptr> +ProjMatrixByBinPinholeSPECTUB::get_attenuation_image_sptr() const { - return this->attenuation_image_sptr; + return this->attenuation_image_sptr; } void -ProjMatrixByBinPinholeSPECTUB:: -set_attenuation_image_sptr(const shared_ptr< const DiscretisedDensity<3,float> > value) +ProjMatrixByBinPinholeSPECTUB::set_attenuation_image_sptr(const shared_ptr> value) { - this->attenuation_image_sptr = value; - if (this->attenuation_type == "no") + this->attenuation_image_sptr = value; + if (this->attenuation_type == "no") { - info("Setting attenuation type to 'simple'."); - this->set_attenuation_type("simple"); + info("Setting attenuation type to 'simple'."); + this->set_attenuation_type("simple"); } - this->already_setup = false; + this->already_setup = false; } void -ProjMatrixByBinPinholeSPECTUB:: -set_attenuation_image_sptr(const string& value) +ProjMatrixByBinPinholeSPECTUB::set_attenuation_image_sptr(const string& value) { - this->attenuation_map = value; - shared_ptr< const DiscretisedDensity<3,float> > im_sptr(read_from_file >(this->attenuation_map)); - set_attenuation_image_sptr(im_sptr); + this->attenuation_map = value; + shared_ptr> im_sptr(read_from_file>(this->attenuation_map)); + set_attenuation_image_sptr(im_sptr); } //! Object radius (cm) float -ProjMatrixByBinPinholeSPECTUB:: -get_object_radius() const +ProjMatrixByBinPinholeSPECTUB::get_object_radius() const { - return this->object_radius; + return this->object_radius; } -void -ProjMatrixByBinPinholeSPECTUB:: -set_object_radius( const float value ) +void +ProjMatrixByBinPinholeSPECTUB::set_object_radius(const float value) { - if (this->object_radius != value) + if (this->object_radius != value) { - this->object_radius = value; - this->already_setup = false; + this->object_radius = value; + this->already_setup = false; } } //! Mask image bool -ProjMatrixByBinPinholeSPECTUB:: -get_mask_from_attenuation_map() const +ProjMatrixByBinPinholeSPECTUB::get_mask_from_attenuation_map() const { - return this->mask_from_attenuation_map; + return this->mask_from_attenuation_map; } void -ProjMatrixByBinPinholeSPECTUB:: -set_mask_from_attenuation_map(bool value) +ProjMatrixByBinPinholeSPECTUB::set_mask_from_attenuation_map(bool value) { - if (this->mask_from_attenuation_map != value) + if (this->mask_from_attenuation_map != value) { - this->mask_from_attenuation_map = value; - this->already_setup = false; + this->mask_from_attenuation_map = value; + this->already_setup = false; } } -shared_ptr< const DiscretisedDensity<3,float> > -ProjMatrixByBinPinholeSPECTUB:: -get_mask_image_sptr() const +shared_ptr> +ProjMatrixByBinPinholeSPECTUB::get_mask_image_sptr() const { - return this->mask_image_sptr; + return this->mask_image_sptr; } void -ProjMatrixByBinPinholeSPECTUB:: -set_mask_image_sptr(const shared_ptr< const DiscretisedDensity<3,float> > value) +ProjMatrixByBinPinholeSPECTUB::set_mask_image_sptr(const shared_ptr> value) { - this->mask_image_sptr = value; - if (this->mask_from_attenuation_map == true) + this->mask_image_sptr = value; + if (this->mask_from_attenuation_map == true) { - info("Setting mask from attenuation map to '0'"); - this->set_mask_from_attenuation_map(false); + info("Setting mask from attenuation map to '0'"); + this->set_mask_from_attenuation_map(false); } - this->already_setup = false; + this->already_setup = false; } void -ProjMatrixByBinPinholeSPECTUB:: -set_mask_image_sptr(const string& value) +ProjMatrixByBinPinholeSPECTUB::set_mask_image_sptr(const string& value) { - this->mask_file = value; - shared_ptr< const DiscretisedDensity<3,float> > im_sptr(read_from_file >(this->mask_file)); - set_mask_image_sptr(im_sptr); + this->mask_file = value; + shared_ptr> im_sptr(read_from_file>(this->mask_file)); + set_mask_image_sptr(im_sptr); } //! Keep all views in cache bool -ProjMatrixByBinPinholeSPECTUB:: -get_keep_all_views_in_cache() const +ProjMatrixByBinPinholeSPECTUB::get_keep_all_views_in_cache() const { - return this->keep_all_views_in_cache; + return this->keep_all_views_in_cache; } void -ProjMatrixByBinPinholeSPECTUB:: -set_keep_all_views_in_cache(bool value) +ProjMatrixByBinPinholeSPECTUB::set_keep_all_views_in_cache(bool value) { - if (this->keep_all_views_in_cache != value) + if (this->keep_all_views_in_cache != value) { - this->keep_all_views_in_cache = value; - this->already_setup = false; + this->keep_all_views_in_cache = value; + this->already_setup = false; } } //******************** actual implementation ************* void -ProjMatrixByBinPinholeSPECTUB:: -set_up( - const shared_ptr< const ProjDataInfo >& proj_data_info_ptr_v, - const shared_ptr< const DiscretisedDensity<3,float> >& density_info_ptr // TODO should be Info only - ) +ProjMatrixByBinPinholeSPECTUB::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); + ProjMatrixByBin::set_up(proj_data_info_ptr_v, density_info_ptr); #ifdef STIR_OPENMP - if (!this->keep_all_views_in_cache) + if (!this->keep_all_views_in_cache) { - warning("Pinhole SPECTUB matrix can currently only use single-threaded code unless all views are kept. Setting num_threads to 1."); - set_num_threads(1); + warning("Pinhole SPECTUB matrix can currently only use single-threaded code unless all views are kept. Setting num_threads " + "to 1."); + set_num_threads(1); } #endif - std::stringstream info_stream; + std::stringstream info_stream; - 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 == nullptr) - error("ProjMatrixByBinPinholeSPECTUB set-up with a wrong type of DiscretisedDensity\n"); + if (image_info_ptr == nullptr) + error("ProjMatrixByBinPinholeSPECTUB set-up with a wrong type of DiscretisedDensity\n"); - if (this->already_setup) + 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_PinholeSPECTUB_arrays(); - } + 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_PinholeSPECTUB_arrays(); + } } - this->proj_data_info_ptr=proj_data_info_ptr_v; - symmetries_sptr.reset( - new TrivialDataSymmetriesForBins(proj_data_info_ptr_v)); + 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(); + 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()); + const ProjDataInfoCylindricalArcCorr* proj_Data_Info_Cylindrical + = dynamic_cast(this->proj_data_info_ptr.get()); - CPUTimer timer; - timer.start(); + CPUTimer timer; + timer.start(); - //... *** code below replaces wm_inputs_mph() and read_inputs_mph() + //... *** code below replaces wm_inputs_mph() and read_inputs_mph() - //.....image parameters...................... - - vol.Dimx = image_info_ptr->get_x_size(); // Image: number of columns - vol.Dimy = image_info_ptr->get_y_size(); // Image: number of rows - vol.Dimz = 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) - - vol.first_sl = 0; // Image: first slice to take into account (no weight below) - vol.last_sl = vol.Dimz; // Image: last slice to take into account (no weights above) - - //if ( wmh.vol.first_sl < 0 || wmh.vol.first_sl > wmh.vol.Dimz ) error_wm_SPECT_mph( 107, param[ 7 ] ); - //if ( wmh.vol.last_sl <= wmh.vol.first_sl || wmh.vol.last_sl > wmh.vol.Dimz ) error_wm_SPECT_mph( 108, param[ 8 ] ); - - wmh.ro = object_radius; // Image: object radius (cm) - - //..... geometrical and other derived parameters of the volume structure............... - - vol.Npix = vol.Dimx * vol.Dimy; - vol.Nvox = vol.Npix * vol.Dimz; - - vol.FOVxcmd2 = (float) vol.Dimx * vol.szcm / (float) 2.; // half of the size of the image volume, dimension x (cm); - vol.FOVcmyd2 = (float) vol.Dimy * vol.szcm / (float) 2.; // half of the size of the image volume, dimension y (cm); - vol.FOVzcmd2 = (float) vol.Dimz * vol.thcm / (float) 2.; // Half of the size of the image volume, dimension z (cm); - - vol.x0 = - vol.FOVxcmd2 + (float)0.5 * vol.szcm ; // x coordinate of first voxel - vol.y0 = - vol.FOVcmyd2 + (float)0.5 * vol.szcm ; // y coordinate of first voxel - vol.z0 = - vol.FOVzcmd2 + (float)0.5 * vol.thcm ; // z coordinate of first voxel + //.....image parameters...................... - wmh.vol = vol; - - //...ring parameters ................................................ - - wmh.detector_fn = detector_file; - - //....collimator parameters ........................................ - - wmh.collim_fn = collimator_file; - - //... resolution parameters .............................................. - - wmh.mn_w = minimum_weight; - wmh.Nsigm = maximum_number_of_sigmas; - wmh.highres = spatial_resolution_PSF; - wmh.subsamp = subsampling_factor_PSF; - - wmh.do_subsamp = false; - - //...correction for intrinsic PSF.................................... - boost::algorithm::to_lower(psf_correction); - if ( psf_correction == "no" ) wmh.do_psfi = false; - else{ - if ( psf_correction == "yes" ) wmh.do_psfi = true; - else error("psf_correction has to be Yes or No"); //error_wm_SPECT_mph( 116, psf_correction ); - wmh.do_subsamp = true; + vol.Dimx = image_info_ptr->get_x_size(); // Image: number of columns + vol.Dimy = image_info_ptr->get_y_size(); // Image: number of rows + vol.Dimz = 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) + + vol.first_sl = 0; // Image: first slice to take into account (no weight below) + vol.last_sl = vol.Dimz; // Image: last slice to take into account (no weights above) + + // if ( wmh.vol.first_sl < 0 || wmh.vol.first_sl > wmh.vol.Dimz ) error_wm_SPECT_mph( 107, param[ 7 ] ); + // if ( wmh.vol.last_sl <= wmh.vol.first_sl || wmh.vol.last_sl > wmh.vol.Dimz ) error_wm_SPECT_mph( 108, param[ 8 ] ); + + wmh.ro = object_radius; // Image: object radius (cm) + + //..... geometrical and other derived parameters of the volume structure............... + + vol.Npix = vol.Dimx * vol.Dimy; + vol.Nvox = vol.Npix * vol.Dimz; + + vol.FOVxcmd2 = (float)vol.Dimx * vol.szcm / (float)2.; // half of the size of the image volume, dimension x (cm); + vol.FOVcmyd2 = (float)vol.Dimy * vol.szcm / (float)2.; // half of the size of the image volume, dimension y (cm); + vol.FOVzcmd2 = (float)vol.Dimz * vol.thcm / (float)2.; // Half of the size of the image volume, dimension z (cm); + + vol.x0 = -vol.FOVxcmd2 + (float)0.5 * vol.szcm; // x coordinate of first voxel + vol.y0 = -vol.FOVcmyd2 + (float)0.5 * vol.szcm; // y coordinate of first voxel + vol.z0 = -vol.FOVzcmd2 + (float)0.5 * vol.thcm; // z coordinate of first voxel + + wmh.vol = vol; + + //...ring parameters ................................................ + + wmh.detector_fn = detector_file; + + //....collimator parameters ........................................ + + wmh.collim_fn = collimator_file; + + //... resolution parameters .............................................. + + wmh.mn_w = minimum_weight; + wmh.Nsigm = maximum_number_of_sigmas; + wmh.highres = spatial_resolution_PSF; + wmh.subsamp = subsampling_factor_PSF; + + wmh.do_subsamp = false; + + //...correction for intrinsic PSF.................................... + boost::algorithm::to_lower(psf_correction); + if (psf_correction == "no") + wmh.do_psfi = false; + else + { + if (psf_correction == "yes") + wmh.do_psfi = true; + else + error("psf_correction has to be Yes or No"); // error_wm_SPECT_mph( 116, psf_correction ); + wmh.do_subsamp = true; } - - //... impact depth ......................... - boost::algorithm::to_lower(doi_correction); - if ( doi_correction == "no" ) { - wmh.do_depth = false; + + //... impact depth ......................... + boost::algorithm::to_lower(doi_correction); + if (doi_correction == "no") + { + wmh.do_depth = false; } - else{ - if ( doi_correction == "yes" ) wmh.do_depth = true; - else error("doi_correction has to be Yes or No"); //error_wm_SPECT_mph( 117, doi_correction ); - wmh.do_subsamp = true; + else + { + if (doi_correction == "yes") + wmh.do_depth = true; + else + error("doi_correction has to be Yes or No"); // error_wm_SPECT_mph( 117, doi_correction ); + wmh.do_subsamp = true; } - - //... attenuation parameters ......................... - boost::algorithm::to_lower(attenuation_type); - if ( attenuation_type == "no" ) { - wmh.do_att = wmh.do_full_att = false; + + //... attenuation parameters ......................... + boost::algorithm::to_lower(attenuation_type); + if (attenuation_type == "no") + { + wmh.do_att = wmh.do_full_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("attenuation_type has to be Simple, Full, or No"); //error_wm_SPECT_mph( 118, attenuation_type ); + 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("attenuation_type has to be Simple, Full, or No"); // error_wm_SPECT_mph( 118, attenuation_type ); } - - wmh.att_fn = attenuation_map; - } - - //... masking parameters............................. - wmh.do_msk_att = mask_from_attenuation_map; - - // no longer use mask type - /* - boost::algorithm::to_lower(mask_type); - if( mask_type == "no" ) wmh.do_msk_att = wmh.do_msk_file = false; - 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; - } - else error("mask_type has to be Attenuation Map, Explicit Mask, or No"); //error_wm_SPECT_mph( 120, mask_type); - } + wmh.att_fn = attenuation_map; } - */ - //... initialization of do_variables to false.............. - - wmh.do_round_cumsum = wmh.do_square_cumsum = false ; + //... masking parameters............................. + wmh.do_msk_att = mask_from_attenuation_map; - //... projection parameters ................... + // no longer use mask type + /* + boost::algorithm::to_lower(mask_type); + if( mask_type == "no" ) wmh.do_msk_att = wmh.do_msk_file = false; + else { + if( mask_type == "attenuation map" ) wmh.do_msk_att = true; + else { + if( mask_type == "explicit mask" ){ + wmh.do_msk_file = true; - wmh.prj.rad = proj_Data_Info_Cylindrical->get_ring_radius() / (float) 10.; // ring radius (cm) - wmh.prj.Nbin = proj_Data_Info_Cylindrical->get_num_tangential_poss(); // number of bins per row - wmh.prj.Nsli = proj_Data_Info_Cylindrical->get_num_axial_poss(0); // number of slices + wmh.msk_fn = mask_file; + } + else error("mask_type has to be Attenuation Map, Explicit Mask, or No"); //error_wm_SPECT_mph( 120, mask_type); + } + } + */ - wmh.prj.szcm = proj_Data_Info_Cylindrical->get_tangential_sampling() / (float) 10.; // bin size (cm) - wmh.prj.thcm = proj_Data_Info_Cylindrical->get_axial_sampling(0) / (float) 10.; // slice thickness (cm) + //... initialization of do_variables to false.............. - //... derived variables ....................... + wmh.do_round_cumsum = wmh.do_square_cumsum = false; - wmh.prj.FOVxcmd2 = (float) wmh.prj.Nbin * wmh.prj.szcm / (float) 2.; // FOVcmx divided by 2 - wmh.prj.FOVzcmd2 = (float) wmh.prj.Nsli * wmh.prj.thcm / (float) 2.; // FOVcmz divided by 2 + //... projection parameters ................... - wmh.prj.Nbd = wmh.prj.Nsli * wmh.prj.Nbin; + wmh.prj.rad = proj_Data_Info_Cylindrical->get_ring_radius() / (float)10.; // ring radius (cm) + wmh.prj.Nbin = proj_Data_Info_Cylindrical->get_num_tangential_poss(); // number of bins per row + wmh.prj.Nsli = proj_Data_Info_Cylindrical->get_num_axial_poss(0); // number of slices - wmh.prj.szcmd2 = wmh.prj.szcm / (float) 2.; - wmh.prj.thcmd2 = wmh.prj.thcm / (float) 2. ; + wmh.prj.szcm = proj_Data_Info_Cylindrical->get_tangential_sampling() / (float)10.; // bin size (cm) + wmh.prj.thcm = proj_Data_Info_Cylindrical->get_axial_sampling(0) / (float)10.; // slice thickness (cm) - //... files with complementary information ................. - - read_prj_params_mph( wmh ); - read_coll_params_mph( wmh ); - - //... precalculated functions ................ - - fill_pcf( wmh, pcf ); - - //... other variables ......................... + //... derived variables ....................... - wm.Nbt = wmh.prj.Nbt; // number of rows of the weight matrix - wm.Nvox = wmh.vol.Nvox; // number of columns of the weight matrix - wmh.mndvh2 = ( wmh.collim.rad - wmh.ro ) * ( wmh.collim.rad - wmh.ro ); // reference distance ^2 for efficiency + wmh.prj.FOVxcmd2 = (float)wmh.prj.Nbin * wmh.prj.szcm / (float)2.; // FOVcmx divided by 2 + wmh.prj.FOVzcmd2 = (float)wmh.prj.Nsli * wmh.prj.thcm / (float)2.; // FOVcmz divided by 2 - // variables for wm calculations by view ("UB-subset") - wmh.prj.NOS = this->proj_data_info_ptr->get_num_views(); - wmh.prj.NdOS = wmh.prj.Ndt/wmh.prj.NOS; - wmh.prj.NbOS = wmh.prj.Nbt/wmh.prj.NOS; + wmh.prj.Nbd = wmh.prj.Nsli * wmh.prj.Nbin; - wm.do_save_STIR = true; + wmh.prj.szcmd2 = wmh.prj.szcm / (float)2.; + wmh.prj.thcmd2 = wmh.prj.thcm / (float)2.; - //... control of read parameters .............. - info_stream << "Parameters of Pinhole SPECT UB matrix: (in cm)" << endl; - info_stream << "Image. Nrow: " << wmh.vol.Dimy << "\tNcol: " << wmh.vol.Dimx << "\tvoxel_size: " << wmh.vol.szcm<< endl; - info_stream << "Number of slices: " << wmh.vol.Dimz << "\tslice_thickness: " << wmh.vol.thcm << endl; - info_stream << "FOVxcmd2: " << wmh.vol.FOVxcmd2 << "\tFOVcmyd2: " << wmh.vol.FOVcmyd2 << "\tradius object: " << wmh.ro <has_same_characteristics(*attenuation_image_sptr, explanation)) - error("Currently the attenuation map and emission image must have the same dimension, orientation, and voxel size:\n" + explanation); - - if ( ( attmap = new (nothrow) float [ wmh.vol.Nvox ] ) == nullptr ) - error("Error allocating space to store values for attenuation map."); - - bool exist_nan = false; + //... files with complementary information ................. + + read_prj_params_mph(wmh); + read_coll_params_mph(wmh); + + //... precalculated functions ................ + + fill_pcf(wmh, pcf); + + //... other variables ......................... + + wm.Nbt = wmh.prj.Nbt; // number of rows of the weight matrix + wm.Nvox = wmh.vol.Nvox; // number of columns of the weight matrix + wmh.mndvh2 = (wmh.collim.rad - wmh.ro) * (wmh.collim.rad - wmh.ro); // reference distance ^2 for efficiency - std::copy(attenuation_image_sptr->begin_all(), attenuation_image_sptr->end_all(),attmap); //read_att_map_mph( attmap ); + // variables for wm calculations by view ("UB-subset") + wmh.prj.NOS = this->proj_data_info_ptr->get_num_views(); + wmh.prj.NdOS = wmh.prj.Ndt / wmh.prj.NOS; + wmh.prj.NbOS = wmh.prj.Nbt / wmh.prj.NOS; - for (int i = 0 ; i < wmh.vol.Nvox ; i++ ){ - if ((boost::math::isnan)(attmap [ i ])){ - attmap [ i ] = 0; - exist_nan = true; - } - if ( exist_nan ) warning("attmap contains NaN values. Converted to zero."); - } + wm.do_save_STIR = true; + + //... control of read parameters .............. + info_stream << "Parameters of Pinhole SPECT UB matrix: (in cm)" << endl; + info_stream << "Image. Nrow: " << wmh.vol.Dimy << "\tNcol: " << wmh.vol.Dimx << "\tvoxel_size: " << wmh.vol.szcm << endl; + info_stream << "Number of slices: " << wmh.vol.Dimz << "\tslice_thickness: " << wmh.vol.thcm << endl; + info_stream << "FOVxcmd2: " << wmh.vol.FOVxcmd2 << "\tFOVcmyd2: " << wmh.vol.FOVcmyd2 << "\tradius object: " << wmh.ro << endl; + info_stream << "Minimum weight: " << wmh.mn_w << endl; + + info(info_stream.str()); + + //... up to here replaces wm_inputs_mph() and read_inputs_mph() + + //... to read attenuation map .................................................. + + if (wmh.do_att) + { + if (is_null_ptr(attenuation_image_sptr)) + error("Attenuation image not set."); + std::string explanation; + if (!density_info_ptr->has_same_characteristics(*attenuation_image_sptr, explanation)) + error("Currently the attenuation map and emission image must have the same dimension, orientation, and voxel size:\n" + + explanation); + + if ((attmap = new (nothrow) float[wmh.vol.Nvox]) == nullptr) + error("Error allocating space to store values for attenuation map."); + + bool exist_nan = false; + + std::copy(attenuation_image_sptr->begin_all(), attenuation_image_sptr->end_all(), attmap); // read_att_map_mph( attmap ); + + for (int i = 0; i < wmh.vol.Nvox; i++) + { + if ((boost::math::isnan)(attmap[i])) + { + attmap[i] = 0; + exist_nan = true; + } + if (exist_nan) + warning("attmap contains NaN values. Converted to zero."); + } } - else attmap = nullptr; + else + attmap = nullptr; - //... to generate mask.......................................................... + //... to generate mask.......................................................... - msk_3d = new bool [ wmh.vol.Nvox ]; - //generate_msk_mph( msk_3d, attmap, wmh ); + msk_3d = new bool[wmh.vol.Nvox]; + // generate_msk_mph( msk_3d, attmap, wmh ); - // generate mask from mask file - if (!is_null_ptr(mask_image_sptr)) + // generate mask from mask file + if (!is_null_ptr(mask_image_sptr)) { - if ( !density_info_ptr->has_same_characteristics(*mask_image_sptr) ) - error("Currently the mask image and emission image must have the same dimension, orientation, and voxel size."); - - float * mask_from_file; - if ( ( mask_from_file = new (nothrow) float [ wmh.vol.Nvox ] ) == nullptr ) - error("Error allocating space to store values for mask from file."); + if (!density_info_ptr->has_same_characteristics(*mask_image_sptr)) + error("Currently the mask image and emission image must have the same dimension, orientation, and voxel size."); - std::copy( mask_image_sptr->begin_all(), mask_image_sptr->end_all(), mask_from_file ); + float* mask_from_file; + if ((mask_from_file = new (nothrow) float[wmh.vol.Nvox]) == nullptr) + error("Error allocating space to store values for mask from file."); - // call UB generate_msk_mph pretending that this mask is an attenuation image - // we do this to avoid using its own read_msk_file_mph - wmh.do_msk_file = false; - wmh.do_msk_att = true; - generate_msk_mph( msk_3d, mask_from_file, wmh ); + std::copy(mask_image_sptr->begin_all(), mask_image_sptr->end_all(), mask_from_file); - delete[] mask_from_file; + // call UB generate_msk_mph pretending that this mask is an attenuation image + // we do this to avoid using its own read_msk_file_mph + wmh.do_msk_file = false; + wmh.do_msk_att = true; + generate_msk_mph(msk_3d, mask_from_file, wmh); + + delete[] mask_from_file; } - // generate mask from attenuation map - else if (wmh.do_msk_att) + // generate mask from attenuation map + else if (wmh.do_msk_att) { - if (is_null_ptr(attmap)) - error("No attenuation image set, so cannot compute the mask image from it."); - generate_msk_mph( msk_3d, attmap, wmh ); + if (is_null_ptr(attmap)) + error("No attenuation image set, so cannot compute the mask image from it."); + generate_msk_mph(msk_3d, attmap, wmh); } - // generate mask from object radius - else + // generate mask from object radius + else { - wmh.do_msk_file = false; - generate_msk_mph( msk_3d, (float *)0, wmh ); + wmh.do_msk_file = false; + generate_msk_mph(msk_3d, (float*)0, wmh); } - - //... initialize psf2d in bins .................................................. - - wmh.max_amp = ( wmh.prj.rad - wmh.ro ) / ( wmh.collim.rad - wmh.ro ); - - psf_bin.max_dimx = (int) floorf ( wmh.max_hsxcm * wmh.max_amp / wmh.prj.szcm ) + 2 ; - psf_bin.max_dimz = (int) floorf ( wmh.max_hszcm * wmh.max_amp / wmh.prj.thcm ) + 2 ; - - //... distributions at mid resolution ........................................... - - if ( wmh.do_subsamp ){ - - psf_subs.max_dimx = psf_bin.max_dimx * wmh.subsamp ; - psf_subs.max_dimz = psf_bin.max_dimz * wmh.subsamp ; - - if ( wmh.do_depth ){ - psf_subs.max_dimx += ( 1 + (int) ceilf( wmh.prj.crth * wmh.tmax_aix / wmh.prj.szcm ) ) * wmh.subsamp ; - psf_subs.max_dimz += ( 1 + (int) ceilf( wmh.prj.crth * wmh.tmax_aiz / wmh.prj.thcm ) ) * wmh.subsamp ; + + //... initialize psf2d in bins .................................................. + + wmh.max_amp = (wmh.prj.rad - wmh.ro) / (wmh.collim.rad - wmh.ro); + + psf_bin.max_dimx = (int)floorf(wmh.max_hsxcm * wmh.max_amp / wmh.prj.szcm) + 2; + psf_bin.max_dimz = (int)floorf(wmh.max_hszcm * wmh.max_amp / wmh.prj.thcm) + 2; + + //... distributions at mid resolution ........................................... + + if (wmh.do_subsamp) + { + + psf_subs.max_dimx = psf_bin.max_dimx * wmh.subsamp; + psf_subs.max_dimz = psf_bin.max_dimz * wmh.subsamp; + + if (wmh.do_depth) + { + psf_subs.max_dimx += (1 + (int)ceilf(wmh.prj.crth * wmh.tmax_aix / wmh.prj.szcm)) * wmh.subsamp; + psf_subs.max_dimz += (1 + (int)ceilf(wmh.prj.crth * wmh.tmax_aiz / wmh.prj.thcm)) * wmh.subsamp; } - - if ( wmh.do_psfi ){ - - int dimx = (int) ceil( (float)0.5 * wmh.prj.sgm_i * wmh.Nsigm / wmh.prj.szcm ) ; - int dimz = (int) ceil( (float)0.5 * wmh.prj.sgm_i * wmh.Nsigm / wmh.prj.thcm ) ; - - kern.dimx = kern.max_dimx = 2 * wmh.subsamp * dimx + 1 ; - kern.dimz = kern.max_dimz = 2 * wmh.subsamp * dimz + 1 ; - kern.ib0 = - dimx; - kern.jb0 = - dimz; - kern.lngxcmd2 = kern.lngzcmd2 = wmh.prj.sgm_i * wmh.Nsigm / (float)2.; - - kern.val = new float * [ kern.max_dimz ]; - - for ( int i = 0 ; i < kern.max_dimz ; i++ ) - kern.val[ i ] = new float [ kern.max_dimx ]; - - fill_psfi ( &kern, wmh ); - - psf_subs.max_dimx += kern.max_dimx - 1 ; - psf_subs.max_dimz += kern.max_dimz - 1 ; - - psf_aux.max_dimx = psf_aux.dimx = psf_subs.max_dimx ; - psf_aux.max_dimz = psf_aux.dimz = psf_subs.max_dimz ; - psf_aux.val = new float * [ psf_aux.max_dimz ]; - - for ( int i = 0 ; i < psf_aux.max_dimz ; i++ ) psf_aux.val[ i ] = new float [ psf_aux.max_dimx ]; + if (wmh.do_psfi) + { + + int dimx = (int)ceil((float)0.5 * wmh.prj.sgm_i * wmh.Nsigm / wmh.prj.szcm); + int dimz = (int)ceil((float)0.5 * wmh.prj.sgm_i * wmh.Nsigm / wmh.prj.thcm); + + kern.dimx = kern.max_dimx = 2 * wmh.subsamp * dimx + 1; + kern.dimz = kern.max_dimz = 2 * wmh.subsamp * dimz + 1; + kern.ib0 = -dimx; + kern.jb0 = -dimz; + kern.lngxcmd2 = kern.lngzcmd2 = wmh.prj.sgm_i * wmh.Nsigm / (float)2.; + + kern.val = new float*[kern.max_dimz]; + + for (int i = 0; i < kern.max_dimz; i++) + kern.val[i] = new float[kern.max_dimx]; + + fill_psfi(&kern, wmh); + + psf_subs.max_dimx += kern.max_dimx - 1; + psf_subs.max_dimz += kern.max_dimz - 1; + + psf_aux.max_dimx = psf_aux.dimx = psf_subs.max_dimx; + psf_aux.max_dimz = psf_aux.dimz = psf_subs.max_dimz; + + psf_aux.val = new float*[psf_aux.max_dimz]; + + for (int i = 0; i < psf_aux.max_dimz; i++) + psf_aux.val[i] = new float[psf_aux.max_dimx]; } - - psf_subs.val = new float * [ psf_subs.max_dimz ]; - - for ( int i = 0 ; i < psf_subs.max_dimz ; i++ ) psf_subs.val[ i ] = new float [ psf_subs.max_dimx ]; - - psf_bin.max_dimx = psf_subs.max_dimx / wmh.subsamp + 2 ; - psf_bin.max_dimz = psf_subs.max_dimz / wmh.subsamp + 2 ; + + psf_subs.val = new float*[psf_subs.max_dimz]; + + for (int i = 0; i < psf_subs.max_dimz; i++) + psf_subs.val[i] = new float[psf_subs.max_dimx]; + + psf_bin.max_dimx = psf_subs.max_dimx / wmh.subsamp + 2; + psf_bin.max_dimz = psf_subs.max_dimz / wmh.subsamp + 2; } - - psf_bin.val = new float * [ psf_bin.max_dimz ]; - - for ( int i = 0 ; i < psf_bin.max_dimz ; i++ ) psf_bin.val[ i ] = new float [ psf_bin.max_dimx ]; - - //... size estimation ......................................................... - - // number of non-zero elements for each weight matrix row - Nitems = new int * [ wmh.prj.NOS ]; - for (int kOS = 0 ; kOS < wmh.prj.NOS ; kOS++) { - Nitems[kOS] = new int [ wmh.prj.NbOS ]; - for ( int i = 0 ; i < wmh.prj.NbOS ; i++ ) Nitems[ kOS ][ i ] = 1; // Nitems initializated to one + + psf_bin.val = new float*[psf_bin.max_dimz]; + + for (int i = 0; i < psf_bin.max_dimz; i++) + psf_bin.val[i] = new float[psf_bin.max_dimx]; + + //... size estimation ......................................................... + + // number of non-zero elements for each weight matrix row + Nitems = new int*[wmh.prj.NOS]; + for (int kOS = 0; kOS < wmh.prj.NOS; kOS++) + { + Nitems[kOS] = new int[wmh.prj.NbOS]; + for (int i = 0; i < wmh.prj.NbOS; i++) + Nitems[kOS][i] = 1; // Nitems initializated to one } - //... double array wm.val and wm.col ..................................................... - - if ( ( wm.val = new (nothrow) float * [ wmh.prj.NbOS ] ) == nullptr ) - error("Error allocating space to store values for SPECTUB matrix"); //error_wmtools_SPECT_mph( 200, wmh.prj.NbOS, "wm.val[]" ); - - if ( ( wm.col = new (nothrow) int * [ wmh.prj.NbOS ] ) == nullptr ) - error("Error allocating space to store column indices for SPECTUB matrix"); //error_wmtools_SPECT_mph( 200, wmh.prj.NbOS, "wm.col[]" ); - - //... array wm.ne ......................................................................... - - if ( ( wm.ne = new (nothrow) int [ wmh.prj.NbOS + 1 ] ) == 0 ) - error("Error allocating space to store number of elements for SPECTUB matrix"); //error_wmtools_SPECT_mph(200, wmh.prj.NbOS + 1, "wm.ne[]"); - - // allocate memory for weight matrix - if ( wm.do_save_STIR ){ - wm.ns = new int [ wmh.prj.NbOS ]; - wm.nb = new int [ wmh.prj.NbOS ]; - wm.na = new int [ wmh.prj.NbOS ]; - - wm.nx = new short int [ wmh.vol.Nvox ]; - wm.ny = new short int [ wmh.vol.Nvox ]; - wm.nz = new short int [ wmh.vol.Nvox ]; + //... double array wm.val and wm.col ..................................................... + + if ((wm.val = new (nothrow) float*[wmh.prj.NbOS]) == nullptr) + error( + "Error allocating space to store values for SPECTUB matrix"); // error_wmtools_SPECT_mph( 200, wmh.prj.NbOS, "wm.val[]" ); + + if ((wm.col = new (nothrow) int*[wmh.prj.NbOS]) == nullptr) + error("Error allocating space to store column indices for SPECTUB matrix"); // error_wmtools_SPECT_mph( 200, wmh.prj.NbOS, + // "wm.col[]" ); + + //... array wm.ne ......................................................................... + + if ((wm.ne = new (nothrow) int[wmh.prj.NbOS + 1]) == 0) + error("Error allocating space to store number of elements for SPECTUB matrix"); // error_wmtools_SPECT_mph(200, wmh.prj.NbOS + + // 1, "wm.ne[]"); + + // allocate memory for weight matrix + if (wm.do_save_STIR) + { + wm.ns = new int[wmh.prj.NbOS]; + wm.nb = new int[wmh.prj.NbOS]; + wm.na = new int[wmh.prj.NbOS]; + + wm.nx = new short int[wmh.vol.Nvox]; + wm.ny = new short int[wmh.vol.Nvox]; + wm.nz = new short int[wmh.vol.Nvox]; } - // size estimation - for (int kOS = 0 ; kOS < wmh.prj.NOS ; kOS++) { - wm_calculation_mph ( false , kOS, &psf_bin, &psf_subs, &psf_aux, &kern, attmap, msk_3d, Nitems[ kOS ], wmh, wm, pcf ); + // size estimation + for (int kOS = 0; kOS < wmh.prj.NOS; kOS++) + { + wm_calculation_mph(false, kOS, &psf_bin, &psf_subs, &psf_aux, &kern, attmap, msk_3d, Nitems[kOS], wmh, wm, pcf); } - info(boost::format("Done estimating size of matrix. Execution time, CPU %1% s") % timer.value(), 2); + info(boost::format("Done estimating size of matrix. Execution time, CPU %1% s") % timer.value(), 2); - this->already_setup= true; + this->already_setup = true; } -ProjMatrixByBinPinholeSPECTUB* +ProjMatrixByBinPinholeSPECTUB* ProjMatrixByBinPinholeSPECTUB::clone() const { // we deleted the copy constructor as it's not safe with all those bare pointers, so cannot do this - //return new ProjMatrixByBinPinholeSPECTUB(*this); + // return new ProjMatrixByBinPinholeSPECTUB(*this); error("ProjMatrixByBinPinholeSPECTUB::clone not implemented yet"); return 0; } -ProjMatrixByBinPinholeSPECTUB:: -~ProjMatrixByBinPinholeSPECTUB() +ProjMatrixByBinPinholeSPECTUB::~ProjMatrixByBinPinholeSPECTUB() { - delete_PinholeSPECTUB_arrays(); + delete_PinholeSPECTUB_arrays(); } - void -ProjMatrixByBinPinholeSPECTUB:: -delete_PinholeSPECTUB_arrays() +ProjMatrixByBinPinholeSPECTUB::delete_PinholeSPECTUB_arrays() { - if (!this->already_setup) - return; - - //... freeing matrix memory.................................... - - delete [] wm.val; - delete [] wm.col; - delete [] wm.ne; - - if ( wm.do_save_STIR ){ - delete [] wm.ns; - delete [] wm.nb; - delete [] wm.na; - delete [] wm.nx; - delete [] wm.ny; - delete [] wm.nz; + if (!this->already_setup) + return; + + //... freeing matrix memory.................................... + + delete[] wm.val; + delete[] wm.col; + delete[] wm.ne; + + if (wm.do_save_STIR) + { + delete[] wm.ns; + delete[] wm.nb; + delete[] wm.na; + delete[] wm.nx; + delete[] wm.ny; + delete[] wm.nz; } - //... freeing pre-calculated functions .................................... + //... freeing pre-calculated functions .................................... - if ( wmh.do_round_cumsum ){ - for ( int i = 0 ; i < pcf.round.dim ; i ++ ) delete [] pcf.round.val[ i ]; - delete [] pcf.round.val; + if (wmh.do_round_cumsum) + { + for (int i = 0; i < pcf.round.dim; i++) + delete[] pcf.round.val[i]; + delete[] pcf.round.val; } - - if ( wmh.do_square_cumsum ){ - for ( int i = 0 ; i < pcf.square.dim ; i ++ ) delete [] pcf.square.val[ i ]; - delete [] pcf.square.val; + + if (wmh.do_square_cumsum) + { + for (int i = 0; i < pcf.square.dim; i++) + delete[] pcf.square.val[i]; + delete[] pcf.square.val; } - - if ( wmh.do_depth ) delete pcf.cr_att.val ; - //... freeing memory .................................... + if (wmh.do_depth) + delete pcf.cr_att.val; - for ( int i = 0 ; i < psf_bin.max_dimz ; i++ ) delete [] psf_bin.val[ i ]; - delete [] psf_bin.val; - - if ( wmh.do_subsamp ){ - for ( int i = 0 ; i < psf_subs.max_dimz ; i++ ) delete [] psf_subs.val[ i ]; - delete [] psf_subs.val; + //... freeing memory .................................... + + for (int i = 0; i < psf_bin.max_dimz; i++) + delete[] psf_bin.val[i]; + delete[] psf_bin.val; + + if (wmh.do_subsamp) + { + for (int i = 0; i < psf_subs.max_dimz; i++) + delete[] psf_subs.val[i]; + delete[] psf_subs.val; } - - if ( wmh.do_psfi ){ - for ( int i = 0 ; i < kern.max_dimz ; i++ ) delete [] kern.val[ i ]; - delete [] kern.val; - // original code did not deallocate psf_aux.val, possible memory leak - for ( int i = 0 ; i < psf_aux.max_dimz ; i++ ) delete [] psf_aux.val[ i ]; - delete [] psf_aux.val; + if (wmh.do_psfi) + { + for (int i = 0; i < kern.max_dimz; i++) + delete[] kern.val[i]; + delete[] kern.val; + + // original code did not deallocate psf_aux.val, possible memory leak + for (int i = 0; i < psf_aux.max_dimz; i++) + delete[] psf_aux.val[i]; + delete[] psf_aux.val; } - - for (int kOS = 0 ; kOS < wmh.prj.NOS ; kOS++) - delete [] Nitems[ kOS ]; - delete [] Nitems; - - if ( wmh.do_att ) delete [] attmap; - delete [] msk_3d; -} + for (int kOS = 0; kOS < wmh.prj.NOS; kOS++) + delete[] Nitems[kOS]; + delete[] Nitems; + if (wmh.do_att) + delete[] attmap; + + delete[] msk_3d; +} void -ProjMatrixByBinPinholeSPECTUB:: -compute_one_subset(const int kOS) const +ProjMatrixByBinPinholeSPECTUB::compute_one_subset(const int kOS) const { - CPUTimer timer; - timer.start(); - - //... size information .......................................................................... + CPUTimer timer; + timer.start(); - unsigned int ne = 0; + //... size information .......................................................................... - for ( int i = 0 ; i < wmh.prj.NbOS ; i++ ) ne += Nitems[kOS][ i ]; + unsigned int ne = 0; - info(boost::format("Total number of non-zero weights in this view: %1%, estimated size: %2% MB") - % ne - % ( wm.do_save_STIR ? (ne + 10* wmh.prj.NbOS)/104857.6 : ne/131072), - 2); + for (int i = 0; i < wmh.prj.NbOS; i++) + ne += Nitems[kOS][i]; - //... memory allocation for wm float arrays .................................................... + info(boost::format("Total number of non-zero weights in this view: %1%, estimated size: %2% MB") % ne + % (wm.do_save_STIR ? (ne + 10 * wmh.prj.NbOS) / 104857.6 : ne / 131072), + 2); - wm_alloc( Nitems[kOS], wm, wmh ); + //... memory allocation for wm float arrays .................................................... - //... wm calculation ............................................................................... + wm_alloc(Nitems[kOS], wm, wmh); - wm_calculation_mph ( true, kOS, &psf_bin, &psf_subs, &psf_aux, &kern, attmap, msk_3d, Nitems[kOS], wmh, wm, pcf ); - info(boost::format("Weight matrix calculation done, CPU %1% s") % timer.value(), - 2); + //... wm calculation ............................................................................... - //... fill lor .......................... - for( int j = 0 ; j < wmh.prj.NbOS ; j++ ){ - ProjMatrixElemsForOneBin lor; - Bin bin; - bin.segment_num()=0; - bin.view_num()=wm.na [ j ]; - bin.axial_pos_num()=wm.ns [ j ]; - bin.tangential_pos_num()=wm.nb [ j ]; - bin.set_bin_value(0); - lor.set_bin(bin); + wm_calculation_mph(true, kOS, &psf_bin, &psf_subs, &psf_aux, &kern, attmap, msk_3d, Nitems[kOS], wmh, wm, pcf); + info(boost::format("Weight matrix calculation done, CPU %1% s") % timer.value(), 2); - lor.reserve(wm.ne[ j ]); - for ( int i = 0 ; i < wm.ne[ j ] ; i++ ){ - - 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); + //... fill lor .......................... + for (int j = 0; j < wmh.prj.NbOS; j++) + { + ProjMatrixElemsForOneBin lor; + Bin bin; + bin.segment_num() = 0; + bin.view_num() = wm.na[j]; + bin.axial_pos_num() = wm.ns[j]; + bin.tangential_pos_num() = wm.nb[j]; + bin.set_bin_value(0); + lor.set_bin(bin); + + lor.reserve(wm.ne[j]); + for (int i = 0; i < wm.ne[j]; i++) + { + + 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); + this->cache_proj_matrix_elems_for_one_bin(lor); } - info(boost::format("Total time after transfering to ProjMatrixElemsForOneBin, CPU %1% s") % timer.value(), - 2); + info(boost::format("Total time after transfering to ProjMatrixElemsForOneBin, CPU %1% s") % timer.value(), 2); } - -void -ProjMatrixByBinPinholeSPECTUB:: -calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor - ) const +void +ProjMatrixByBinPinholeSPECTUB::calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { - const int view_num=lor.get_bin().view_num(); + const int view_num = lor.get_bin().view_num(); #ifdef STIR_OPENMP -#pragma omp critical(PROJMATRIXBYBINUBONEVIEW) +# pragma omp critical(PROJMATRIXBYBINUBONEVIEW) #endif - if (!this->keep_all_views_in_cache) this->clear_cache(); - - info(boost::format("Computing matrix elements for view %1%") % view_num, - 2); - compute_one_subset(view_num); - - lor.erase(); -} + if (!this->keep_all_views_in_cache) + this->clear_cache(); + info(boost::format("Computing matrix elements for view %1%") % view_num, 2); + compute_one_subset(view_num); + lor.erase(); +} //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%% associated functions: reading, setting up variables and error messages %%%%%% diff --git a/src/recon_buildblock/ProjMatrixByBinSPECTUB.cxx b/src/recon_buildblock/ProjMatrixByBinSPECTUB.cxx index 1dd61a420..554cfc2f9 100644 --- a/src/recon_buildblock/ProjMatrixByBinSPECTUB.cxx +++ b/src/recon_buildblock/ProjMatrixByBinSPECTUB.cxx @@ -35,7 +35,7 @@ #include "stir/error.h" #include "stir/CPUTimer.h" #ifdef STIR_OPENMP -#include "stir/num_threads.h" +# include "stir/num_threads.h" #endif //#include "boost/cstdint.hpp" @@ -62,19 +62,15 @@ using namespace SPECTUB; START_NAMESPACE_STIR -const char * const -ProjMatrixByBinSPECTUB::registered_name = -"SPECT UB"; +const char* const ProjMatrixByBinSPECTUB::registered_name = "SPECT UB"; -ProjMatrixByBinSPECTUB:: -ProjMatrixByBinSPECTUB() +ProjMatrixByBinSPECTUB::ProjMatrixByBinSPECTUB() { - set_defaults(); + set_defaults(); } -void -ProjMatrixByBinSPECTUB:: -initialise_keymap() +void +ProjMatrixByBinSPECTUB::initialise_keymap() { parser.add_start_key("Projection Matrix By Bin SPECT UB Parameters"); ProjMatrixByBin::initialise_keymap(); @@ -96,26 +92,24 @@ initialise_keymap() parser.add_stop_key("End Projection Matrix By Bin SPECT UB Parameters"); } - void 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 @@ -130,21 +124,19 @@ 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) +ProjMatrixByBinSPECTUB::set_keep_all_views_in_cache(bool value) { if (this->keep_all_views_in_cache != value) { @@ -154,38 +146,34 @@ set_keep_all_views_in_cache(bool value) } 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) +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") + 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; - this->attenuation_map=""; + this->attenuation_map = ""; if (this->attenuation_type == "no") { info("Setting attenuation type to 'simple'"); @@ -195,17 +183,17 @@ set_attenuation_image_sptr(const shared_ptr > } 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, const bool full_3D) +ProjMatrixByBinSPECTUB::set_resolution_model(const float collimator_sigma_0_in_mm, + const float collimator_slope, + const bool full_3D) { // convert sigma_0 to cm. slope is dimensionless this->collimator_sigma_0 = collimator_sigma_0_in_mm / 10; @@ -226,11 +214,9 @@ set_resolution_model(const float collimator_sigma_0_in_mm, const float collimato } 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); @@ -243,524 +229,547 @@ set_up( } #endif - 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->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_intrinsic_azimuthal_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(); + { - 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(); - } + const auto max_radius = *std::max_element(radius_all_views.begin(), radius_all_views.end()); + const auto max_im_radius = std::max(vol.Xcmd2, vol.Ycmd2) * 10; + if (max_im_radius > max_radius) + { + warning("Image radius (" + std::to_string(max_im_radius) + " is larger than max detector radius (" + + std::to_string(max_radius) + "). Are you sure this is correct? (Proceeding anyway)"); + } } + 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; + } - 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_intrinsic_azimuthal_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(); + //... 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; + wmh.do_psf_3d = 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 { - const auto max_radius = *std::max_element(radius_all_views.begin(), radius_all_views.end()); - const auto max_im_radius = std::max(vol.Xcmd2, vol.Ycmd2)*10; - if (max_im_radius > max_radius) + if (psf_type == "2d") { - warning("Image radius (" + std::to_string(max_im_radius) + " is larger than max detector radius (" + - std::to_string(max_radius) + "). Are you sure this is correct? (Proceeding anyway)"); + 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"); } } - 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; - wmh.do_psf_3d = 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"); - } - } - } - - wmh.predef_col = false; - wmh.COL.A = collimator_slope; - wmh.COL.B = collimator_sigma_0; - // no fan-beam - wmh.COL.do_fb = false; - - if ( !wmh.do_psf ) - // 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 ( wmh.COL.do_fb ==0 ) { - info_stream << "No correction for PSF. Parallel geometry" << std::endl; - //} - //else { - // 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); - wmh.att_fn=this->attenuation_map; - - if ( attenuation_type == "no" ) { - wmh.do_full_att=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.predef_col = false; + wmh.COL.A = collimator_slope; + wmh.COL.B = collimator_sigma_0; + // no fan-beam + wmh.COL.do_fb = false; + + if (!wmh.do_psf) + // 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 ( wmh.COL.do_fb ==0 ) { + info_stream << "No correction for PSF. Parallel geometry" << std::endl; + //} + // else { + // 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); + wmh.att_fn = this->attenuation_map; + + if (attenuation_type == "no") + { + wmh.do_full_att = wmh.do_att = false; + } + else + { + wmh.do_att = true; + + if (attenuation_type == "simple") + wmh.do_full_att = false; + else { - wmh.do_msk_cyl = true; - wmh.do_msk_att = wmh.do_msk_file = false; + 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"); + } } - else { - if( mask_type == "attenuation map" ) + } + + //... 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; + wmh.do_msk_att = wmh.do_msk_file = false; + } + else + { + if (mask_type == "attenuation map") + { + wmh.do_msk_att = true; + wmh.do_msk_cyl = wmh.do_msk_file = false; + } + else + { + if (mask_type == "explicit mask") + { + wmh.do_msk_file = true; + wmh.do_msk_cyl = wmh.do_msk_att = false; + 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, wmh); + + //... to fill ang structure ............................................ + + ang = new angle_type[prj.Nang]; + fill_ang(ang, wmh, Rrad); + + //... 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"); + std::string explanation; + if (!density_info_ptr->has_same_characteristics(*attenuation_image_sptr, explanation)) + error("Currently the attenuation map and emission image must have the same dimension, orientation and voxel size:\n" + + explanation); + + 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])) { - wmh.do_msk_att = true; - wmh.do_msk_cyl = wmh.do_msk_file = false; + attmap[i] = 0; } - else{ - if( mask_type == "explicit mask" ){ - wmh.do_msk_file = true; - wmh.do_msk_cyl = wmh.do_msk_att = false; - 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, explanation)) - error("Currently the attenuation map and emission image must have the same dimension, orientation and voxel size:\n" + explanation); - - 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, wmh); - delete[] mask_from_file; - } - else - { - generate_msk( msk_3d, msk_2d, attmap, &vol, wmh); - } - } - 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 + } + // 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, wmh); + delete[] mask_from_file; + } + else + { + generate_msk(msk_3d, msk_2d, attmap, &vol, wmh); + } + } + 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, wmh); // 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"); + } - //... setting PSF maximum size (in bins) and memory allocation for PSF values ....... + //... STIR indices ....................................................................... - this->maxszb = max_psf_szb( ang, wmh ); // maximum PSF size (horizontal component of PSF) - NITEMS = new int * [prj.NOS]; - for (int kOS=0; kOSalready_setup= true; + wmh.index[i] = prj.order[i + kOS * prj.NangOS]; + wmh.Rrad[i] = Rrad[wmh.index[i]]; + if (wmh.Rrad[i] != wmh.Rrad[0]) + wmh.fixed_Rrad = false; + } + + //... NITEMS initialization ...................... + + for (int i = 0; i < prj.NbOS; i++) + NITEMS[kOS][i] = 1; + + //... size estimations ........................................................ + + wm_size_estimation(kOS, ang, vox, bin, vol, prj, msk_3d, msk_2d, maxszb, &gaussdens, NITEMS[kOS], wmh, Rrad); + + // cout << "\nwm_SPECT. Size estimation done. time (s): " << double( clock()-ini )/CLOCKS_PER_SEC <already_setup = true; } -ProjMatrixByBinSPECTUB* +ProjMatrixByBinSPECTUB* ProjMatrixByBinSPECTUB::clone() const { // we deleted the copy constructor as it's not safe with all those bare pointers, so cannot do this - //return new ProjMatrixByBinSPECTUB(*this); + // return new ProjMatrixByBinSPECTUB(*this); error("ProjMatrixByBinSPECTUB::clone not implemented yet"); return 0; } -ProjMatrixByBinSPECTUB:: -~ProjMatrixByBinSPECTUB() +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.................................... - 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; kOSwmh.subset_ind = kOS; - for ( int i = 0 ; i < prj.NangOS ; i ++ ){ + for (int i = 0; i < prj.NangOS; i++) + { - this->wmh.index[ i ] = prj.order[ i + kOS * prj.NangOS ]; - this->wmh.Rrad [ i ] = Rrad[ this->wmh.index[ i ] ]; - } + this->wmh.index[i] = prj.order[i + kOS * prj.NangOS]; + this->wmh.Rrad[i] = Rrad[this->wmh.index[i]]; + } //... NITEMS initialization ...................... // for ( int i = 0 ; i < prj.NbOS ; i++ ) NITEMS[ i ] = 1; - //... size esmitations ........................................................ - //wm_size_estimation ( kOS, ang, vox, bin, vol, prj, msk_3d, msk_2d, maxszb, &gaussdens, NITEMS ); + // wm_size_estimation ( kOS, ang, vox, bin, vol, prj, msk_3d, msk_2d, maxszb, &gaussdens, NITEMS ); - //cout << "\nwm_SPECT. Size estimation done. time (s): " << double( clock()-ini )/CLOCKS_PER_SEC <wmh.prj.NbOS ; i++ ) ne += NITEMS[kOS][ i ]; + for (int i = 0; i < this->wmh.prj.NbOS; i++) + ne += NITEMS[kOS][i]; //... size information .................................................................... - info(boost::format("total number of non-zero weights in this view: %1%, estimated size: %2% MB") - % ne - % ( this->wm.do_save_STIR ? (ne + 10* prj.NbOS)/104857.6 : ne/131072), + info(boost::format("total number of non-zero weights in this view: %1%, estimated size: %2% MB") % ne + % (this->wm.do_save_STIR ? (ne + 10 * prj.NbOS) / 104857.6 : ne / 131072), 2); //... memory allocation for wm float arrays ................................... - for( int i = 0 ; i < this->wmh.prj.NbOS ; i++ ){ + for (int i = 0; i < this->wmh.prj.NbOS; i++) + { - if ( ( this->wm.val[ i ] = new (std::nothrow) float [ NITEMS[kOS][ i ] ]) == NULL) - { - //error_wm_SPECT( 200, "wm.val[][]" ); - error("Error allocating space to store values for SPECTUB matrix"); - } + if ((this->wm.val[i] = new (std::nothrow) float[NITEMS[kOS][i]]) == NULL) + { + // error_wm_SPECT( 200, "wm.val[][]" ); + error("Error allocating space to store values for SPECTUB matrix"); + } - if ( ( this->wm.col[ i ] = new (std::nothrow) int [ NITEMS[kOS][ i ] ]) == NULL) - { - //error_wm_SPECT( 200, "wm.col[]" ); - error("Error allocating space to store column indices for SPECTUB matrix"); - } - } + if ((this->wm.col[i] = new (std::nothrow) int[NITEMS[kOS][i]]) == NULL) + { + // error_wm_SPECT( 200, "wm.col[]" ); + error("Error allocating space to store column indices for SPECTUB matrix"); + } + } //... to initialize wm to zero ...................... - for ( int i = 0 ; i < this->wm.NbOS ; i++ ){ + for (int i = 0; i < this->wm.NbOS; i++) + { - this->wm.ne[ i ] = 0; + this->wm.ne[i] = 0; - for( int j = 0 ; j < NITEMS[kOS][ i ] ; j++ ){ + for (int j = 0; j < NITEMS[kOS][i]; j++) + { - this->wm.val[ i ][ j ] = (float)0.; - this->wm.col[ i ][ j ] = 0; + this->wm.val[i][j] = (float)0.; + this->wm.col[i][j] = 0; + } } - } - this->wm.ne[ this->wm.NbOS ] = 0; + this->wm.ne[this->wm.NbOS] = 0; //... wm calculation for this subset ........................... - wm_calculation ( kOS, ang, vox, bin, vol, prj, attmap, msk_3d, msk_2d, maxszb, &gaussdens, NITEMS[kOS], - this->wm, this->wmh, Rrad ); - info(boost::format("Weight matrix calculation done. time %1% (s)") % timer.value(), - 2); + wm_calculation( + kOS, ang, vox, bin, vol, prj, attmap, msk_3d, msk_2d, maxszb, &gaussdens, NITEMS[kOS], this->wm, this->wmh, Rrad); + info(boost::format("Weight matrix calculation done. time %1% (s)") % timer.value(), 2); //... fill lor ......................... - for( int j = 0 ; j < this->wm.NbOS ; j++ ){ - ProjMatrixElemsForOneBin lor; - Bin bin; - bin.segment_num()=0; - bin.view_num()=this->wm.na [ j ]; - bin.axial_pos_num()=this->wm.ns [ j ]; - bin.tangential_pos_num()=this->wm.nb [ j ]; - bin.set_bin_value(0); - lor.set_bin(bin); - - lor.reserve(this->wm.ne[ j ]); - for ( int i = 0 ; i < this->wm.ne[ j ] ; i++ ){ - - const ProjMatrixElemsForOneBin::value_type - elem(Coordinate3D(this->wm.nz[ this->wm.col[ j ][ i ] ],this->wm.ny[ this->wm.col[ j ][ i ] ],this->wm.nx[ this->wm.col[ j ][ i ] ]), this->wm.val[ j ][ i ]); - lor.push_back( elem); - } + for (int j = 0; j < this->wm.NbOS; j++) + { + ProjMatrixElemsForOneBin lor; + Bin bin; + bin.segment_num() = 0; + bin.view_num() = this->wm.na[j]; + bin.axial_pos_num() = this->wm.ns[j]; + bin.tangential_pos_num() = this->wm.nb[j]; + bin.set_bin_value(0); + lor.set_bin(bin); + + lor.reserve(this->wm.ne[j]); + for (int i = 0; i < this->wm.ne[j]; i++) + { - delete [] this->wm.val[ j ]; - delete [] this->wm.col[ j ]; + const ProjMatrixElemsForOneBin::value_type elem(Coordinate3D(this->wm.nz[this->wm.col[j][i]], + this->wm.ny[this->wm.col[j][i]], + this->wm.nx[this->wm.col[j][i]]), + this->wm.val[j][i]); + lor.push_back(elem); + } - this->cache_proj_matrix_elems_for_one_bin(lor); - } + delete[] this->wm.val[j]; + delete[] this->wm.col[j]; - info(boost::format("Total time after transfering to ProjMatrixElemsForOneBin. time %1% (s)") % timer.value(), - 2); + this->cache_proj_matrix_elems_for_one_bin(lor); + } + 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 +void +ProjMatrixByBinSPECTUB::calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { - //error("ProjMatrixByBinSPECTUB element not found in cache (and hence file)"); + // error("ProjMatrixByBinSPECTUB element not found in cache (and hence file)"); - const int view_num=lor.get_bin().view_num(); + 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); - } + { + this->clear_cache(); + subset_already_processed.assign(prj.NOS, false); + } info(boost::format("Computing matrix elements for view %1%") % view_num, - 2);// potentially pass a wm, wmh[threadh] not sure if works then in setup we need an array of wmh - compute_one_subset(kOS,Rrad); - subset_already_processed[kOS]=true; + 2); // potentially pass a wm, wmh[threadh] not sure if works then in setup we need an array of wmh + compute_one_subset(kOS, Rrad); + 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 1be4d6c48..ed82fb433 100644 --- a/src/recon_buildblock/ProjMatrixByBinUsingInterpolation.cxx +++ b/src/recon_buildblock/ProjMatrixByBinUsingInterpolation.cxx @@ -35,36 +35,31 @@ 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) +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); + 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() +ProjMatrixByBinUsingInterpolation::ProjMatrixByBinUsingInterpolation() { set_defaults(); } -void +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); @@ -74,7 +69,6 @@ ProjMatrixByBinUsingInterpolation::initialise_keymap() parser.add_stop_key("End Interpolation Matrix Parameters"); } - void ProjMatrixByBinUsingInterpolation::set_defaults() { @@ -89,7 +83,6 @@ ProjMatrixByBinUsingInterpolation::set_defaults() use_exact_Jacobian_now = true; } - bool ProjMatrixByBinUsingInterpolation::post_processing() { @@ -98,85 +91,73 @@ ProjMatrixByBinUsingInterpolation::post_processing() 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)); + 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"); - } + 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"); + } } - } + } } ProjMatrixByBinUsingInterpolation* ProjMatrixByBinUsingInterpolation::clone() const { - return new ProjMatrixByBinUsingInterpolation(*this); + 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) +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); + s = (point.x() * cphi + point.y() * sphi); - m = - point.z()- tantheta*(-point.x()*sphi+point.y()*cphi); + m = point.z() - tantheta * (-point.x() * sphi + point.y() * cphi); } - /* interpolationkernel[s,a,b] b == interpolationkernel[s,b,a] a @@ -188,59 +169,47 @@ interpolationkernel[s_,ssize_,xsize_] \ */ // piecewise_linear interpolation for bin between -1 and 1 // vox -static inline -float +static inline float piecewise_linear_interpolate(const float s, const float vox_size) { - if (fabs(s)(2+vox_size)/2) + 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 +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 +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 @@ -271,44 +240,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); @@ -326,7 +279,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) @@ -352,35 +305,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: @@ -388,16 +327,15 @@ 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]) + 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())]; + 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(); @@ -405,63 +343,59 @@ calculate_proj_matrix_elems_for_one_bin( #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() + // 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(); + 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; + found_nonzero1 = true; #ifndef __PMByBinElement_SLOW__ else if (found_nonzero1) - break; + break; #endif } } diff --git a/src/recon_buildblock/ProjMatrixByBinUsingRayTracing.cxx b/src/recon_buildblock/ProjMatrixByBinUsingRayTracing.cxx index 4fae773dc..85714256a 100644 --- a/src/recon_buildblock/ProjMatrixByBinUsingRayTracing.cxx +++ b/src/recon_buildblock/ProjMatrixByBinUsingRayTracing.cxx @@ -31,14 +31,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). */ @@ -64,26 +64,21 @@ using std::min; using std::max; START_NAMESPACE_STIR +const char* const ProjMatrixByBinUsingRayTracing::registered_name = "Ray Tracing"; -const char * const -ProjMatrixByBinUsingRayTracing::registered_name = - "Ray Tracing"; - -ProjMatrixByBinUsingRayTracing:: -ProjMatrixByBinUsingRayTracing() +ProjMatrixByBinUsingRayTracing::ProjMatrixByBinUsingRayTracing() { set_defaults(); } //******************** parsing ************* -void +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); @@ -93,7 +88,6 @@ ProjMatrixByBinUsingRayTracing::initialise_keymap() parser.add_stop_key("End Ray Tracing Matrix Parameters"); } - void ProjMatrixByBinUsingRayTracing::set_defaults() { @@ -109,18 +103,17 @@ ProjMatrixByBinUsingRayTracing::set_defaults() this->already_setup = false; } - bool 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); - 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); + return true; + } this->already_setup = false; return false; } @@ -128,130 +121,109 @@ 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->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->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->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->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->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->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->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->already_setup && (this->do_symmetry_shift_z == val); this->do_symmetry_shift_z = val; } - //******************** actual implementation ************* #if 0 @@ -264,28 +236,25 @@ static bool is_multiple(const float a, const float b) #endif void -ProjMatrixByBinUsingRayTracing:: -set_up( +ProjMatrixByBinUsingRayTracing::set_up( const shared_ptr& proj_data_info_sptr_v, - const shared_ptr >& density_info_sptr_v // TODO should be Info only - ) + const shared_ptr>& density_info_sptr_v // TODO should be Info only +) { - auto image_info_ptr = dynamic_cast*> (density_info_sptr_v.get()); + auto image_info_ptr = dynamic_cast*>(density_info_sptr_v.get()); if (!image_info_ptr) error("ProjMatrixByBinUsingRayTracing initialised with wrong type of DiscretisedDensity."); if (this->already_setup) { - if (*this->proj_data_info_sptr == *proj_data_info_sptr_v && - this->voxel_size == image_info_ptr->get_voxel_size() && - this->origin == image_info_ptr->get_origin()) + if (*this->proj_data_info_sptr == *proj_data_info_sptr_v && this->voxel_size == image_info_ptr->get_voxel_size() + && this->origin == image_info_ptr->get_origin()) { CartesianCoordinate3D new_min_index; CartesianCoordinate3D new_max_index; image_info_ptr->get_regular_range(new_min_index, new_max_index); - if (this->max_index == new_max_index && - this->min_index == new_min_index) + if (this->max_index == new_max_index && this->min_index == new_min_index) { info("ProjMatrixByBinUsingRayTracing::set_up skipped as already set-up with same characteristics.", 3); } @@ -297,127 +266,119 @@ set_up( voxel_size = image_info_ptr->get_voxel_size(); origin = image_info_ptr->get_origin(); - if (abs(origin.x())>.05F || abs(origin.y())>.05F) + 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(boost::format("ProjMatrixByBinUsingRayTracing used for pixel size (x,y)=(%g,%g) " - "that is smaller than the central bin size (%g) divided by num_tangential_LORs (%d).\n" - "This matrix will completely miss some voxels for some (or all) views. It is therefore to best to increase " - "'number of rays in tangential direction to trace for each bin'.") - % voxel_size.x() % voxel_size.y() % sampling_distance_of_adjacent_LORs_xy % num_tangential_LORs); + 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( + boost::format("ProjMatrixByBinUsingRayTracing used for pixel size (x,y)=(%g,%g) " + "that is smaller than the central bin size (%g) divided by num_tangential_LORs (%d).\n" + "This matrix will completely miss some voxels for some (or all) views. It is therefore to best to increase " + "'number of rays in tangential direction to trace for each bin'.") + % voxel_size.x() % voxel_size.y() % sampling_distance_of_adjacent_LORs_xy % num_tangential_LORs); if (use_actual_detector_boundaries) { - if (proj_data_info_sptr->get_scanner_ptr()->get_scanner_geometry()== "Cylindrical") - { - const ProjDataInfoCylindricalNoArcCorr * proj_data_info_cyl_ptr = - dynamic_cast(proj_data_info_sptr.get()); - if (proj_data_info_cyl_ptr== 0) + if (proj_data_info_sptr->get_scanner_ptr()->get_scanner_geometry() == "Cylindrical") { - warning("ProjMatrixByBinUsingRayTracing: use_actual_detector_boundaries" - " is reset to false as the projection data should be non-arccorrected."); - use_actual_detector_boundaries = false; + 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-arccorrected."); + 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; + } + } } - else + else if (proj_data_info_sptr->get_scanner_ptr()->get_scanner_geometry() == "BlocksOnCylindrical") { - 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) + const ProjDataInfoBlocksOnCylindricalNoArcCorr* proj_data_info_blk_ptr + = dynamic_cast(proj_data_info_sptr.get()); + + if (proj_data_info_blk_ptr == 0) { warning("ProjMatrixByBinUsingRayTracing: use_actual_detector_boundaries" - " is reset to false as the projection data as either mashed or uses axial compression\n"); + " is reset to false as the projection data should be non-arccorrected."); use_actual_detector_boundaries = false; } + else + { + bool nocompression = proj_data_info_blk_ptr->get_view_mashing_factor() == 1; + for (int segment_num = proj_data_info_blk_ptr->get_min_segment_num(); + nocompression && segment_num <= proj_data_info_blk_ptr->get_max_segment_num(); + ++segment_num) + nocompression = proj_data_info_blk_ptr->get_min_ring_difference(segment_num) + == proj_data_info_blk_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."); + use_actual_detector_boundaries = false; + } + } } - } - else if(proj_data_info_sptr->get_scanner_ptr()->get_scanner_geometry()== "BlocksOnCylindrical") - { - const ProjDataInfoBlocksOnCylindricalNoArcCorr * proj_data_info_blk_ptr = - dynamic_cast(proj_data_info_sptr.get()); - - if (proj_data_info_blk_ptr== 0) - { - warning("ProjMatrixByBinUsingRayTracing: use_actual_detector_boundaries" - " is reset to false as the projection data should be non-arccorrected."); - use_actual_detector_boundaries = false; - } else - { - bool nocompression = - proj_data_info_blk_ptr->get_view_mashing_factor()==1; - for (int segment_num=proj_data_info_blk_ptr->get_min_segment_num(); - nocompression && segment_num <= proj_data_info_blk_ptr->get_max_segment_num(); - ++segment_num) - nocompression= - proj_data_info_blk_ptr->get_min_ring_difference(segment_num) == - proj_data_info_blk_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."); - use_actual_detector_boundaries = false; - } - } - } - else - { - const ProjDataInfoGenericNoArcCorr * proj_data_info_blk_ptr = - dynamic_cast(proj_data_info_sptr.get()); - - if (proj_data_info_blk_ptr== 0) { - warning("ProjMatrixByBinUsingRayTracing: use_actual_detector_boundaries" - " is reset to false as the projection data should be non-arccorrected."); - use_actual_detector_boundaries = false; - } - else - { - bool nocompression = - proj_data_info_blk_ptr->get_view_mashing_factor()==1; - for (int segment_num=proj_data_info_blk_ptr->get_min_segment_num(); - nocompression && segment_num <= proj_data_info_blk_ptr->get_max_segment_num(); - ++segment_num) - nocompression= - proj_data_info_blk_ptr->get_min_ring_difference(segment_num) == - proj_data_info_blk_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."); - use_actual_detector_boundaries = false; - } + const ProjDataInfoGenericNoArcCorr* proj_data_info_blk_ptr + = dynamic_cast(proj_data_info_sptr.get()); + + if (proj_data_info_blk_ptr == 0) + { + warning("ProjMatrixByBinUsingRayTracing: use_actual_detector_boundaries" + " is reset to false as the projection data should be non-arccorrected."); + use_actual_detector_boundaries = false; + } + else + { + bool nocompression = proj_data_info_blk_ptr->get_view_mashing_factor() == 1; + for (int segment_num = proj_data_info_blk_ptr->get_min_segment_num(); + nocompression && segment_num <= proj_data_info_blk_ptr->get_max_segment_num(); + ++segment_num) + nocompression = proj_data_info_blk_ptr->get_min_ring_difference(segment_num) + == proj_data_info_blk_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."); + use_actual_detector_boundaries = false; + } + } } - } - - if (use_actual_detector_boundaries) - info("ProjMatrixByBinUsingRayTracing: use_actual_detector_boundaries==true.", 3); - } + if (use_actual_detector_boundaries) + info("ProjMatrixByBinUsingRayTracing: use_actual_detector_boundaries==true.", 3); + } - #if 0 +#if 0 // test if our 2D code does not have problems { // currently 2D code relies on the LOR falling in the middle of a voxel (in z-direction) @@ -430,8 +391,7 @@ set_up( "- or an even number of planes and z_origin=(n+1/2)*z_voxel_size\n" "(for some integer n).\n"); } - #endif - +#endif this->already_setup = true; this->clear_cache(); @@ -440,17 +400,14 @@ set_up( ProjMatrixByBinUsingRayTracing* ProjMatrixByBinUsingRayTracing::clone() const { - return new ProjMatrixByBinUsingRayTracing(*this); + return new ProjMatrixByBinUsingRayTracing(*this); } -/* this is used when +/* 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 @@ -462,17 +419,21 @@ static void merge_zplus1(ProjMatrixElemsForOneBin& lor); #endif template -static inline int sign(const T& t) +static inline int +sign(const T& t) { - return t<0 ? -1 : 1; + 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, +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, @@ -483,70 +444,71 @@ ray_trace_one_lor(ProjMatrixElemsForOneBin& lor, /* 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) - { + { #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; - } - } // restrict_to_cylindrical_FOV + // 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 - { - // 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 - |X| <= fovrad_in_mm && |Y| <= fovrad_in_mm - */ - 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()) - 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(); + // 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 + |X| <= fovrad_in_mm && |Y| <= fovrad_in_mm + */ + 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()) + 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(); #if 0 // KT 18/05/2005 this is no longer necessary @@ -573,47 +535,42 @@ 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())))); + 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())))); // 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, + + 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 +void +ProjMatrixByBinUsingRayTracing::calculate_proj_matrix_elems_for_one_bin(ProjMatrixElemsForOneBin& lor) const { if (!this->already_setup) { @@ -621,11 +578,11 @@ calculate_proj_matrix_elems_for_one_bin( } const Bin bin = lor.get_bin(); - 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(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_sptr->get_s(bin); /* Implementation note. @@ -636,93 +593,83 @@ 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_sptr->get_phi(bin); - //s_in_mm = proj_data_info_sptr->get_s(bin); - } - else - { - if (proj_data_info_sptr->get_scanner_ptr()->get_scanner_geometry()== "Cylindrical") { - // can be static_cast later on - const ProjDataInfoCylindricalNoArcCorr& proj_data_info_noarccor = - dynamic_cast(*proj_data_info_sptr); - // TODO check on 180 degrees for views - 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 + proj_data_info_noarccor.get_azimuthal_angle_offset() ); - 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); + phi = proj_data_info_sptr->get_phi(bin); + // s_in_mm = proj_data_info_sptr->get_s(bin); } - else if(proj_data_info_sptr->get_scanner_ptr()->get_scanner_geometry()== "BlocksOnCylindrical") + else { - // can be static_cast later on - const ProjDataInfoBlocksOnCylindricalNoArcCorr& proj_data_info_noarccor = - dynamic_cast(*proj_data_info_sptr); + if (proj_data_info_sptr->get_scanner_ptr()->get_scanner_geometry() == "Cylindrical") + { + // can be static_cast later on + const ProjDataInfoCylindricalNoArcCorr& proj_data_info_noarccor + = dynamic_cast(*proj_data_info_sptr); + // TODO check on 180 degrees for views + 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 + + proj_data_info_noarccor.get_azimuthal_angle_offset()); + 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); + } + else if (proj_data_info_sptr->get_scanner_ptr()->get_scanner_geometry() == "BlocksOnCylindrical") + { + // can be static_cast later on + const ProjDataInfoBlocksOnCylindricalNoArcCorr& proj_data_info_noarccor + = dynamic_cast(*proj_data_info_sptr); - phi = proj_data_info_noarccor.get_phi(bin); - s_in_mm = proj_data_info_noarccor.get_s(bin); - } - else - { - const ProjDataInfoGenericNoArcCorr& proj_data_info_noarccor = - dynamic_cast(*proj_data_info_sptr); + phi = proj_data_info_noarccor.get_phi(bin); + s_in_mm = proj_data_info_noarccor.get_s(bin); + } + else + { + const ProjDataInfoGenericNoArcCorr& proj_data_info_noarccor + = dynamic_cast(*proj_data_info_sptr); - phi = proj_data_info_noarccor.get_phi(bin); - s_in_mm = proj_data_info_noarccor.get_s(bin); + phi = proj_data_info_noarccor.get_phi(bin); + s_in_mm = proj_data_info_noarccor.get_s(bin); + } } - } - const float cphi = cos(phi); const float sphi = sin(phi); - + const float tantheta = proj_data_info_sptr->get_tantheta(bin); - const float costheta = 1/sqrt(1+square(tantheta)); + 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; - + + 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 - if (fabs(sampling_distance_of_adjacent_LORs_z/voxel_size.z() - - num_lors_per_axial_pos) > 1E-3) - error(boost::format("ProjMatrixByBinUsingRayTracing: currently need sampling distance in axial direction (%f) to be an integer multiple of the voxel size (%g)") + if (fabs(sampling_distance_of_adjacent_LORs_z / voxel_size.z() - num_lors_per_axial_pos) > 1E-3) + error(boost::format("ProjMatrixByBinUsingRayTracing: currently need sampling distance in axial direction (%f) to be an " + "integer multiple of the voxel size (%g)") % sampling_distance_of_adjacent_LORs_z % voxel_size.z()); - // find offset in z, taking into account if there are 1 or more LORs // KT 20/06/2001 take origin.z() into account // KT 15/05/2002 move +(max_index.z()+min_index.z())/2.F offset here instead of in formulas for Z1f,Z2f @@ -736,112 +683,108 @@ 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) + 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 + // 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(); + 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 + // 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 - 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()); - if (proj_data_info_sptr->get_scanner_ptr()->get_scanner_geometry() == "BlocksOnCylindrical") - { - fovrad_in_mm = - min((min(max_index.x(), -min_index.x()) - 5.f) * voxel_size.x(), - (min(max_index.y(), -min_index.y()) - 5.f) * voxel_size.y()); - } + 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()); + if (proj_data_info_sptr->get_scanner_ptr()->get_scanner_geometry() == "BlocksOnCylindrical") + { + fovrad_in_mm = min((min(max_index.x(), -min_index.x()) - 5.f) * voxel_size.x(), + (min(max_index.y(), -min_index.y()) - 5.f) * 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, + { + 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); - } + 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_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; - lor.merge(ray_traced_lor); + 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_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; + 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) { @@ -849,166 +792,145 @@ 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); + 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 = ProjMatrixElemsForOneBin::value_type( + Coordinate3D(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); } } - } // if( tantheta!=0 && num_lors_per_axial_pos>1) - } //if (lor.size()!=0) - + } // 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) +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); + 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. // !author Parisa Khateri: modify to take into account voxels before the first LOR in raytracing. - const int num_overlapping_voxels = z_of_first_voxel > 0.5? - round(ceil(right_edge_of_TOR-z_of_first_voxel+.5)) + 1: - round(ceil(right_edge_of_TOR-z_of_first_voxel+.5)); + const int num_overlapping_voxels = z_of_first_voxel > 0.5 ? round(ceil(right_edge_of_TOR - z_of_first_voxel + .5)) + 1 + : 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); + 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 + 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())); + 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); + 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)); + 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 - - // !author Parisa Khateri: modify to take into account voxels before the first LOR in raytracing. - if (z_of_first_voxel > 0.5) + + // !author Parisa Khateri: modify to take into account voxels before the first LOR in raytracing. + if (z_of_first_voxel > 0.5) { - int z_index= -1; + int z_index = -1; const float overlap_of_voxel_with_TOR = z_of_first_voxel - .5F; - assert(num_overlapping_voxels>=z_index); + assert(num_overlapping_voxels >= z_index); 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) + const int new_z = lor.begin()->coord1() + z_index; + if (overlap_of_voxel_with_TOR > .9999) // test if it is 1 { - 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())); + // 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)); + // 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)); + } } - } - - }//Parisa end + + } // Parisa end // 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); + 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); assert(overlap_of_voxel_with_TOR < 1.0001); - if (overlap_of_voxel_with_TOR<.9999) // test if it is 1 + 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; + 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 @@ -1047,7 +969,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()) { @@ -1056,7 +978,7 @@ static void merge_zplus1(ProjMatrixElemsForOneBin& lor) << '\n'; ++iter; } -#endif +# endif float next_value; @@ -1095,4 +1017,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 c5196f2a0..831ba69d4 100644 --- a/src/recon_buildblock/ProjMatrixElemsForOneBin.cxx +++ b/src/recon_buildblock/ProjMatrixElemsForOneBin.cxx @@ -14,15 +14,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" @@ -41,87 +41,88 @@ using std::copy; START_NAMESPACE_STIR - -ProjMatrixElemsForOneBin:: -ProjMatrixElemsForOneBin(const Bin& bin, const int default_capacity) -: bin(bin) +ProjMatrixElemsForOneBin::ProjMatrixElemsForOneBin(const Bin& bin, const int default_capacity) + : bin(bin) { - elements.reserve(default_capacity); + 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) - { - iterator element_ptr = begin(); - while (element_ptr != end()) { - *element_ptr *= d; - ++element_ptr; + iterator element_ptr = begin(); + while (element_ptr != end()) + { + *element_ptr *= d; + ++element_ptr; + } } - } return *this; } -ProjMatrixElemsForOneBin& ProjMatrixElemsForOneBin::operator/=(const float d) +ProjMatrixElemsForOneBin& +ProjMatrixElemsForOneBin::operator/=(const float d) { - assert( d != 0); + assert(d != 0); // KT 21/02/2002 added check on 1 if (d != 1.F) - { - iterator element_ptr = begin(); - while (element_ptr != end()) - { - *element_ptr /= d; - ++element_ptr; - } - } + { + iterator element_ptr = begin(); + 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))) + + for (ProjMatrixElemsForOneBin::const_iterator lor_iter = lor.begin(); lor_iter != lor.end() - 1; ++lor_iter) { - 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 (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()) @@ -132,150 +133,149 @@ Succeeded ProjMatrixElemsForOneBin::check_state() const ++iter; } #endif - success = Succeeded::no; + success = Succeeded::no; + } } - } return success; } - -void ProjMatrixElemsForOneBin::sort() +void +ProjMatrixElemsForOneBin::sort() { std::sort(begin(), end(), value_type::coordinates_less); } - -float ProjMatrixElemsForOneBin::square_sum() const +float +ProjMatrixElemsForOneBin::square_sum() const { - float sq_sum=0; + float sq_sum = 0; const_iterator element_ptr = begin(); while (element_ptr != end()) - { - sq_sum += square(element_ptr->get_value()); - ++element_ptr; - } + { + 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()) - { - elements.reserve((lor2.end() - element_ptr2) + size()); - elements.insert(end(), element_ptr2, lor2.end()); - break; - } - if (value_type::coordinates_equal(*element_ptr2, *element_ptr)) - { - *element_ptr++ += *element_ptr2++; - } - 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 - //++insertions; -#endif - } - else +# ifndef NDEBUG + // unsigned int insertions = 0; +# endif + while (element_ptr2 != lor2.end()) { - ++element_ptr; + if (element_ptr == end()) + { + elements.reserve((lor2.end() - element_ptr2) + size()); + elements.insert(end(), element_ptr2, lor2.end()); + break; + } + if (value_type::coordinates_equal(*element_ptr2, *element_ptr)) + { + *element_ptr++ += *element_ptr2++; + } + 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 + //++insertions; +# 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() ) - { - // 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() ) + bool found = false; + while (element_ptr2 != lor2.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 - } + // 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; + found = true; + break; // assume no more duplicated point + } + else + ++dup_xyz; + } + if (found) + { + element_ptr2 = lor2.erase(element_ptr2); + found = false; + } else - ++dup_xyz; - } - if( found ) - { - element_ptr2 = lor2.erase(element_ptr2); - found = false; + { + ++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; - } + 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 sort(); #endif #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() @@ -329,107 +329,90 @@ 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(); + + 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++; - } - } + { + 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++; + } + } } - -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()) - { - 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; - } - } + { + 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; + } + } } +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); - symm_ptr->transform_proj_matrix_elems_for_one_bin(row_copy); - row_copy.back_project(density,symmetric_bin); - } -} + { + 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); + symm_ptr->transform_proj_matrix_elems_for_one_bin(row_copy); + row_copy.back_project(density, symmetric_bin); + } +} -void -ProjMatrixElemsForOneBin:: -forward_project(RelatedBins& r_bins, - const DiscretisedDensity<3,float>& density) const +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(); + const DataSymmetriesForBins* symmetries = r_bins.get_symmetries_ptr(); + + 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); - symm_op_ptr->transform_proj_matrix_elems_for_one_bin(row_copy); - row_copy.forward_project(*r_bins_iterator,density); - } - -} + { + row_copy = *this; + + 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); + } +} -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 @@ -439,18 +422,18 @@ 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) + 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 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()) + while (this_iter != end() && lor_iter != lor.end()) { if (this_iter->get_coords() == lor_iter->get_coords()) { @@ -460,14 +443,16 @@ operator==(const ProjMatrixElemsForOneBin& lor) const } else { - // coordinates are not equal, so check if value of one of them is small and we should skip it + // 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; + ++this_iter; + continue; } if (lor_iter->get_value() < tolerance) { - ++lor_iter; continue; + ++lor_iter; + continue; } // either one is not small return false; @@ -476,22 +461,22 @@ operator==(const ProjMatrixElemsForOneBin& lor) const ++this_iter; ++lor_iter; } - for (; this_iter!= end(); ++this_iter) + for (; this_iter != end(); ++this_iter) { - if (this_iter->get_value()> tolerance) - return false; + if (this_iter->get_value() > tolerance) + return false; } - for (; lor_iter!= lor.end(); ++lor_iter) + for (; lor_iter != lor.end(); ++lor_iter) { - if (lor_iter->get_value()> tolerance) - return false; + 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 e210da23a..c85a0e89d 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 @@ -29,164 +29,160 @@ START_NAMESPACE_STIR - -ProjMatrixElemsForOneDensel:: -ProjMatrixElemsForOneDensel(const Densel& densel, const int default_capacity) -: densel(densel) +ProjMatrixElemsForOneDensel::ProjMatrixElemsForOneDensel(const Densel& densel, const int default_capacity) + : densel(densel) { - elements.reserve(default_capacity); + elements.reserve(default_capacity); } -ProjMatrixElemsForOneDensel:: -ProjMatrixElemsForOneDensel() +ProjMatrixElemsForOneDensel::ProjMatrixElemsForOneDensel() { - elements.reserve(300); + 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) - { - iterator element_ptr = begin(); - while (element_ptr != end()) { - *element_ptr *= d; - ++element_ptr; - } - } + iterator element_ptr = begin(); + while (element_ptr != end()) + { + *element_ptr *= d; + ++element_ptr; + } + } return *this; } -ProjMatrixElemsForOneDensel& ProjMatrixElemsForOneDensel::operator/=(const float d) +ProjMatrixElemsForOneDensel& +ProjMatrixElemsForOneDensel::operator/=(const float d) { - assert( d != 0); + assert(d != 0); // KT 21/02/2002 added check on 1 if (d != 1.F) - { - iterator element_ptr = begin(); - while (element_ptr != end()) - { - *element_ptr /= d; - ++element_ptr; + { + iterator element_ptr = begin(); + while (element_ptr != end()) + { + *element_ptr /= d; + ++element_ptr; + } } - } 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))) + + for (ProjMatrixElemsForOneDensel::const_iterator lor_iter = lor.begin(); lor_iter != lor.end() - 1; ++lor_iter) { - 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; + 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() { std::sort(begin(), end(), value_type::coordinates_less); } - -float ProjMatrixElemsForOneDensel::square_sum() const +float +ProjMatrixElemsForOneDensel::square_sum() const { - float sq_sum=0; + float sq_sum = 0; const_iterator element_ptr = begin(); while (element_ptr != end()) - { - sq_sum += square(element_ptr->get_bin_value()); - ++element_ptr; - } + { + 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() ) + iterator element_ptr2 = lor2.begin(); + + bool found = false; + while (element_ptr2 != lor2.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; - found = true; - break; // assume no more duplicated point, only 2 lors - } + // 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; + found = true; + break; // assume no more duplicated point, only 2 lors + } + else + ++dup_xyz; + } + if (found) + { + element_ptr2 = lor2.erase(element_ptr2); + found = false; + } else - ++dup_xyz; + { + ++element_ptr2; + } } - if( found ) - { - element_ptr2 = lor2.erase(element_ptr2); - found = false; - } - else{ - ++element_ptr2; - } - } // append the rest - element_ptr2 = lor2.begin(); - while ( element_ptr2 != lor2.end() ) - { - push_back( *element_ptr2); - ++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() @@ -240,7 +236,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 0cb911d83..22d524e74 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 @@ -19,7 +19,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/ProjectorByBinPair.h" #include "stir/ProjDataInfo.h" #include "stir/DiscretisedDensity.h" @@ -30,19 +29,15 @@ 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; @@ -52,30 +47,28 @@ set_up(const shared_ptr& proj_data_info_sptr, } 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%") + 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)) + 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 135d2d948..f7767d5eb 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 @@ -19,7 +19,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" @@ -29,22 +28,17 @@ START_NAMESPACE_STIR +const char* const ProjectorByBinPairUsingProjMatrixByBin::registered_name = "Matrix"; -const char * const -ProjectorByBinPairUsingProjMatrixByBin::registered_name = - "Matrix"; - - -void +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() { @@ -58,30 +52,30 @@ 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; } + { + 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() +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); @@ -92,23 +86,20 @@ 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 +ProjectorByBinPairUsingProjMatrixByBin::get_proj_matrix_sptr() const { - return proj_matrix_sptr; + 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)); diff --git a/src/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.cxx b/src/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.cxx index b00b7e9c6..bd5ce945f 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 @@ -18,7 +18,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/recon_buildblock/ProjectorByBinPairUsingSeparateProjectors.h" #include "stir/is_null_ptr.h" #include "stir/Succeeded.h" @@ -26,25 +25,19 @@ START_NAMESPACE_STIR +const char* const ProjectorByBinPairUsingSeparateProjectors::registered_name = "Separate Projectors"; -const char * const -ProjectorByBinPairUsingSeparateProjectors::registered_name = - "Separate Projectors"; - - -void +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(); @@ -52,33 +45,36 @@ set_defaults() } 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; } + { + 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; } + { + warning("No valid back projector is defined\n"); + return true; + } return false; } -ProjectorByBinPairUsingSeparateProjectors:: -ProjectorByBinPairUsingSeparateProjectors() +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 de20cea32..1b2e7aead 100644 --- a/src/recon_buildblock/QuadraticPrior.cxx +++ b/src/recon_buildblock/QuadraticPrior.cxx @@ -11,8 +11,8 @@ /*! \file \ingroup priors - \brief implementation of the stir::QuadraticPrior class - + \brief implementation of the stir::QuadraticPrior class + \author Kris Thielemans \author Sanida Mustafovic @@ -38,12 +38,12 @@ using std::max; START_NAMESPACE_STIR template -void +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); @@ -51,17 +51,17 @@ QuadraticPrior::initialise_keymap() } template -bool +bool QuadraticPrior::post_processing() { - if (base_type::post_processing()==true) + 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 } @@ -74,24 +74,24 @@ QuadraticPrior::post_processing() } 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); } } @@ -101,12 +101,11 @@ QuadraticPrior::post_processing() 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); @@ -114,7 +113,8 @@ QuadraticPrior::set_up (shared_ptr > co } 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); @@ -126,14 +126,12 @@ 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() @@ -141,59 +139,60 @@ QuadraticPrior::QuadraticPrior() set_defaults(); } - template QuadraticPrior::QuadraticPrior(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; } template bool -QuadraticPrior:: -is_convex() const +QuadraticPrior::is_convex() const { return true; } - //! 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) @@ -205,233 +204,220 @@ compute_weights(Array<3,float>& weights, const CartesianCoordinate3D& gri 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) + 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) + 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())); + 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) +QuadraticPrior::compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate) { - if (this->penalisation_factor==0) - { - return 0.; - } - + 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) - { - compute_weights(this->weights, current_image_cast.get_grid_spacing(), this->only_2D); - } - + + 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_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_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(); + 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); - } - } - } + 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) +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; - } + 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) - { - compute_weights(this->weights, current_image_cast.get_grid_spacing(), this->only_2D); - } - - - + + 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_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 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_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; - } -#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 + 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) - sum_of_weights += weights[dz][dy][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; } - } - // 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 +#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) - gradient *= (*kappa_ptr)[z][y][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) + 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; - } - } + 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) + if (gradient_filename_prefix.size() > 0) { - char *filename = new char[gradient_filename_prefix.size()+100]; + 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; @@ -440,154 +426,151 @@ compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, 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) const +QuadraticPrior::compute_Hessian(DiscretisedDensity<3, elemT>& prior_Hessian_for_single_densel, + const BasicCoordinate<3, int>& coords, + const DiscretisedDensity<3, elemT>& current_image_estimate) const { - assert( prior_Hessian_for_single_densel.has_same_characteristics(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) - { - return; - } - + 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) - { - compute_weights(weights, current_image_cast.get_grid_spacing(), this->only_2D); - } - - + + 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) - { - elemT current = 0.0; - if (dz == 0 && dy == 0 && dx == 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) { - // The j == k case (diagonal Hessian element), which is a sum over the neighbourhood. - for (int ddz=min_dz;ddz<=max_dz;++ddz) - for (int ddy=min_dy;ddy<=max_dy;++ddy) - for (int ddx=min_dx;ddx<=max_dx;++ddx) - { - elemT diagonal_current = weights[ddz][ddy][ddx] * - derivative_20(current_image_estimate[z][y][x], - current_image_estimate[z + ddz][y + ddy][x + ddx]); - if (do_kappa) - diagonal_current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+ddz][y+ddy][x+ddx]; - current += diagonal_current; - } - } - else - { - // The j != k vases (off-diagonal Hessian elements) - current = weights[dz][dy][dx] * derivative_11(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]; + elemT current = 0.0; + if (dz == 0 && dy == 0 && dx == 0) + { + // The j == k case (diagonal Hessian element), which is a sum over the neighbourhood. + for (int ddz = min_dz; ddz <= max_dz; ++ddz) + for (int ddy = min_dy; ddy <= max_dy; ++ddy) + for (int ddx = min_dx; ddx <= max_dx; ++ddx) + { + elemT diagonal_current + = weights[ddz][ddy][ddx] + * derivative_20(current_image_estimate[z][y][x], current_image_estimate[z + ddz][y + ddy][x + ddx]); + if (do_kappa) + diagonal_current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + ddz][y + ddy][x + ddx]; + current += diagonal_current; + } + } + else + { + // The j != k vases (off-diagonal Hessian elements) + current = weights[dz][dy][dx] + * derivative_11(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]; + } + 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; - } -} +} template -void -QuadraticPrior::parabolic_surrogate_curvature(DiscretisedDensity<3,elemT>& parabolic_surrogate_curvature, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) +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; - } - + 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) - { - compute_weights(weights, current_image_cast.get_grid_spacing(), this->only_2D); - } - + + 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; @@ -599,28 +582,26 @@ QuadraticPrior::parabolic_surrogate_curvature(DiscretisedDensity<3,elemT> template void -QuadraticPrior:: -add_multiplication_with_approximate_Hessian(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& input) const +QuadraticPrior::add_multiplication_with_approximate_Hessian(DiscretisedDensity<3, elemT>& output, + 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) - { - return; - } + assert(output.has_same_characteristics(input)); + if (this->penalisation_factor == 0) + { + return; + } this->check(input); - DiscretisedDensityOnCartesianGrid<3,elemT>& output_cast = - dynamic_cast &>(output); + DiscretisedDensityOnCartesianGrid<3, elemT>& output_cast = dynamic_cast&>(output); - if (weights.get_length() ==0) - { - compute_weights(weights, output_cast.get_grid_spacing(), this->only_2D); - } + 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); @@ -629,42 +610,40 @@ add_multiplication_with_approximate_Hessian(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++) + 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_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++) + 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_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++) + 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_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; } } } @@ -672,58 +651,56 @@ add_multiplication_with_approximate_Hessian(DiscretisedDensity<3,elemT>& output, template void -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) - { - return; - } + assert(output.has_same_characteristics(input)); + if (this->penalisation_factor == 0) + { + return; + } this->check(input); - - DiscretisedDensityOnCartesianGrid<3,elemT>& output_cast = - dynamic_cast &>(output); - - if (weights.get_length() ==0) - { - compute_weights(weights, output_cast.get_grid_spacing(), this->only_2D); - } - + + 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); - + 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); + /// At this point, we have j = [z][y][x] // The next for loops will have k = [z+dz][y+dy][x+dx] // The following computes @@ -732,58 +709,59 @@ accumulate_Hessian_times_input(DiscretisedDensity<3,elemT>& output, // \sum_{(i \in N_j) \ne j} w_{(j,i)} f''_{od}(x_j, x_i) y_i // Note the condition in the second sum that i is not equal to j - 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]; - if (current == elemT(0)) - continue; - if (dz == 0 && dy == 0 && dx == 0) { + 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]; + if (current == elemT(0)) + continue; + if (dz == 0 && dy == 0 && dx == 0) + { // The j == k case - current *= derivative_20(current_estimate[z][y][x], - current_estimate[z + dz][y + dy][x + dx]) * input[z][y][x]; - } else { - current *= (derivative_20(current_estimate[z][y][x], - current_estimate[z + dz][y + dy][x + dx]) * input[z][y][x] + - derivative_11(current_estimate[z][y][x], - current_estimate[z + dz][y + dy][x + dx]) * - input[z + dz][y + dy][x + dx]); + current *= derivative_20(current_estimate[z][y][x], current_estimate[z + dz][y + dy][x + dx]) + * input[z][y][x]; + } + else + { + current *= (derivative_20(current_estimate[z][y][x], current_estimate[z + dz][y + dy][x + dx]) + * input[z][y][x] + + derivative_11(current_estimate[z][y][x], current_estimate[z + dz][y + dy][x + 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; - } + 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; + } } } } template elemT -QuadraticPrior:: -derivative_20(const elemT x_j, const elemT x_k) const -{ return 1.0;} +QuadraticPrior::derivative_20(const elemT x_j, const elemT x_k) const +{ + return 1.0; +} template elemT -QuadraticPrior:: -derivative_11(const elemT x_j, const elemT x_k) const -{ return -1.0;} +QuadraticPrior::derivative_11(const elemT x_j, const elemT x_k) const +{ + return -1.0; +} -# 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 4a6e6bed0..735a7582f 100644 --- a/src/recon_buildblock/RayTraceVoxelsOnCartesianGrid.cxx +++ b/src/recon_buildblock/RayTraceVoxelsOnCartesianGrid.cxx @@ -13,7 +13,7 @@ \file \ingroup recon_buildblock - \brief Implementation of RayTraceVoxelsOnCartesianGrid + \brief Implementation of RayTraceVoxelsOnCartesianGrid \author Kris Thielemans \author Mustapha Sadki @@ -22,7 +22,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 @@ -45,22 +45,20 @@ START_NAMESPACE_STIR static inline bool is_half_integer(const float a) { - return - fabs(floor(a)+.5F - a)<.0001F; + 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) +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; + const CartesianCoordinate3D difference = stop_point - start_point; - if (norm(difference)<=.00001F) + if (norm(difference) <= .00001F) { // TODO // not sure how to handle this case as we're normally ray tracing from voxel edges @@ -72,20 +70,17 @@ RayTraceVoxelsOnCartesianGrid // 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; + const int unsigned lor_size + = 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 @@ -95,51 +90,43 @@ 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); + inc = CartesianCoordinate3D(.5F, 0, 0); } else if (zero_diff_in_y && is_half_integer(start_point.y())) { - inc = CartesianCoordinate3D (0,.5F,0); + inc = CartesianCoordinate3D(0, .5F, 0); } else if (zero_diff_in_x && is_half_integer(start_point.x())) { - inc = CartesianCoordinate3D (0,0,.5F); + inc = CartesianCoordinate3D(0, 0, .5F); } - if (norm(inc)>.1) + 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; + 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; } } @@ -150,17 +137,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. @@ -169,26 +156,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: @@ -202,9 +189,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_? @@ -214,56 +201,70 @@ 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; - } - } // end of while (a 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; + } + } // end of while (a::Reconstruction() this->set_defaults(); } - // parameters template -void +void Reconstruction::set_defaults() { - this->_already_set_up=false; - this->output_filename_prefix=""; - this->output_file_format_ptr = - OutputFileFormat::default_sptr(); + 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 +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 +void Reconstruction::initialise(const std::string& parameter_filename) { _already_set_up = false; - if(parameter_filename.size()==0) - { - this->set_defaults(); - this->ask_parameters(); - } - -else - { - this->set_defaults(); - if(!this->parse(parameter_filename.c_str())) + if (parameter_filename.size() == 0) { - error("Error parsing input file %s, exiting", parameter_filename.c_str()); + 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()); + } + } } - 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"); } + { + 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; } + { + 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) +Reconstruction::set_output_filename_prefix(const std::string& arg) { - this->output_filename_prefix = arg; + this->output_filename_prefix = arg; } template void -Reconstruction:: -set_output_file_format_ptr(const shared_ptr >& arg) +Reconstruction::set_output_file_format_ptr(const shared_ptr>& arg) { - this->output_file_format_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)) - { - 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 (!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; + } + } 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) +Reconstruction::set_disable_output(bool _val) { - this->_disable_output = _val; + this->_disable_output = _val; } -template < typename TargetT> -shared_ptr -Reconstruction:: -get_target_image() +template +shared_ptr +Reconstruction::get_target_image() { - return target_data_sptr; + 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/RelativeDifferencePrior.cxx b/src/recon_buildblock/RelativeDifferencePrior.cxx index fd033de45..d407f1d72 100644 --- a/src/recon_buildblock/RelativeDifferencePrior.cxx +++ b/src/recon_buildblock/RelativeDifferencePrior.cxx @@ -13,7 +13,7 @@ \file \ingroup priors \brief implementation of the stir::RelativeDifferencePrior class - + \author Kris Thielemans \author Sanida Mustafovic \author Robert Twyman @@ -40,12 +40,12 @@ using std::max; START_NAMESPACE_STIR template -void +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); @@ -55,17 +55,17 @@ RelativeDifferencePrior::initialise_keymap() } template -bool +bool RelativeDifferencePrior::post_processing() { - if (base_type::post_processing()==true) + 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 } @@ -78,24 +78,24 @@ RelativeDifferencePrior::post_processing() } 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); } } @@ -105,12 +105,11 @@ RelativeDifferencePrior::post_processing() 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); @@ -118,7 +117,8 @@ RelativeDifferencePrior::set_up (shared_ptr > } 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); @@ -129,18 +129,16 @@ void RelativeDifferencePrior::set_defaults() { base_type::set_defaults(); -// this->_is_convex = true; + // this->_is_convex = true; 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() @@ -150,8 +148,7 @@ RelativeDifferencePrior::RelativeDifferencePrior() template bool -RelativeDifferencePrior:: -is_convex() const +RelativeDifferencePrior::is_convex() const { return true; } @@ -159,35 +156,41 @@ is_convex() const // 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) { set_defaults(); this->penalisation_factor = penalisation_factor_v; @@ -195,44 +198,46 @@ RelativeDifferencePrior::RelativeDifferencePrior(const bool only_2D_v, fl 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) @@ -244,188 +249,197 @@ compute_weights(Array<3,float>& weights, const CartesianCoordinate3D& gri 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) + 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) + 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())); + 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) +RelativeDifferencePrior::compute_value(const DiscretisedDensity<3, elemT>& current_image_estimate) { - if (this->penalisation_factor==0) - { - return 0.; - } - + 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) - { - compute_weights(this->weights, current_image_cast.get_grid_spacing(), this->only_2D); - } - + + 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_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_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){ + 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); - } - } - } + 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) +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; - } + 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) - { - compute_weights(this->weights, current_image_cast.get_grid_spacing(), this->only_2D); - } - - + + 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); + 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(); - 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 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); - 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){ + 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]; + 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; - } + gradient += current; + } - prior_gradient[z][y][x]= gradient * this->penalisation_factor; - } - } + 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) + if (gradient_filename_prefix.size() > 0) { - char *filename = new char[gradient_filename_prefix.size()+100]; + 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; @@ -434,31 +448,29 @@ compute_gradient(DiscretisedDensity<3,elemT>& prior_gradient, template void -RelativeDifferencePrior:: -compute_Hessian(DiscretisedDensity<3,elemT>& prior_Hessian_for_single_densel, - const BasicCoordinate<3,int>& coords, - const DiscretisedDensity<3,elemT> ¤t_image_estimate) const +RelativeDifferencePrior::compute_Hessian(DiscretisedDensity<3, elemT>& prior_Hessian_for_single_densel, + const BasicCoordinate<3, int>& coords, + const DiscretisedDensity<3, elemT>& current_image_estimate) const { - assert( prior_Hessian_for_single_densel.has_same_characteristics(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) - { - return; - } + 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); + 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); - } + 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); @@ -468,80 +480,77 @@ 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) - { - elemT current = 0.0; - if (dz == 0 && dy == 0 && dx == 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) { - // The j == k case (diagonal Hessian element), which is a sum over the neighbourhood. - for (int ddz=min_dz;ddz<=max_dz;++ddz) - for (int ddy=min_dy;ddy<=max_dy;++ddy) - for (int ddx=min_dx;ddx<=max_dx;++ddx) - { - elemT diagonal_current = weights[ddz][ddy][ddx] * - derivative_20(current_image_estimate[z][y][x], - current_image_estimate[z + ddz][y + ddy][x + ddx]); - if (do_kappa) - diagonal_current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z+ddz][y+ddy][x+ddx]; - current += diagonal_current; - } - } - else - { - // The j != k cases (off-diagonal Hessian elements), no summing over neighbourhood - current = weights[dz][dy][dx] * derivative_11(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]; + elemT current = 0.0; + if (dz == 0 && dy == 0 && dx == 0) + { + // The j == k case (diagonal Hessian element), which is a sum over the neighbourhood. + for (int ddz = min_dz; ddz <= max_dz; ++ddz) + for (int ddy = min_dy; ddy <= max_dy; ++ddy) + for (int ddx = min_dx; ddx <= max_dx; ++ddx) + { + elemT diagonal_current + = weights[ddz][ddy][ddx] + * derivative_20(current_image_estimate[z][y][x], current_image_estimate[z + ddz][y + ddy][x + ddx]); + if (do_kappa) + diagonal_current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + ddz][y + ddy][x + ddx]; + current += diagonal_current; + } + } + else + { + // The j != k cases (off-diagonal Hessian elements), no summing over neighbourhood + current = weights[dz][dy][dx] + * derivative_11(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]; + } + 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; - } } template void -RelativeDifferencePrior:: -add_multiplication_with_approximate_Hessian(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& input) const +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."); + error("add_multiplication_with_approximate_Hessian() is not implemented in Relative Difference Prior."); } template void -RelativeDifferencePrior:: -accumulate_Hessian_times_input(DiscretisedDensity<3,elemT>& output, - const DiscretisedDensity<3,elemT>& current_estimate, - const DiscretisedDensity<3,elemT>& input) const +RelativeDifferencePrior::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) - { - return; - } + assert(output.has_same_characteristics(input)); + if (this->penalisation_factor == 0) + { + return; + } - DiscretisedDensityOnCartesianGrid<3,elemT>& output_cast = - dynamic_cast &>(output); + DiscretisedDensityOnCartesianGrid<3, elemT>& output_cast = dynamic_cast&>(output); - if (weights.get_length() ==0) - { - compute_weights(weights, output_cast.get_grid_spacing(), this->only_2D); - } + 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); @@ -550,99 +559,96 @@ 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(); + 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); - - /// At this point, we have j = [z][y][x] - // The next for loops will have k = [z+dz][y+dy][x+dx] - // The following computes - //(H_{wf} y)_j = - // \sum_{k\in N_j} w_{(j,k)} f''_{d}(x_j,x_k) y_j + - // \sum_{(i \in N_j) \ne j} w_{(j,i)} f''_{od}(x_j, x_i) y_i - // Note the condition in the second sum that i is not equal to j - - 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) + 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++) { - elemT current = weights[dz][dy][dx]; - if (current == elemT(0)) - continue; - if ((dz == 0) && (dy == 0) && (dx == 0)) { - // The j == k case - current *= derivative_20(current_estimate[z][y][x], - current_estimate[z + dz][y + dy][x + dx]) * input[z][y][x]; - } else { - current *= (derivative_20(current_estimate[z][y][x], - current_estimate[z + dz][y + dy][x + dx]) * input[z][y][x] + - derivative_11(current_estimate[z][y][x], - current_estimate[z + dz][y + dy][x + dx]) * - input[z + dz][y + dy][x + dx]); - } + 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); + + /// At this point, we have j = [z][y][x] + // The next for loops will have k = [z+dz][y+dy][x+dx] + // The following computes + //(H_{wf} y)_j = + // \sum_{k\in N_j} w_{(j,k)} f''_{d}(x_j,x_k) y_j + + // \sum_{(i \in N_j) \ne j} w_{(j,i)} f''_{od}(x_j, x_i) y_i + // Note the condition in the second sum that i is not equal to j + + 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]; + if (current == elemT(0)) + continue; + if ((dz == 0) && (dy == 0) && (dx == 0)) + { + // The j == k case + current *= derivative_20(current_estimate[z][y][x], current_estimate[z + dz][y + dy][x + dx]) + * input[z][y][x]; + } + else + { + current *= (derivative_20(current_estimate[z][y][x], current_estimate[z + dz][y + dy][x + dx]) + * input[z][y][x] + + derivative_11(current_estimate[z][y][x], current_estimate[z + dz][y + dy][x + 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]; + if (do_kappa) + current *= (*kappa_ptr)[z][y][x] * (*kappa_ptr)[z + dz][y + dy][x + dx]; - result += current; - } + result += current; + } - output[z][y][x] += result * this->penalisation_factor; - } + output[z][y][x] += result * this->penalisation_factor; + } + } } - } } template elemT -RelativeDifferencePrior:: -derivative_20(const elemT x_j, const elemT x_k) const +RelativeDifferencePrior::derivative_20(const elemT x_j, const elemT x_k) const { if (x_j > 0.0 || x_k > 0.0 || this->epsilon > 0.0) - return 2 * pow(2 * x_k + this->epsilon, 2) / - pow(x_j + x_k + this->gamma * abs(x_j - x_k) + this->epsilon, 3); + return 2 * pow(2 * x_k + this->epsilon, 2) / pow(x_j + x_k + this->gamma * abs(x_j - x_k) + this->epsilon, 3); else return 0.0; } template elemT -RelativeDifferencePrior:: -derivative_11(const elemT x_j, const elemT x_k) const +RelativeDifferencePrior::derivative_11(const elemT x_j, const elemT x_k) const { if (x_j > 0.0 || x_k > 0.0 || this->epsilon > 0.0) - return - 2 * (2 * x_j + this->epsilon)*(2 * x_k + this->epsilon) / - pow(x_j + x_k + this->gamma * abs(x_j - x_k) + this->epsilon, 3); + return -2 * (2 * x_j + this->epsilon) * (2 * x_k + this->epsilon) + / pow(x_j + x_k + this->gamma * abs(x_j - x_k) + this->epsilon, 3); else return 0.0; } -# 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 e71a9f0e7..aab99b6e5 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. @@ -10,7 +10,7 @@ \author Carles Falcon */ -//system libraries +// system libraries #include #include #include @@ -28,448 +28,503 @@ using namespace std; #include "stir/recon_buildblock/SPECTUB_Tools.h" #include "stir/recon_buildblock/SPECTUB_Weight3d.h" +namespace SPECTUB +{ -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 //============================================================================= //=== write_wm_FC ============================================================= //============================================================================= -void write_wm_FC(SPECTUB::wm_da_type& wm) +void +write_wm_FC(SPECTUB::wm_da_type& wm) { - 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]; + 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) .............. + + 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); + } + } - fclose (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(SPECTUB::wm_da_type& wm, SPECTUB::wmh_type& wmh) +void +write_wm_hdr(SPECTUB::wm_da_type& wm, SPECTUB::wmh_type& wmh) { - 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 ................. + ofstream stream1(wm.fn_hdr.c_str()); + if (!stream1) + error_wmtools_SPECT(31, wm.fn_hdr); - - 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(); + //....... 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 << "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(wm_da_type &wm) +void +write_wm_STIR(wm_da_type& wm) { - 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 ); + 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 , SPECTUB::wmh_type& wmh) +void +index_calc(int* indexs, SPECTUB::wmh_type& wmh) { - 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; - } - + 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(float * Rrad, SPECTUB::wmh_type& wmh) +void +read_Rrad(float* Rrad, SPECTUB::wmh_type& wmh) { - 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; + 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)); // } -//} +// } ///============================================================================= //=== 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; @@ -477,425 +532,489 @@ void read_Rrad(float * Rrad, SPECTUB::wmh_type& wmh) // } // // 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, SPECTUB::wmh_type& wmh) +float +calc_sigma_v(voxel_type vox, collim_type COL, SPECTUB::wmh_type& wmh) { - 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 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, SPECTUB::wmh_type& wmh,const float * Rrad) +void +fill_ang(angle_type* ang, SPECTUB::wmh_type& wmh, const float* Rrad) { - 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 ; - } - } + 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,SPECTUB::wmh_type& wmh ) +void +generate_msk(bool* msk_3d, bool* msk_2d, float* attmap, volume_type* vol, SPECTUB::wmh_type& wmh) { - //... 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, wmh); - } - } + //... 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, wmh); + } + } + + //... 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, SPECTUB::wmh_type& wmh ) +void +read_msk_file(bool* msk, SPECTUB::wmh_type& wmh) { - 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; + 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,SPECTUB::wmh_type& wmh ) +void +read_att_map(float* attmap, SPECTUB::wmh_type& wmh) { - 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); + 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, SPECTUB::wmh_type& wmh) -{ - 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, wmh ); - 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, SPECTUB::wmh_type& wmh) +{ + 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; + } - return( maxszb ); + 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, wmh); + 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 +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 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) +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 ) +void +free_wm(wm_type* f) { - delete [] f->ar; - delete [] f->ja; - delete [] f->ia; + delete[] f->ar; + delete[] f->ja; + delete[] f->ia; } //============================================================================= //=== free_wm_da ============================================================== //============================================================================= -void free_wm_da( wm_da_type *f ) +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; - } + 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){ @@ -921,28 +1040,55 @@ 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; - - //... 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()"); - } - + 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()"); + } + #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 c254004a5..c2aff7325 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. @@ -11,8 +11,7 @@ \author Carles Falcon */ - -//user defined libraries +// user defined libraries #include "stir/recon_buildblock/SPECTUB_Tools.h" #include "stir/recon_buildblock/SPECTUB_Weight3d.h" @@ -21,946 +20,1066 @@ #include #include "stir/spatial_transformation/InvertAxis.h" -//system libraries +// system libraries #include #include #include #include #include -namespace SPECTUB { +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, wm_da_type &wm, wmh_type &wmh, const float *Rrad) +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, + wm_da_type& wm, + wmh_type& wmh, + const float* Rrad) { - - 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; - } - } - - //... 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, wmh ); - - //... 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, wmh); - - else{ - - if ( wmh.do_psf_3d ) fill_psf_3d ( &psf, &psf1d_h, &psf1d_v, vox, gaussdens, bin.szdx, bin.thdx, bin.thcmd2, wmh ); - - else fill_psf_2d ( &psf, &psf1d_h, vox, gaussdens, bin.szdx, wmh); - } - - //... 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, wmh); - - //... 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, wmh ); - - 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 ; - } + float weight; + float coeff_att = (float)1.; + int jp; + float eff; - 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; - } -} + //... 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; + } + } + + //... 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, wmh); + + //... 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, wmh); + + else + { + + if (wmh.do_psf_3d) + fill_psf_3d(&psf, &psf1d_h, &psf1d_v, vox, gaussdens, bin.szdx, bin.thdx, bin.thcmd2, wmh); + + else + fill_psf_2d(&psf, &psf1d_h, vox, gaussdens, bin.szdx, wmh); + } + + //... 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, wmh); + + //... 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, wmh); + + 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, - wmh_type& wmh, - const float * Rrad) +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, + wmh_type& wmh, + const float* Rrad) { - 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, wmh); - - //... 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, wmh); - - else{ - - if ( wmh.do_psf_3d ) fill_psf_3d ( &psf, &psf1d_h, &psf1d_v, vox, gaussdens, bin.szdx, bin.thdx, bin.thcmd2, wmh ); - - else fill_psf_2d ( &psf, &psf1d_h, vox, gaussdens, bin.szdx, wmh); - } - - - //=== 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; -} + 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, wmh); + + //... 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, wmh); + + else + { + + if (wmh.do_psf_3d) + fill_psf_3d(&psf, &psf1d_h, &psf1d_v, vox, gaussdens, bin.szdx, bin.thdx, bin.thcmd2, wmh); + + else + fill_psf_2d(&psf, &psf1d_h, vox, gaussdens, bin.szdx, wmh); + } + + //=== 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 ) +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 ]; - } + 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 ) +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 ]; - } -} + //... 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, wmh_type &wmh) +void +voxel_projection(voxel_type* vox, float* eff, float lngcmd2, wmh_type& wmh) { - - 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. ; - } + + 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, - wmh_type &wmh) +void +fill_psf_no(psf2da_type* psf, psf1d_type* psf1d_h, const voxel_type& vox, angle_type const* const ang, float szdx, wmh_type& wmh) { - psf1d_h->sgmcm = vox.szcm; + 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, wmh); - - 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, wmh); + + 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,wmh_type &wmh ) +void +fill_psf_2d( + psf2da_type* psf, psf1d_type* psf1d_h, const voxel_type& vox, discrf_type const* const gaussdens, float szdx, wmh_type& wmh) { - - 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, wmh); - - 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; + + 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, wmh); + + 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, - SPECTUB::wmh_type &wmh) +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, + SPECTUB::wmh_type& wmh) { - - //... horizontal component ........................... - 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, wmh); + //... horizontal component ........................... - //... vertical component .............................. - - psf1d_v->sgmcm = calc_sigma_v( vox, wmh.COL, wmh); - 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, wmh); - - //... 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, wmh); + + //... vertical component .............................. + + psf1d_v->sgmcm = calc_sigma_v(vox, wmh.COL, wmh); + 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, wmh); + + //... 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, - SPECTUB::wmh_type &wmh) +void +calc_psf_bin(float center_psf, float binszcm, discrf_type const* const vxprj, psf1d_type* psf, SPECTUB::wmh_type& wmh) { - float weight, preval; + 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 ) +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++; - } - } + 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 +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 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, - wmh_type& wmh){ - - 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, wmh_type& wmh) +{ + + 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){ @@ -978,24 +1097,42 @@ 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 fd1b1782d..6cf8fb9f1 100644 --- a/src/recon_buildblock/SqrtHessianRowSum.cxx +++ b/src/recon_buildblock/SqrtHessianRowSum.cxx @@ -27,19 +27,16 @@ #include "stir/unique_ptr.h" #include "stir/Verbosity.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()); @@ -47,8 +44,7 @@ SqrtHessianRowSum(const std::string& filename) template void -SqrtHessianRowSum:: -set_defaults() +SqrtHessianRowSum::set_defaults() { output_file_format_sptr = OutputFileFormat::default_sptr(); output_filename = ""; @@ -79,10 +75,10 @@ SqrtHessianRowSum::post_processing() { if (input_image_filename.empty()) - { - error("Please define input_image_filename."); - return true; - } + { + error("Please define input_image_filename."); + return true; + } input_image_sptr = read_from_file(input_image_filename); if (_verbosity >= 0) @@ -92,35 +88,31 @@ SqrtHessianRowSum::post_processing() } template -GeneralisedObjectiveFunction const& -SqrtHessianRowSum:: -get_objective_function_sptr() +GeneralisedObjectiveFunction const& +SqrtHessianRowSum::get_objective_function_sptr() { - return static_cast&> (*objective_function_sptr); + return static_cast&>(*objective_function_sptr); } template void -SqrtHessianRowSum:: -set_objective_function_sptr(const shared_ptr >& obj_fun) +SqrtHessianRowSum::set_objective_function_sptr(const shared_ptr>& obj_fun) { - this->objective_function_sptr = 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); @@ -128,60 +120,54 @@ set_input_image_sptr(shared_ptr const& 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() +SqrtHessianRowSum::set_up() { if (is_null_ptr(this->objective_function_sptr)) - { - error("objective_function_sptr is null"); - } + { + error("objective_function_sptr is null"); + } if (is_null_ptr(this->input_image_sptr)) - { - error("input_image_sptr is null"); - } + { + 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,26 +175,24 @@ set_up() template void -SqrtHessianRowSum:: -process_data() +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(); - } + { + // 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 - { - // 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(); - } + { + // 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 negative output of the Hessian_row_sum methods // (approximate) Hessian times a non-negative vector will result in a negative output. Flip the sign before sqrt. - 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()) @@ -220,8 +204,7 @@ process_data() template void -SqrtHessianRowSum:: -compute_Hessian_row_sum() +SqrtHessianRowSum::compute_Hessian_row_sum() { if (!_already_setup) error("set_up() needs to be called first"); @@ -233,18 +216,18 @@ 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 @@ -255,11 +238,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 0feac799e..02073512e 100644 --- a/src/recon_buildblock/SymmetryOperation.cxx +++ b/src/recon_buildblock/SymmetryOperation.cxx @@ -26,44 +26,38 @@ 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()) - { - Coordinate3D c(element_ptr->get_coords()); - transform_image_coordinates(c); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } - -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()) - { - Bin c(*element_ptr); - transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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 7825a6883..4526bb65e 100644 --- a/src/recon_buildblock/SymmetryOperations_PET_CartesianGrid.cxx +++ b/src/recon_buildblock/SymmetryOperations_PET_CartesianGrid.cxx @@ -32,648 +32,563 @@ #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()) - { - // 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); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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); + *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); + ++element_ptr; + } } - -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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()) - { - Coordinate3D c(element_ptr->get_coords()); - self::transform_image_coordinates(c); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } - -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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()) - { - Coordinate3D c(element_ptr->get_coords()); - self::transform_image_coordinates(c); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } - -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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()) - { - Coordinate3D c(element_ptr->get_coords()); - self::transform_image_coordinates(c); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } - -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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()) - { - Coordinate3D c(element_ptr->get_coords()); - self::transform_image_coordinates(c); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } - -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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()) - { - Coordinate3D c(element_ptr->get_coords()); - self::transform_image_coordinates(c); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } - -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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()) - { - Coordinate3D c(element_ptr->get_coords()); - self::transform_image_coordinates(c); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } - -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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()) - { - Coordinate3D c(element_ptr->get_coords()); - self::transform_image_coordinates(c); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } - -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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 { Bin bin = lor.get_bin(); transform_bin_coordinates(bin); lor.set_bin(bin); ProjMatrixElemsForOneBin::iterator element_ptr = lor.begin(); - 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()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } - -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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()) - { - Coordinate3D c(element_ptr->get_coords()); - self::transform_image_coordinates(c); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } - -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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()) - { - Coordinate3D c(element_ptr->get_coords()); - self::transform_image_coordinates(c); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } - -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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()) - { - Coordinate3D c(element_ptr->get_coords()); - self::transform_image_coordinates(c); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } - -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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()) - { - Coordinate3D c(element_ptr->get_coords()); - self::transform_image_coordinates(c); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } - -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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()) - { - Coordinate3D c(element_ptr->get_coords()); - self::transform_image_coordinates(c); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } - -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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()) - { - Coordinate3D c(element_ptr->get_coords()); - self::transform_image_coordinates(c); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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()) - { - Coordinate3D c(element_ptr->get_coords()); - self::transform_image_coordinates(c); - *element_ptr = ProjMatrixElemsForOneBin::value_type(c, element_ptr->get_value()); - ++element_ptr; - } + 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()); + ++element_ptr; + } } - - -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()) - { - Bin c(*element_ptr); - self::transform_bin_coordinates(c); - *element_ptr = ProjMatrixElemsForOneDensel::value_type(c); - ++element_ptr; - } -} + ProjMatrixElemsForOneDensel::iterator element_ptr = probs.begin(); + 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 8eff26beb..6dd1eb865 100644 --- a/src/recon_buildblock/TrivialBinNormalisation.cxx +++ b/src/recon_buildblock/TrivialBinNormalisation.cxx @@ -21,8 +21,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 1d7685cde..c351876c5 100644 --- a/src/recon_buildblock/TrivialDataSymmetriesForBins.cxx +++ b/src/recon_buildblock/TrivialDataSymmetriesForBins.cxx @@ -11,7 +11,7 @@ /*! \file \ingroup symmetries - \brief non-inline implementations for class + \brief non-inline implementations for class stir::TrivialDataSymmetriesForBins \author Kris Thielemans @@ -24,22 +24,16 @@ 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); } @@ -50,35 +44,31 @@ 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 +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) + 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()); + axtan_pos_nums[0] = AxTangPosNumbers(b.axial_pos_num(), b.tangential_pos_num()); } else { @@ -87,18 +77,18 @@ get_related_bins_factorised(vector& axtan_pos_nums, const Bin& } 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 int min_timing_pos_num, const int max_timing_pos_num) const +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) + 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; @@ -110,45 +100,39 @@ get_related_bins(vector& rel_b, const Bin& b, } 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 5dfa6ed08..d422a0723 100644 --- a/src/recon_buildblock/distributable.cxx +++ b/src/recon_buildblock/distributable.cxx @@ -17,8 +17,8 @@ \brief Implementation of stir::distributable_computation() and related functions \author Nikos Efthimiou - \author Kris Thielemans - \author Alexey Zverovich + \author Kris Thielemans + \author Alexey Zverovich \author Matthew Jacobson \author PARAPET project \author Tobias Beisel @@ -26,7 +26,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 @@ -59,87 +59,87 @@ #include "stir/Bin.h" #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) + 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 + // broadcast end of processing notification distributed::send_int_value(task_stop_processing, -1); } #endif - } template @@ -150,8 +150,7 @@ zero_end_sinograms(ViewgramsPtr 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(); + 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); @@ -160,54 +159,52 @@ zero_end_sinograms(ViewgramsPtr viewgrams_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 - ) +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 - additive_binwise_correction_viewgrams.reset( - new RelatedViewgrams - (binwise_correction->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); + additive_binwise_correction_viewgrams.reset(new RelatedViewgrams( + binwise_correction->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); } - + if (read_from_proj_dat) { #ifdef STIR_OPENMP -#pragma omp critical(VIEW) +# pragma omp critical(VIEW) #endif - y.reset(new RelatedViewgrams - (proj_dat_ptr->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); + y.reset(new RelatedViewgrams( + proj_dat_ptr->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); } else { - y.reset(new RelatedViewgrams - (proj_dat_ptr->get_empty_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); + 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, false, timing_pos_num))); + 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); } @@ -215,11 +212,11 @@ void get_viewgrams(shared_ptr >& y, { // No normalisation provided but zero_seg0_end_planes, create a mult_viewgrams mult_viewgrams_sptr.reset( - new RelatedViewgrams(proj_dat_ptr->get_empty_related_viewgrams(view_segment_num, symmetries_ptr))); + new RelatedViewgrams(proj_dat_ptr->get_empty_related_viewgrams(view_segment_num, symmetries_ptr))); mult_viewgrams_sptr->fill(1.F); } - - if (view_segment_num.segment_num()==0 && zero_seg0_end_planes) + + if (view_segment_num.segment_num() == 0 && zero_seg0_end_planes) { zero_end_sinograms(y); zero_end_sinograms(additive_binwise_correction_viewgrams); @@ -228,42 +225,42 @@ void get_viewgrams(shared_ptr >& y, } #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) +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 + 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 + // 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 + { // 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 + // 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 + // 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 + // 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); } @@ -272,40 +269,43 @@ void send_viewgrams(const shared_ptr >& y, } #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, - int min_timing_pos_num, int max_timing_pos_num) +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; - */ + 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"); @@ -316,16 +316,17 @@ void distributable_computation( if (caching_info_ptr != NULL) { - distributable_computation_cache_enabled( - forward_projector_ptr, + 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, + subset_num, + num_subsets, + min_segment_num, + max_segment_num, zero_seg0_end_planes, log_likelihood_ptr, binwise_correction, @@ -334,38 +335,38 @@ void distributable_computation( end_time_of_frame, RPC_process_related_viewgrams, caching_info_ptr, - min_timing_pos_num, max_timing_pos_num); + 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) +# 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(); - + 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 +# 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; @@ -375,14 +376,14 @@ void distributable_computation( assert(min_segment_num <= max_segment_num); assert(min_timing_pos_num <= max_timing_pos_num); - assert(subset_num >=0); + 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; @@ -391,24 +392,22 @@ void distributable_computation( 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 // the RPC function might not need to do a forward projection, e.g. for sensitivity // so test if it exists before doing anything with it if (input_image_ptr && forward_projector_ptr) - forward_projector_ptr->set_input(*input_image_ptr); + forward_projector_ptr->set_input(*input_image_ptr); // same for backprojector if (output_image_ptr && back_projector_ptr) back_projector_ptr->start_accumulating_in_new_target(); @@ -416,106 +415,117 @@ 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); } - #if _OPENMP <201107 - #pragma omp for schedule(dynamic) - #else - // OpenMP loop over both vs_nums_to_process and tof_pos_num - #pragma omp for schedule(dynamic) collapse(2) - #endif +# if _OPENMP < 201107 +# pragma omp for schedule(dynamic) +# else +// OpenMP loop over both vs_nums_to_process and tof_pos_num +# pragma omp for schedule(dynamic) collapse(2) +# endif #endif - 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(vs_nums_to_process.size()); ++i) + for (int timing_pos_num = min_timing_pos_num; timing_pos_num <= max_timing_pos_num; ++timing_pos_num) { - 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]; - } + // 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, timing_pos_num: %d") - % thread_num % omp_get_num_threads() - % view_segment_num.segment_num() % view_segment_num.view_num() % timing_pos_num, 3); -#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,3); -#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, + 3); +# 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, + 3); +# 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 for-loop over timing_pos_num - } // 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) + 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); @@ -525,198 +535,206 @@ void distributable_computation( if (output_image_ptr && back_projector_ptr) 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) + 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]; + + // 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); + 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) + // 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)); - + 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; + 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()); } -void LM_distributable_computation( - const shared_ptr PM_sptr, - const shared_ptr& proj_data_info_sptr, - DiscretisedDensity<3,float>* output_image_ptr, - const DiscretisedDensity<3,float>* input_image_ptr, - const std::vector& record_ptr, - const int subset_num, const int num_subsets, - const bool has_add, - const bool accumulate) +void +LM_distributable_computation(const shared_ptr PM_sptr, + const shared_ptr& proj_data_info_sptr, + DiscretisedDensity<3, float>* output_image_ptr, + const DiscretisedDensity<3, float>* input_image_ptr, + const std::vector& record_ptr, + const int subset_num, + const int num_subsets, + const bool has_add, + const bool accumulate) { - CPUTimer CPU_timer; - CPU_timer.start(); - HighResWallClockTimer wall_clock_timer; - wall_clock_timer.start(); + CPUTimer CPU_timer; + CPU_timer.start(); + HighResWallClockTimer wall_clock_timer; + wall_clock_timer.start(); - assert(!record_ptr.empty()); + assert(!record_ptr.empty()); - const float max_quotient = 10000.F; + const float max_quotient = 10000.F; - if (output_image_ptr != NULL && !accumulate) - output_image_ptr->fill(0.F); + if (output_image_ptr != NULL && !accumulate) + output_image_ptr->fill(0.F); -std::vector< shared_ptr > > local_output_image_sptrs; -std::vector local_log_likelihoods; -std::vector local_counts, local_count2s; -std::vector local_measured_bin, local_basic_bin, local_fwd_bin; -std::vector local_row; -std::vectormeasured_div_fwd; + std::vector>> local_output_image_sptrs; + std::vector local_log_likelihoods; + std::vector local_counts, local_count2s; + std::vector local_measured_bin, local_basic_bin, local_fwd_bin; + std::vector local_row; + std::vector measured_div_fwd; #ifdef STIR_OPENMP -#pragma omp parallel shared(local_output_image_sptrs,local_row, local_log_likelihoods, local_counts, local_count2s, local_measured_bin, local_fwd_bin) +# pragma omp parallel shared(local_output_image_sptrs, \ + local_row, \ + local_log_likelihoods, \ + local_counts, \ + local_count2s, \ + local_measured_bin, \ + local_fwd_bin) #endif - // start of threaded section if openmp - { + // start of threaded section if openmp + { #ifdef STIR_OPENMP -#pragma omp single - { - info("Listmode gradient calculation: starting loop with " + std::to_string(omp_get_num_threads()) + " threads", 2); - local_output_image_sptrs.resize(omp_get_max_threads(), shared_ptr >()); - // 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); - measured_div_fwd.resize(omp_get_max_threads(), 0.f); - local_measured_bin.resize(omp_get_max_threads(), Bin()); - local_basic_bin.resize(omp_get_max_threads(), Bin()); - local_fwd_bin.resize(omp_get_max_threads(), Bin()); - local_row.resize(omp_get_max_threads(), ProjMatrixElemsForOneBin()); - } +# pragma omp single + { + info("Listmode gradient calculation: starting loop with " + std::to_string(omp_get_num_threads()) + " threads", 2); + local_output_image_sptrs.resize(omp_get_max_threads(), shared_ptr>()); + // 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); + measured_div_fwd.resize(omp_get_max_threads(), 0.f); + local_measured_bin.resize(omp_get_max_threads(), Bin()); + local_basic_bin.resize(omp_get_max_threads(), Bin()); + local_fwd_bin.resize(omp_get_max_threads(), Bin()); + local_row.resize(omp_get_max_threads(), ProjMatrixElemsForOneBin()); + } -#pragma omp for schedule(dynamic) +# pragma omp for schedule(dynamic) #else - { - info("Listmode gradient calculation: starting loop with 1 thread", 2); - local_output_image_sptrs.resize(1, shared_ptr >()); - // local_log_likelihoods.resize(omp_get_max_threads(), 0.); - local_counts.resize(1, 0); - local_count2s.resize(1, 0); - measured_div_fwd.resize(1, 0.f); - local_measured_bin.resize(1, Bin()); - local_basic_bin.resize(1, Bin()); - local_fwd_bin.resize(1, Bin()); - local_row.resize(1, ProjMatrixElemsForOneBin()); - } + { + info("Listmode gradient calculation: starting loop with 1 thread", 2); + local_output_image_sptrs.resize(1, shared_ptr>()); + // local_log_likelihoods.resize(omp_get_max_threads(), 0.); + local_counts.resize(1, 0); + local_count2s.resize(1, 0); + measured_div_fwd.resize(1, 0.f); + local_measured_bin.resize(1, Bin()); + local_basic_bin.resize(1, Bin()); + local_fwd_bin.resize(1, Bin()); + local_row.resize(1, ProjMatrixElemsForOneBin()); + } #endif - // Putting the Bins here I avoid rellocation. - for (long int ievent = 0; ievent < record_ptr.size(); ++ievent) - { + // Putting the Bins here I avoid rellocation. + for (long int ievent = 0; ievent < record_ptr.size(); ++ievent) + { #ifdef STIR_OPENMP - const int thread_num = omp_get_thread_num(); + const int thread_num = omp_get_thread_num(); #else - const int thread_num=0; + const int thread_num = 0; #endif - local_measured_bin[thread_num] = record_ptr.at(ievent).my_bin; + local_measured_bin[thread_num] = record_ptr.at(ievent).my_bin; - if (local_measured_bin[thread_num].get_bin_value() == 0.0f) - continue; - - if (num_subsets > 1) - { - local_basic_bin[thread_num] = local_measured_bin[thread_num]; - if (!PM_sptr->get_symmetries_ptr()->is_basic(local_measured_bin[thread_num]) ) - PM_sptr->get_symmetries_ptr()->find_basic_bin(local_basic_bin[thread_num]); - - if (subset_num != static_cast(local_basic_bin[thread_num].view_num() % num_subsets)) - { - continue; - } - } + if (local_measured_bin[thread_num].get_bin_value() == 0.0f) + continue; - PM_sptr->get_proj_matrix_elems_for_one_bin(local_row[thread_num], - local_measured_bin[thread_num]); + if (num_subsets > 1) + { + local_basic_bin[thread_num] = local_measured_bin[thread_num]; + if (!PM_sptr->get_symmetries_ptr()->is_basic(local_measured_bin[thread_num])) + PM_sptr->get_symmetries_ptr()->find_basic_bin(local_basic_bin[thread_num]); - local_fwd_bin[thread_num].set_bin_value(0.0f); - local_row[thread_num].forward_project(local_fwd_bin[thread_num], *input_image_ptr); + if (subset_num != static_cast(local_basic_bin[thread_num].view_num() % num_subsets)) + { + continue; + } + } - if (has_add) - { - local_fwd_bin[thread_num].set_bin_value( - local_fwd_bin[thread_num].get_bin_value() + record_ptr.at(ievent).my_corr); - } + PM_sptr->get_proj_matrix_elems_for_one_bin(local_row[thread_num], local_measured_bin[thread_num]); - measured_div_fwd[thread_num] = 0.0; + local_fwd_bin[thread_num].set_bin_value(0.0f); + local_row[thread_num].forward_project(local_fwd_bin[thread_num], *input_image_ptr); - if (output_image_ptr != NULL) - { - if(is_null_ptr(local_output_image_sptrs[thread_num])) - local_output_image_sptrs[thread_num].reset(output_image_ptr->get_empty_copy()); - } + if (has_add) + { + local_fwd_bin[thread_num].set_bin_value(local_fwd_bin[thread_num].get_bin_value() + record_ptr.at(ievent).my_corr); + } - if ( local_measured_bin[thread_num].get_bin_value() <= max_quotient *local_fwd_bin[thread_num].get_bin_value()) - measured_div_fwd[thread_num] = local_measured_bin[thread_num].get_bin_value() /local_fwd_bin[thread_num].get_bin_value(); - else - continue; + measured_div_fwd[thread_num] = 0.0; - local_measured_bin[thread_num].set_bin_value(measured_div_fwd[thread_num]); - local_row[thread_num].back_project(*local_output_image_sptrs[thread_num], local_measured_bin[thread_num]); - } - } -#ifdef STIR_OPENMP - // flatten data constructed by threads - { if (output_image_ptr != NULL) - { - 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 - *output_image_ptr += *(local_output_image_sptrs[i]); - } - - } + { + if (is_null_ptr(local_output_image_sptrs[thread_num])) + local_output_image_sptrs[thread_num].reset(output_image_ptr->get_empty_copy()); + } + + if (local_measured_bin[thread_num].get_bin_value() <= max_quotient * local_fwd_bin[thread_num].get_bin_value()) + measured_div_fwd[thread_num] + = local_measured_bin[thread_num].get_bin_value() / local_fwd_bin[thread_num].get_bin_value(); + else + continue; + + local_measured_bin[thread_num].set_bin_value(measured_div_fwd[thread_num]); + local_row[thread_num].back_project(*local_output_image_sptrs[thread_num], local_measured_bin[thread_num]); + } + } +#ifdef STIR_OPENMP + // flatten data constructed by threads + { + if (output_image_ptr != NULL) + { + 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 + *output_image_ptr += *(local_output_image_sptrs[i]); + } + } #endif - 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()); + 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()); } END_NAMESPACE_STIR diff --git a/src/recon_buildblock/distributableMPICacheEnabled.cxx b/src/recon_buildblock/distributableMPICacheEnabled.cxx index e96107ef5..560eeaa14 100644 --- a/src/recon_buildblock/distributableMPICacheEnabled.cxx +++ b/src/recon_buildblock/distributableMPICacheEnabled.cxx @@ -16,8 +16,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 @@ -25,7 +25,7 @@ /* Modification history:d 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 @@ -45,9 +45,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 @@ -62,8 +62,7 @@ zero_end_sinograms(ViewgramsPtr 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(); + 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); @@ -72,57 +71,55 @@ zero_end_sinograms(ViewgramsPtr viewgrams_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 - ) +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 (!is_null_ptr(binwise_correction)) { - additive_binwise_correction_viewgrams.reset( - new RelatedViewgrams - (binwise_correction->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); + additive_binwise_correction_viewgrams.reset(new RelatedViewgrams( + binwise_correction->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); } - + if (read_from_proj_dat) { - y.reset(new RelatedViewgrams - (proj_dat_ptr->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); + y.reset(new RelatedViewgrams( + proj_dat_ptr->get_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); } else { - y.reset(new RelatedViewgrams - (proj_dat_ptr->get_empty_related_viewgrams(view_segment_num, symmetries_ptr, false, timing_pos_num))); + 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, false, timing_pos_num))); + 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); } else if (zero_seg0_end_planes) - { - // No normalisation provided but zero_seg0_end_planes, create a mult_viewgrams - 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 (view_segment_num.segment_num()==0 && zero_seg0_end_planes) + { + // No normalisation provided but zero_seg0_end_planes, create a mult_viewgrams + 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 (view_segment_num.segment_num() == 0 && zero_seg0_end_planes) { zero_end_sinograms(y); zero_end_sinograms(additive_binwise_correction_viewgrams); @@ -130,42 +127,42 @@ void get_viewgrams(shared_ptr >& y, } } -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) +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); + 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 + // 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 + { // 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 + // 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 + // 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 + // 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); } @@ -173,198 +170,206 @@ static void send_viewgrams(const shared_ptr >& 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, - int min_timing_pos_num, int max_timing_pos_num - ) -{ - //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) + 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(); - + 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(min_timing_pos_num <= max_timing_pos_num); - assert(subset_num >=0); + 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; }; - + // 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 + + // 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]; + // 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) > 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) < 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) + while (working_slaves_count > 0) { - status=distributed::receive_int_values(int_values, 2, AVAILABLE_NOTIFICATION_TAG); + 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]; + + // 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 - // the call-back function + + // 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 + // 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); + 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) + + // 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)); - + 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; + 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 de2d03153..8eff81b6f 100644 --- a/src/recon_buildblock/distributed_functions.cxx +++ b/src/recon_buildblock/distributed_functions.cxx @@ -14,7 +14,7 @@ \brief Implementation of functions in distributed namespace - \author Tobias Beisel + \author Tobias Beisel \author Kris Thielemans */ @@ -36,764 +36,956 @@ 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; +// 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; -#ifdef STIR_MPI_TIMINGS - if (test_send_receive_times) {t.reset(); t.start();} +#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();} -#endif - - if (destination == -1) - for (int processor=1; processormin_threshold) std::cout << "Master/Slave: sending string 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 string took " << t.value() << " seconds" << std::endl; #endif - delete[] buf; - } - - void send_bool_value(bool value, int tag, int destination) - { - int i; - if (value==true) i=1; - else i=0; - + 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();} + 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); - + + 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) - { +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();} + if (test_send_receive_times) + { + t.reset(); + t.start(); + } #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.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 +} - } - - void send_double_values(double * values, int count, int tag, int destination) - { +void +send_double_values(double* values, int count, int tag, int destination) +{ #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; -#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();} -#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 - - } - - 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 + + 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.reset(); t.start();} + 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 - - if (destination == -1) - { - MPI_Bcast(image_buf, image_buffer_size, MPI_FLOAT, 0, MPI_COMM_WORLD); - //for (int processor=1; processor* 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.stop(); - if (test_send_receive_times && t.value()>min_threshold) std::cout << "Master/Slave: sending image values took " << t.value() << " seconds" << std::endl; + if (test_send_receive_times) + { + t.reset(); + t.start(); + } #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 - - //send text_buffer - if (destination==-1) - for (processor=1; processor 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 +} + +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; 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 + + // send text_buffer + if (destination == -1) + for (processor = 1; processor < num_processors; processor++) { - 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); + 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); } - -#ifdef STIR_MPI_TIMINGS - 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_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 + 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); + } + #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: sending projection_data_info took " << t.value() << " seconds" << std::endl; #endif - MPI_Send(viewgram_buf, buffer_size, MPI_FLOAT, destination, VIEWGRAM_TAG, MPI_COMM_WORLD); + 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.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.reset(); + t.start(); + } #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); + MPI_Send(viewgram_buf, buffer_size, MPI_FLOAT, destination, VIEWGRAM_TAG, MPI_COMM_WORLD); - } - - //--------------------------------------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.stop(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Master: sending viewgram took " << t.value() << " seconds" << std::endl; #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); - + + 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); +} + +//--------------------------------------Receive Operations------------------------------------- + +int +receive_int_value(int source) +{ + int i; #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.reset(); + t.start(); + } #endif - - return i; - } - - std::string receive_string(int tag, int source) - { + + 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.reset(); t.start();} + 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 - - 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); - + + return i; +} + +std::string +receive_string(int tag, int source) +{ #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.reset(); + t.start(); + } #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 - + + 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.reset(); t.start();} + 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 - - 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); - + + // 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.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.reset(); + t.start(); + } #endif - - return i!=0; - } - - MPI_Status receive_int_values(int * values, int count, int tag) - { + // 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.reset(); t.start();} + 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 - 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); + // 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.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.reset(); + t.start(); + } #endif - return status; - } - - MPI_Status receive_double_values(double * values, int count, int tag) - { + 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.reset(); t.start();} + 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 - - 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); - + + // 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.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.reset(); + t.start(); + } #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();} + 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 - - 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); + + return i != 0; +} + +MPI_Status +receive_int_values(int* values, int count, int tag) +{ #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.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 == 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(); + 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 - - 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]); + + 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 + + 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(); + } +#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); + +#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(); + } +#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; +#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]); #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)); -#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();} -#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; -#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 + 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();} + 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_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 - - //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) - { - //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); - } - - 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();} -#endif - //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); - - const int v_num = viewgram_values[4]; - const int s_num = viewgram_values[5]; - const int t_num = viewgram_values[6]; - - viewgram_ptr= new stir::Viewgram(proj_data_info_ptr, v_num, s_num, t_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 - - 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; -#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(); + 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(); + } +#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; +#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) +{ + // 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(); + } #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(proj_data_info_ptr, v_num, s_num, t_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 + + 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.reset(); t.start();} + 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 +} - MPI_Reduce(image_buf, output_buf, image_buffer_size, MPI_FLOAT, MPI_SUM, destination, MPI_COMM_WORLD); - delete[] image_buf; +//--------------------------------------Reduce Operations------------------------------------- +void +reduce_received_output_image(stir::DiscretisedDensity<3, float>* output_image_ptr, int destination) +{ #ifdef STIR_MPI_TIMINGS - 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; + 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; ibegin_all()); - delete[] output_buf; + // receive output image values #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.reset(); + t.start(); + } #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 -#ifdef STIR_MPI_TIMINGS - 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; - } - + + 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(); + if (test_send_receive_times && t.value() > min_threshold) + std::cout << "Master: reduced output_image after " << t.value() << " seconds" << std::endl; +#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; +#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; +#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 +#ifdef STIR_MPI_TIMINGS + 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 7f5bb0497..052c43ea6 100644 --- a/src/recon_buildblock/distributed_test_functions.cxx +++ b/src/recon_buildblock/distributed_test_functions.cxx @@ -15,7 +15,7 @@ \brief Implementation of test functions in distributed namespace - \author Tobias Beisel + \author Tobias Beisel */ @@ -25,246 +25,262 @@ 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); +void +test_viewgram_slave(const stir::shared_ptr& proj_data_info_ptr) +{ + printf("\n-----Slave startet Test for sending viewgram----------\n"); - 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); - } - - 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) + 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) { - 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++; + 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"); } - - 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<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++; + } + + 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]); + } + viewgrams_iter++; + received_viewgrams_iter++; + } + + 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< - 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); +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 48c8309c8..47457b05b 100644 --- a/src/recon_buildblock/recon_buildblock_registries.cxx +++ b/src/recon_buildblock/recon_buildblock_registries.cxx @@ -61,37 +61,38 @@ #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 #ifdef STIR_WITH_Parallelproj_PROJECTOR -#include "stir/recon_buildblock/Parallelproj_projector/ForwardProjectorByBinParallelproj.h" -#include "stir/recon_buildblock/Parallelproj_projector/BackProjectorByBinParallelproj.h" -#include "stir/recon_buildblock/Parallelproj_projector/ProjectorByBinPairUsingParallelproj.h" +# include "stir/recon_buildblock/Parallelproj_projector/ForwardProjectorByBinParallelproj.h" +# include "stir/recon_buildblock/Parallelproj_projector/BackProjectorByBinParallelproj.h" +# include "stir/recon_buildblock/Parallelproj_projector/ProjectorByBinPairUsingParallelproj.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,17 +121,17 @@ 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; -static OSMAPOSLReconstruction::RegisterIt dummyOSMAPOSLPVC; -static OSSPSReconstruction::RegisterIt dummyOSSPSPVC; +static OSMAPOSLReconstruction::RegisterIt dummyOSMAPOSLPVC; +static OSSPSReconstruction::RegisterIt dummyOSSPSPVC; #ifdef STIR_WITH_NiftyPET_PROJECTOR static ForwardProjectorByBinNiftyPET::RegisterIt gpu_fwd; diff --git a/src/recon_test/bcktest.cxx b/src/recon_test/bcktest.cxx index 9c975a19c..47a49adc7 100644 --- a/src/recon_test/bcktest.cxx +++ b/src/recon_test/bcktest.cxx @@ -23,10 +23,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:= @@ -70,133 +70,129 @@ using std::find; using std::cerr; using std::endl; - - - START_NAMESPACE_STIR void -do_segments(DiscretisedDensity<3,float>& image, +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) + 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()); - - + + shared_ptr symmetries_sptr(back_projector_ptr->get_symmetries_used()->clone()); + list already_processed; back_projector_ptr->start_accumulating_in_new_target(); 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 + { + 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"; +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"); + 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]); + 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 @@ -205,56 +201,49 @@ main(int argc, char **argv) // 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())); + 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) + 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.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(); - if (argc>3) + shared_ptr> image_sptr; + + if (argc > 3) { - image_sptr = read_from_file >(argv[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)); + 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); } @@ -264,127 +253,123 @@ main(int argc, char **argv) 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); - + 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); - - // 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 - int max_axial_pos_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); - } - - 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); + 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); + + // 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 + int max_axial_pos_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); + } + + 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 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); #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; - - 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_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; - - 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_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)); - return EXIT_SUCCESS; + // 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; + + 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_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; + + 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_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)); + + return EXIT_SUCCESS; } - - diff --git a/src/recon_test/fwdtest.cxx b/src/recon_test/fwdtest.cxx index a7b07a955..d4e9bc708 100644 --- a/src/recon_test/fwdtest.cxx +++ b/src/recon_test/fwdtest.cxx @@ -18,7 +18,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 @@ -26,7 +26,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 @@ -62,151 +62,135 @@ #include "stir/error.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_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); - - +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[]) +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); - } - + 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]); - 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(); - } + 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 - { - 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() ); + { + 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()); 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) + 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; - } - } + 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; + } + } } else { - image_sptr = - read_from_file >(argv[3]); - vox_image_ptr = dynamic_cast *> (image_sptr.get()); + 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(); - - vox_image_ptr->set_origin(make_coordinate(z_origin,0.F,0.F) + vox_image_ptr->get_origin()); + 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()); // use shared_ptr such that it cleans up automatically shared_ptr forw_projector_ptr; - if (argc>=5) + 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.add_stop_key("END"); parser.parse(argv[4]); } @@ -215,8 +199,7 @@ main(int argc, char *argv[]) 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) @@ -224,267 +207,229 @@ main(int argc, char *argv[]) cerr << "Displaying start image"; display(*image_sptr, image_sptr->find_max()); } - if (save) - { - cerr << "Saving start image to 'test_image'" << endl; - OutputFileFormat >::default_sptr()-> - write_to_file("test_image", *image_sptr); - } - + { + cerr << "Saving start image to 'test_image'" << endl; + OutputFileFormat>::default_sptr()->write_to_file("test_image", *image_sptr); + } + std::list already_processed; 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_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_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 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 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, - 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"<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" << endl; + } + else + { + const bool disp = ask("Display projected related viewgrams ? ", false); + + // first set all data to 0 + cerr << "Filling output file with 0\n"; + 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 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 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, + 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" << endl; + + } while (ask("One more ? ", true)); } - while (ask("One more ? ", true)); - } return EXIT_SUCCESS; - } /******************* Implementation local functions *******************/ void 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) + 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; - 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"); - } - } -} - + shared_ptr symmetries_sptr(forw_projector.get_symmetries_used()->clone()); + std::list already_processed; + 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) +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 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) +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.); - + 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++) + 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)); + 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)); } - - for (int z=image.get_min_z(); z<=image.get_max_z(); z++) + + 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; + 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 139d37212..6b10018c5 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,71 @@ #include "stir/CPUTimer.h" #include "stir/HighResWallClockTimer.h" -static void print_usage_and_exit() +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); + 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[]) +int +main(int argc, const char* argv[]) { - using namespace stir; + 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) + if (reconstruction_method_sptr->reconstruct() == Succeeded::yes) { - t.stop(); - std::cout << "Total Wall clock time: " << t.value() << " seconds" << std::endl; - return EXIT_SUCCESS; + t.stop(); + std::cout << "Total Wall clock time: " << t.value() << " seconds" << std::endl; + return EXIT_SUCCESS; } - else + else { - t.stop(); - return EXIT_FAILURE; + 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 7232c5a58..0f68e53fa 100644 --- a/src/recon_test/test_DataSymmetriesForBins_PET_CartesianGrid.cxx +++ b/src/recon_test/test_DataSymmetriesForBins_PET_CartesianGrid.cxx @@ -12,13 +12,13 @@ \file \ingroup test - + \brief Test program for stir::DataSymmetriesForBins_PET_CartesianGrid Uses stir::ProjMatrixByBinUsingRayTracing. - + \author Kris Thielemans - + */ #include "stir/VoxelsOnCartesianGrid.h" @@ -42,11 +42,10 @@ using std::cerr; START_NAMESPACE_STIR template -bool -coordinates_less(const BasicCoordinate<3,T>& el1, const BasicCoordinate<3,T>& el2) +bool +coordinates_less(const BasicCoordinate<3, T>& el1, const BasicCoordinate<3, T>& el2) { - return el1[1]& el1, const BasicCoordinate<3,T>& el 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() override; + 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); + 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)); @@ -112,629 +109,548 @@ 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 symmetry LORs") || - !check(elems_with_sym.get_bin() == elems_no_sym.get_bin(), "Comparing symmetry bin configuration")) - { - // SYM const Bin bin=*bin_iter; - - cerr << "\nCurrent bin: \tsegment = " << bin.segment_num() - << ", \taxial pos " << bin.axial_pos_num() - << ", \tview = " << bin.view_num() - << ", \ttangential_pos_num = " << bin.tangential_pos_num() + elems_no_sym.sort(); + elems_with_sym.sort(); + + if (!check(elems_no_sym == elems_with_sym, "Comparing symmetry LORs") + || !check(elems_with_sym.get_bin() == elems_no_sym.get_bin(), "Comparing symmetry bin configuration")) + { + // SYM const Bin bin=*bin_iter; + + cerr << "\nCurrent bin: \tsegment = " << bin.segment_num() << ", \taxial pos " << bin.axial_pos_num() + << ", \tview = " << bin.view_num() << ", \ttangential_pos_num = " << bin.tangential_pos_num() << ", timing position index = " << bin.timing_pos_num() - << "\nSymm bin: \t\tsegment = " << elems_with_sym.get_bin().segment_num() - << ", \taxial pos " << elems_with_sym.get_bin().axial_pos_num() - << ", \tview = " << elems_with_sym.get_bin().view_num() + << "\nSymm bin: \t\tsegment = " << elems_with_sym.get_bin().segment_num() << ", \taxial pos " + << elems_with_sym.get_bin().axial_pos_num() << ", \tview = " << elems_with_sym.get_bin().view_num() << ", \ttangential_pos_num = " << elems_with_sym.get_bin().tangential_pos_num() << ", timing position index = " << bin.timing_pos_num() << "\n"; - if (elems_no_sym != elems_with_sym) + if (elems_no_sym != elems_with_sym) { - proj_matrix_with_symm. - get_proj_matrix_elems_for_one_bin(elems_with_sym, bin); + proj_matrix_with_symm.get_proj_matrix_elems_for_one_bin(elems_with_sym, bin); elems_with_sym.sort(); - std::cerr << "No Symmetries Iterator || Symmetries Iterator " << std::endl; - ProjMatrixElemsForOneBin::const_iterator no_sym_iter= elems_no_sym.begin(); - ProjMatrixElemsForOneBin::const_iterator with_sym_iter = elems_with_sym.begin(); - cerr << " no_sym_iter || sym_iter || Error \n"; - 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(); + std::cerr << "No Symmetries Iterator || Symmetries Iterator " << std::endl; + ProjMatrixElemsForOneBin::const_iterator no_sym_iter = elems_no_sym.begin(); + ProjMatrixElemsForOneBin::const_iterator with_sym_iter = elems_with_sym.begin(); + cerr << " no_sym_iter || sym_iter || Error \n"; + 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(); // If the error is in the same const float err = (no_sym_iter->get_value() / with_sym_iter->get_value() - 1); const float t = 0.01; - if (no_sym_iter->get_coords() == with_sym_iter->get_coords()) { - if ((fabs(err) > t) && (no_sym_iter->get_value() > 1e-5 || with_sym_iter->get_value() > 1e-5)) - { cerr << " || abs(" << err*100 << "%) > " << t * 100 << "%"; } - else - { cerr << " || values less than `1e-5%`;";} } - - ++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; - } - } - } - } + if (no_sym_iter->get_coords() == with_sym_iter->get_coords()) + { + if ((fabs(err) > t) && (no_sym_iter->get_value() > 1e-5 || with_sym_iter->get_value() > 1e-5)) + { + cerr << " || abs(" << err * 100 << "%) > " << t * 100 << "%"; + } + else + { + cerr << " || values less than `1e-5%`;"; + } + } + + ++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 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); - } + 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 - ) -{ +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); - } + 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; - { - 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 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_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 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); - } - } + 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 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_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 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 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 := 0\n" - "do symmetry 180degrees min phi := 0\n" - "do_symmetry_swap_segment := 0\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); - } + 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 := 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 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 := 0\n" - "do symmetry 180degrees min phi := 0\n" - "do_symmetry_swap_segment := 1\n" - "do_symmetry_swap_s := 0\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); - } + 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 := 0\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 shift_z and 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 := 0\n" - "do symmetry 180degrees min phi := 0\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); - } + 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 := 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 shift_z and 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 := 0\n" - "do symmetry 180degrees min phi := 0\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); - } + 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 := 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 swap_s and 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 := 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 := 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); - } + 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 := 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); + } } } void -DataSymmetriesForBins_PET_CartesianGridTests:: -run_tests_for_1_projdata(const shared_ptr& proj_data_info_sptr) +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; + 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) @@ -746,7 +662,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) @@ -772,94 +688,87 @@ 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 { - 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 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 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() -{ +{ cerr << "Tests for DataSymmetriesForBins_PET_CartesianGrid\n"; 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=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=*/13, - /*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=*/13, + /*num_views=*/8, + /*num_tang_poss=*/16)); + + run_tests_for_1_projdata(proj_data_info_sptr); } { 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)); + 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); } @@ -868,36 +777,32 @@ DataSymmetriesForBins_PET_CartesianGridTests::run_tests() // 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::test_scanner)); - proj_data_info_sptr.reset( - ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span=*/1, - /*max_delta=*/3, - /*num_views=*/scanner_sptr->get_num_detectors_per_ring()/8, - /*num_tang_poss=*/16, - /*arc_corrected*/false, - /*tof_mashing*/112)); + proj_data_info_sptr.reset(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span=*/1, + /*max_delta=*/3, + /*num_views=*/scanner_sptr->get_num_detectors_per_ring() / 8, + /*num_tang_poss=*/16, + /*arc_corrected*/ false, + /*tof_mashing*/ 112)); 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(); + 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) +int +main(int argc, char** argv) { - DataSymmetriesForBins_PET_CartesianGridTests tests(argc==2? argv[1] : 0); + 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 bae5ce832..f14d6cf60 100644 --- a/src/recon_test/test_FBP2D.cxx +++ b/src/recon_test/test_FBP2D.cxx @@ -17,7 +17,7 @@ START_NAMESPACE_STIR -typedef DiscretisedDensity<3,float> target_type; +typedef DiscretisedDensity<3, float> target_type; /*! \ingroup recon_test \ingroup FBP2D @@ -27,65 +27,61 @@ 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) {} ~TestFBP2D() override {} - std::unique_ptr - construct_default_proj_data_info_uptr() const override; - + std::unique_ptr construct_default_proj_data_info_uptr() const override; + void construct_reconstructor() override; void run_tests() override; }; std::unique_ptr -TestFBP2D:: -construct_default_proj_data_info_uptr() const +TestFBP2D::construct_default_proj_data_info_uptr() const { // construct a small scanner and sinogram shared_ptr scanner_sptr(new Scanner(Scanner::E953)); // currently need this for limitation in the backprojector scanner_sptr->set_intrinsic_azimuthal_tilt(0.F); scanner_sptr->set_num_rings(5); - std::unique_ptr proj_data_info_uptr( - ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span=*/3, - /*max_delta=*/4, - /*num_views=*/128, - /*num_tang_poss=*/128)); + std::unique_ptr proj_data_info_uptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span=*/3, + /*max_delta=*/4, + /*num_views=*/128, + /*num_tang_poss=*/128)); return proj_data_info_uptr; } 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 { - this->construct_input_data(); - this->construct_reconstructor(); - shared_ptr output_sptr(this->_input_density_sptr->get_empty_copy()); - this->reconstruct(output_sptr); - this->compare(output_sptr); - } - catch(const std::exception &error) + try + { + this->construct_input_data(); + this->construct_reconstructor(); + 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(...) + catch (...) { everything_ok = false; } @@ -101,32 +97,31 @@ run_tests() everything_ok = false; } catch (...) - { - } + {} } } 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" - << "Image (optional) has to be compatible with projection data and currently at zoom=1\n"; - return EXIT_FAILURE; + 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 c0175c5c1..b6905cf8d 100644 --- a/src/recon_test/test_FBP3DRP.cxx +++ b/src/recon_test/test_FBP3DRP.cxx @@ -17,7 +17,7 @@ START_NAMESPACE_STIR -typedef DiscretisedDensity<3,float> target_type; +typedef DiscretisedDensity<3, float> target_type; /*! \ingroup recon_test \ingroup FBP3DRP @@ -27,65 +27,61 @@ 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) {} ~TestFBP3DRP() override {} - std::unique_ptr - construct_default_proj_data_info_uptr() const override; - + std::unique_ptr construct_default_proj_data_info_uptr() const override; + void construct_reconstructor() override; void run_tests() override; }; std::unique_ptr -TestFBP3DRP:: -construct_default_proj_data_info_uptr() const +TestFBP3DRP::construct_default_proj_data_info_uptr() const { // construct a small scanner and sinogram shared_ptr scanner_sptr(new Scanner(Scanner::E953)); // currently need this for limitation in the backprojector scanner_sptr->set_intrinsic_azimuthal_tilt(0.F); scanner_sptr->set_num_rings(5); - std::unique_ptr proj_data_info_uptr( - ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span=*/3, - /*max_delta=*/4, - /*num_views=*/128, - /*num_tang_poss=*/128)); + std::unique_ptr proj_data_info_uptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span=*/3, + /*max_delta=*/4, + /*num_views=*/128, + /*num_tang_poss=*/128)); return proj_data_info_uptr; } 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 { - this->construct_input_data(); - this->construct_reconstructor(); - shared_ptr output_sptr(this->_input_density_sptr->get_empty_copy()); - this->reconstruct(output_sptr); - this->compare(output_sptr); - } - catch(const std::exception &error) + try + { + this->construct_input_data(); + this->construct_reconstructor(); + 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(...) + catch (...) { everything_ok = false; } @@ -93,22 +89,22 @@ run_tests() 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" - << "Image (optional) has to be compatible with projection data and currently at zoom=1\n"; - return EXIT_FAILURE; - } + 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(); - 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 b8488eef6..a8c7a0586 100644 --- a/src/recon_test/test_OSMAPOSL.cxx +++ b/src/recon_test/test_OSMAPOSL.cxx @@ -17,7 +17,7 @@ START_NAMESPACE_STIR -typedef DiscretisedDensity<3,float> target_type; +typedef DiscretisedDensity<3, float> target_type; /*! \ingroup recon_test \ingroup OSMAPOSL @@ -27,56 +27,53 @@ 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 &projector_pair_filename = "", - const std::string &proj_data_filename = "", - const std::string & density_filename = "") - : base_type(projector_pair_filename, proj_data_filename, density_filename) + TestOSMAPOSL(const std::string& projector_pair_filename = "", + const std::string& proj_data_filename = "", + const std::string& density_filename = "") + : base_type(projector_pair_filename, proj_data_filename, density_filename) {} ~TestOSMAPOSL() override {} - void construct_reconstructor() override; - OSMAPOSLReconstruction& - recon() - { return dynamic_cast& >(*this->_recon_sptr); } + OSMAPOSLReconstruction& recon() { return dynamic_cast&>(*this->_recon_sptr); } void run_tests() override; }; - 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); - //this->recon().set_num_subsets(4); // TODO should really check if this is appropriate for this->_proj_data_sptr->get_num_views() + // this->recon().set_num_subsets(4); // TODO should really check if this is appropriate for + // this->_proj_data_sptr->get_num_views() this->recon().set_num_subiterations(20); } void -TestOSMAPOSL:: -run_tests() +TestOSMAPOSL::run_tests() { std::cerr << "Tests for OSMAPOSL\n"; - try { - this->construct_input_data(); - this->construct_reconstructor(); - shared_ptr output_sptr(this->_input_density_sptr->get_empty_copy()); - output_sptr->fill(1.F); - this->reconstruct(output_sptr); - this->compare(output_sptr); - } - catch(const std::exception &error) + try + { + this->construct_input_data(); + this->construct_reconstructor(); + shared_ptr output_sptr(this->_input_density_sptr->get_empty_copy()); + 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(...) + catch (...) { everything_ok = false; } @@ -92,34 +89,33 @@ run_tests() everything_ok = false; } catch (...) - { - } + {} } } 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 << "\nUsage: " << argv[0] << " [projector_pair_filename [template_proj_data [image]]]\n" - << "projector_pair_filename (optional) can be used to specify the projectors\n" - <<" if set to an empty string, the default ray-tracing matrix will be used.\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; + if (argc < 1 || argc > 3) + { + std::cerr << "\nUsage: " << argv[0] << " [projector_pair_filename [template_proj_data [image]]]\n" + << "projector_pair_filename (optional) can be used to specify the projectors\n" + << " if set to an empty string, the default ray-tracing matrix will be used.\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] : "", argc > 3 ? argv[3] : ""); + TestOSMAPOSL test(argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "", argc > 3 ? argv[3] : ""); - 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 c96bdf2b8..d940b0752 100644 --- a/src/recon_test/test_PoissonLogLikelihoodWithLinearModelForMeanAndProjData.cxx +++ b/src/recon_test/test_PoissonLogLikelihoodWithLinearModelForMeanAndProjData.cxx @@ -11,7 +11,7 @@ \file \ingroup recon_test - + \brief Test program for stir::PoissonLogLikelihoodWithLinearModelForMeanAndProjData \par Usage @@ -56,24 +56,23 @@ #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). @@ -90,27 +89,27 @@ 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() override; + protected: - char const * proj_data_filename; - char const * density_filename; + char const* proj_data_filename; + char const* density_filename; shared_ptr proj_data_sptr; shared_ptr mult_proj_data_sptr; shared_ptr add_proj_data_sptr; - shared_ptr > objective_function_sptr; + 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); //! Test the gradient of the objective function by comparing to the numerical gradient via perturbation - void test_objective_function_gradient(GeneralisedObjectiveFunction& objective_function, - target_type& target); + void test_objective_function_gradient(GeneralisedObjectiveFunction& objective_function, target_type& target); //! Test the Hessian of the objective function by testing the (x^T Hx > 0) condition void test_objective_function_Hessian_concavity(GeneralisedObjectiveFunction& objective_function, @@ -119,57 +118,57 @@ class PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests : public RunTes //! Test the approximate Hessian of the objective function by testing the (x^T Hx > 0) condition void test_objective_function_approximate_Hessian_concavity(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) +{ std::cerr << "----- testing Gradient\n"; - test_objective_function_gradient(objective_function,target); + test_objective_function_gradient(objective_function, target); std::cerr << "----- testing Hessian-vector product (accumulate_Hessian_times_input)\n"; - test_objective_function_Hessian_concavity(objective_function,target); + test_objective_function_Hessian_concavity(objective_function, target); std::cerr << "----- testing approximate-Hessian-vector product (accumulate_Hessian_times_input)\n"; test_objective_function_approximate_Hessian_concavity(objective_function, target); } void -PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests:: -test_objective_function_gradient(GeneralisedObjectiveFunction &objective_function, - target_type &target) +PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests::test_objective_function_gradient( + GeneralisedObjectiveFunction& objective_function, 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()) + 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); + 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; + testOK = testOK && this->check_if_equal(gradient_at_iter, *gradient_iter, "gradient"); + ++target_iter; + ++gradient_iter; } if (!testOK) { @@ -178,27 +177,28 @@ test_objective_function_gradient(GeneralisedObjectiveFunction &obje write_to_file("gradient.hv", *gradient_sptr); write_to_file("numerical_gradient.hv", *gradient_2_sptr); #if 1 - info("Writing diagnostic files subsens.hv, gradient-without-sens.hv, " - "proj_data.hs, mult_proj_data.hs and add_proj_data.hs"); - - write_to_file("subsens.hv", - reinterpret_cast &>(objective_function).get_subset_sensitivity(subset_num)); - gradient_sptr->fill(0.F); - reinterpret_cast &>(objective_function). - compute_sub_gradient_without_penalty_plus_sensitivity(*gradient_sptr, target, subset_num); - write_to_file("gradient-without-sens.hv", *gradient_sptr); - proj_data_sptr->write_to_file("proj_data.hs"); - mult_proj_data_sptr->write_to_file("mult_proj_data.hs"); - add_proj_data_sptr->write_to_file("add_proj_data.hs"); + info("Writing diagnostic files subsens.hv, gradient-without-sens.hv, " + "proj_data.hs, mult_proj_data.hs and add_proj_data.hs"); + + write_to_file( + "subsens.hv", + reinterpret_cast&>(objective_function) + .get_subset_sensitivity(subset_num)); + gradient_sptr->fill(0.F); + reinterpret_cast&>(objective_function) + .compute_sub_gradient_without_penalty_plus_sensitivity(*gradient_sptr, target, subset_num); + write_to_file("gradient-without-sens.hv", *gradient_sptr); + proj_data_sptr->write_to_file("proj_data.hs"); + mult_proj_data_sptr->write_to_file("mult_proj_data.hs"); + add_proj_data_sptr->write_to_file("add_proj_data.hs"); #endif } - } void -PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests:: -test_objective_function_Hessian_concavity(GeneralisedObjectiveFunction &objective_function, - target_type &target){ +PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests::test_objective_function_Hessian_concavity( + GeneralisedObjectiveFunction& objective_function, target_type& target) +{ /// setup images shared_ptr output(target.get_empty_copy()); @@ -209,22 +209,23 @@ test_objective_function_Hessian_concavity(GeneralisedObjectiveFunctionbegin_all(), 0.F); // test for a CONCAVE function - if (this->check_if_less( my_sum, 0)) { -// info("PASS: Computation of x^T H x = " + std::to_string(my_sum) + " < 0" (Hessian) and is therefore concave); - } else { - // print to console the FAILED configuration - info("FAIL: Computation of x^T H x = " + std::to_string(my_sum) + " > 0 (Hessian) and is therefore NOT concave" + - "\n >target image max=" + std::to_string(target.find_max()) + - "\n >target image min=" + std::to_string(target.find_min())); - } + if (this->check_if_less(my_sum, 0)) + { + // info("PASS: Computation of x^T H x = " + std::to_string(my_sum) + " < 0" (Hessian) and is therefore concave); + } + else + { + // print to console the FAILED configuration + info("FAIL: Computation of x^T H x = " + std::to_string(my_sum) + " > 0 (Hessian) and is therefore NOT concave" + + "\n >target image max=" + std::to_string(target.find_max()) + + "\n >target image min=" + std::to_string(target.find_min())); + } } - - void -PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests:: -test_objective_function_approximate_Hessian_concavity(GeneralisedObjectiveFunction &objective_function, - target_type &target){ +PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests::test_objective_function_approximate_Hessian_concavity( + GeneralisedObjectiveFunction& objective_function, target_type& target) +{ /// setup images shared_ptr output(target.get_empty_copy()); @@ -235,78 +236,73 @@ test_objective_function_approximate_Hessian_concavity(GeneralisedObjectiveFuncti const float my_sum = std::inner_product(target.begin_all(), target.end_all(), output->begin_all(), 0.F); // test for a CONCAVE function - if (this->check_if_less( my_sum, 0)) { -// info("PASS: Computation of x^T H x = " + std::to_string(my_sum) + " < 0" (approximate-Hessian) and is therefore concave); - } else { - // print to console the FAILED configuration - info("FAIL: Computation of x^T H x = " + std::to_string(my_sum) + " > 0 (approximate-Hessian) and is therefore NOT concave" + - "\n >target image max=" + std::to_string(target.find_max()) + - "\n >target image min=" + std::to_string(target.find_min())); - } + if (this->check_if_less(my_sum, 0)) + { + // info("PASS: Computation of x^T H x = " + std::to_string(my_sum) + " < 0" (approximate-Hessian) and is therefore + // concave); + } + else + { + // print to console the FAILED configuration + info("FAIL: Computation of x^T H x = " + std::to_string(my_sum) + " > 0 (approximate-Hessian) and is therefore NOT concave" + + "\n >target image max=" + std::to_string(target.find_max()) + + "\n >target image min=" + std::to_string(target.find_min())); + } } - void -PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests:: -construct_input_data(shared_ptr& density_sptr) -{ +PoissonLogLikelihoodWithLinearModelForMeanAndProjDataTests::construct_input_data(shared_ptr& density_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 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) + 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); - } + 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); + 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)); + 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) + for (target_type::full_iterator iter = density_sptr->begin_all(); iter != density_sptr->end_all(); ++iter) *iter = static_cast(random01()); - } else { @@ -316,97 +312,85 @@ construct_input_data(shared_ptr& density_sptr) // 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()); { - mult_proj_data_sptr.reset(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) + mult_proj_data_sptr.reset(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; - } - mult_proj_data_sptr->set_segment(segment); - } + 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; + } + mult_proj_data_sptr->set_segment(segment); + } } bin_norm_sptr.reset(new BinNormalisationFromProjData(mult_proj_data_sptr)); } // additive term - add_proj_data_sptr.reset(new ProjDataInMemory (proj_data_sptr->get_exam_info_sptr(), - proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone())); + add_proj_data_sptr.reset(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 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; - } - add_proj_data_sptr->set_segment(segment); - } + 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; + } + add_proj_data_sptr->set_segment(segment); + } } } objective_function_sptr.reset(new PoissonLogLikelihoodWithLinearModelForMeanAndProjData); - PoissonLogLikelihoodWithLinearModelForMeanAndProjData& objective_function = - reinterpret_cast< PoissonLogLikelihoodWithLinearModelForMeanAndProjData& >(*objective_function_sptr); + PoissonLogLikelihoodWithLinearModelForMeanAndProjData& objective_function + = 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"; @@ -418,29 +402,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_blocks_on_cylindrical_projectors.cxx b/src/recon_test/test_blocks_on_cylindrical_projectors.cxx index 014526190..2d07afcbd 100644 --- a/src/recon_test/test_blocks_on_cylindrical_projectors.cxx +++ b/src/recon_test/test_blocks_on_cylindrical_projectors.cxx @@ -47,8 +47,8 @@ #include "stir/recon_buildblock/ForwardProjectorByBin.h" #include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" #ifdef STIR_WITH_Parallelproj_PROJECTOR -#include "stir/recon_buildblock/Parallelproj_projector/ForwardProjectorByBinParallelproj.h" -#include "stir/recon_buildblock/Parallelproj_projector/BackProjectorByBinParallelproj.h" +# include "stir/recon_buildblock/Parallelproj_projector/ForwardProjectorByBinParallelproj.h" +# include "stir/recon_buildblock/Parallelproj_projector/BackProjectorByBinParallelproj.h" #endif #include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" #include "stir/IO/write_to_file.h" @@ -98,9 +98,13 @@ BlocksTests::set_blocks_projdata_info(shared_ptr scanner_sptr, int bin_ num_axial_pos_per_segment[i] = scanner_sptr->get_num_rings() - abs(i); } - auto proj_data_info_blocks_sptr = std::make_shared( - scanner_sptr, num_axial_pos_per_segment, min_ring_diff_v, max_ring_diff_v, - scanner_sptr->get_max_num_views(), scanner_sptr->get_max_num_non_arccorrected_bins() / bin_fraction); + auto proj_data_info_blocks_sptr + = std::make_shared(scanner_sptr, + num_axial_pos_per_segment, + min_ring_diff_v, + max_ring_diff_v, + scanner_sptr->get_max_num_views(), + scanner_sptr->get_max_num_non_arccorrected_bins() / bin_fraction); return proj_data_info_blocks_sptr; } @@ -126,9 +130,13 @@ BlocksTests::set_direct_projdata_info(shared_ptr scanner_sptr, int bin_ num_axial_pos_per_segment[i] = scanner_sptr->get_num_rings() - abs(i); } - auto proj_data_info_blocks_sptr = std::make_shared( - scanner_sptr, num_axial_pos_per_segment, min_ring_diff_v, max_ring_diff_v, - scanner_sptr->get_max_num_views(), scanner_sptr->get_max_num_non_arccorrected_bins() / bin_fraction); + auto proj_data_info_blocks_sptr + = std::make_shared(scanner_sptr, + num_axial_pos_per_segment, + min_ring_diff_v, + max_ring_diff_v, + scanner_sptr->get_max_num_views(), + scanner_sptr->get_max_num_non_arccorrected_bins() / bin_fraction); return proj_data_info_blocks_sptr; } @@ -155,15 +163,15 @@ BlocksTests::run_symmetry_test(ForwardProjectorByBin& forw_projector1, ForwardPr const IndexRange<3> range(Coordinate3D(0, -45, -44), Coordinate3D(24, 44, 45)); VoxelsOnCartesianGrid image(exam_info_sptr, range, origin, grid_spacing); - const Array<2, float> direction_vectors = make_array(make_1d_array(1.F, 0.F, 0.F), make_1d_array(0.F, cos(theta1), sin(theta1)), - make_1d_array(0.F, -sin(theta1), cos(theta1))); + const Array<2, float> direction_vectors = make_array( + make_1d_array(1.F, 0.F, 0.F), make_1d_array(0.F, cos(theta1), sin(theta1)), make_1d_array(0.F, -sin(theta1), cos(theta1))); Ellipsoid ellipsoid(CartesianCoordinate3D(/*radius_z*/ 6 * grid_spacing.z(), /*radius_y*/ 6 * grid_spacing.y(), /*radius_x*/ 6 * grid_spacing.x()), /*centre*/ - CartesianCoordinate3D((image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), - -34 * grid_spacing.y(), 0), + CartesianCoordinate3D( + (image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), -34 * grid_spacing.y(), 0), direction_vectors); ellipsoid.construct_volume(image, make_coordinate(3, 3, 3)); @@ -176,7 +184,8 @@ BlocksTests::run_symmetry_test(ForwardProjectorByBin& forw_projector1, ForwardPr theta1 = i * _PI / 180; CartesianCoordinate3D origin1((image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), - -34 * grid_spacing.y() * cos(theta1), 34 * grid_spacing.y() * sin(theta1)); + -34 * grid_spacing.y() * cos(theta1), + 34 * grid_spacing.y() * sin(theta1)); ellipsoid.set_origin(origin1); ellipsoid.construct_volume(image1, make_coordinate(3, 3, 3)); @@ -191,7 +200,8 @@ BlocksTests::run_symmetry_test(ForwardProjectorByBin& forw_projector1, ForwardPr theta2 = i * _PI / 180; CartesianCoordinate3D origin2((image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), - -34 * grid_spacing.y() * cos(theta2), 34 * grid_spacing.y() * sin(theta2)); + -34 * grid_spacing.y() * cos(theta2), + 34 * grid_spacing.y() * sin(theta2)); ellipsoid.set_origin(origin2); ellipsoid.construct_volume(image22, make_coordinate(3, 3, 3)); @@ -224,11 +234,11 @@ BlocksTests::run_symmetry_test(ForwardProjectorByBin& forw_projector1, ForwardPr forw_projector2.set_up(proj_data_info_blocks_sptr, image2_sptr); - auto projdata1 = std::make_shared(exam_info_sptr, proj_data_info_blocks_sptr, "sino1_from_image.hs", - std::ios::out | std::ios::trunc | std::ios::in); + auto projdata1 = std::make_shared( + exam_info_sptr, proj_data_info_blocks_sptr, "sino1_from_image.hs", std::ios::out | std::ios::trunc | std::ios::in); - auto projdata2 = std::make_shared(exam_info_sptr, proj_data_info_blocks_sptr, "sino2_from_image.hs", - std::ios::out | std::ios::trunc | std::ios::in); + auto projdata2 = std::make_shared( + exam_info_sptr, proj_data_info_blocks_sptr, "sino2_from_image.hs", std::ios::out | std::ios::trunc | std::ios::in); forw_projector1.forward_project(*projdata1, *image1_sptr); forw_projector2.forward_project(*projdata2, *image2_sptr); @@ -280,16 +290,16 @@ BlocksTests::run_plane_symmetry_test(ForwardProjectorByBin& forw_projector1, For // 60 degrees phi1 = 60 * _PI / 180; - const Array<2, float> direction_vectors - = make_array(make_1d_array(1.F, 0.F, 0.F), make_1d_array(0.F, cos(float(_PI) - phi1), sin(float(_PI) - phi1)), - make_1d_array(0.F, -sin(float(_PI) - phi1), cos(float(_PI) - phi1))); + const Array<2, float> direction_vectors = make_array(make_1d_array(1.F, 0.F, 0.F), + make_1d_array(0.F, cos(float(_PI) - phi1), sin(float(_PI) - phi1)), + make_1d_array(0.F, -sin(float(_PI) - phi1), cos(float(_PI) - phi1))); Ellipsoid plane(CartesianCoordinate3D(/*edge_z*/ 25 * grid_spacing.z(), /*edge_y*/ 91 * grid_spacing.y(), /*edge_x*/ 5 * grid_spacing.x()), /*centre*/ - CartesianCoordinate3D((image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), - 0 * grid_spacing.y(), 0), + CartesianCoordinate3D( + (image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), 0 * grid_spacing.y(), 0), direction_vectors); plane.construct_volume(image, make_coordinate(3, 3, 3)); @@ -297,16 +307,16 @@ BlocksTests::run_plane_symmetry_test(ForwardProjectorByBin& forw_projector1, For // rotate by 30 degrees phi2 = 30 * _PI / 180; VoxelsOnCartesianGrid image2 = *image.get_empty_copy(); - const Array<2, float> direction2 - = make_array(make_1d_array(1.F, 0.F, 0.F), make_1d_array(0.F, cos(float(_PI) - phi2), sin(float(_PI) - phi2)), - make_1d_array(0.F, -sin(float(_PI) - phi2), cos(float(_PI) - phi2))); + const Array<2, float> direction2 = make_array(make_1d_array(1.F, 0.F, 0.F), + make_1d_array(0.F, cos(float(_PI) - phi2), sin(float(_PI) - phi2)), + make_1d_array(0.F, -sin(float(_PI) - phi2), cos(float(_PI) - phi2))); Ellipsoid plane2(CartesianCoordinate3D(/*edge_z*/ 25 * grid_spacing.z(), /*edge_y*/ 91 * grid_spacing.y(), /*edge_x*/ 5 * grid_spacing.x()), /*centre*/ - CartesianCoordinate3D((image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), - 0 * grid_spacing.y(), 0), + CartesianCoordinate3D( + (image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), 0 * grid_spacing.y(), 0), direction2); plane2.construct_volume(image2, make_coordinate(3, 3, 3)); @@ -342,13 +352,13 @@ BlocksTests::run_plane_symmetry_test(ForwardProjectorByBin& forw_projector1, For forw_projector2.set_up(proj_data_info_blocks_sptr, image2_sptr); - auto projdata = std::make_shared(exam_info_sptr, proj_data_info_blocks_sptr, "sino1_from_plane.hs", - std::ios::out | std::ios::trunc | std::ios::in); + auto projdata = std::make_shared( + exam_info_sptr, proj_data_info_blocks_sptr, "sino1_from_plane.hs", std::ios::out | std::ios::trunc | std::ios::in); forw_projector1.forward_project(*projdata, *image_sptr); - auto projdata2 = std::make_shared(exam_info_sptr, proj_data_info_blocks_sptr, "sino2_from_plane.hs", - std::ios::out | std::ios::trunc | std::ios::in); + auto projdata2 = std::make_shared( + exam_info_sptr, proj_data_info_blocks_sptr, "sino2_from_plane.hs", std::ios::out | std::ios::trunc | std::ios::in); forw_projector2.forward_project(*projdata2, *image2_sptr); @@ -462,16 +472,16 @@ BlocksTests::run_axial_projection_test(ForwardProjectorByBin& forw_projector, Ba // 60 degrees float phi1 = 0 * _PI / 180; - const Array<2, float> direction_vectors - = make_array(make_1d_array(1.F, 0.F, 0.F), make_1d_array(0.F, cos(float(_PI) - phi1), sin(float(_PI) - phi1)), - make_1d_array(0.F, -sin(float(_PI) - phi1), cos(float(_PI) - phi1))); + const Array<2, float> direction_vectors = make_array(make_1d_array(1.F, 0.F, 0.F), + make_1d_array(0.F, cos(float(_PI) - phi1), sin(float(_PI) - phi1)), + make_1d_array(0.F, -sin(float(_PI) - phi1), cos(float(_PI) - phi1))); Ellipsoid plane(CartesianCoordinate3D(/*edge_z*/ 50 * grid_spacing.z(), /*edge_y*/ 2 * grid_spacing.y(), /*edge_x*/ 2 * grid_spacing.x()), /*centre*/ - CartesianCoordinate3D((image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), - 0 * grid_spacing.y(), 0), + CartesianCoordinate3D( + (image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), 0 * grid_spacing.y(), 0), direction_vectors); plane.construct_volume(image, make_coordinate(3, 3, 3)); @@ -498,8 +508,8 @@ BlocksTests::run_axial_projection_test(ForwardProjectorByBin& forw_projector, Ba forw_projector.set_up(proj_data_info_blocks_sptr, image_sptr); back_projector.set_up(proj_data_info_blocks_sptr, bck_proj_image_sptr); - auto projdata = std::make_shared(exam_info_sptr, proj_data_info_blocks_sptr, "test_axial.hs", - std::ios::out | std::ios::trunc | std::ios::in); + auto projdata = std::make_shared( + exam_info_sptr, proj_data_info_blocks_sptr, "test_axial.hs", std::ios::out | std::ios::trunc | std::ios::in); forw_projector.forward_project(*projdata, *image_sptr); @@ -521,7 +531,8 @@ BlocksTests::run_axial_projection_test(ForwardProjectorByBin& forw_projector, Ba for (int y = min_y; y < max_y; y++) for (int x = min_x; x < max_x; x++) { - check_if_equal((*bck_proj_image_sptr)[plane_idA][y][x], (*bck_proj_image_sptr)[plane_idB][y][x], + check_if_equal((*bck_proj_image_sptr)[plane_idA][y][x], + (*bck_proj_image_sptr)[plane_idB][y][x], "checking the symmetry along the axial direction"); } } @@ -545,15 +556,15 @@ BlocksTests::run_map_orientation_test(ForwardProjectorByBin& forw_projector1, Fo const IndexRange<3> range(Coordinate3D(0, -45, -44), Coordinate3D(24, 44, 45)); VoxelsOnCartesianGrid image(exam_info_sptr, range, origin, grid_spacing); - const Array<2, float> direction_vectors = make_array(make_1d_array(1.F, 0.F, 0.F), make_1d_array(0.F, cos(theta1), sin(theta1)), - make_1d_array(0.F, -sin(theta1), cos(theta1))); + const Array<2, float> direction_vectors = make_array( + make_1d_array(1.F, 0.F, 0.F), make_1d_array(0.F, cos(theta1), sin(theta1)), make_1d_array(0.F, -sin(theta1), cos(theta1))); Ellipsoid ellipsoid(CartesianCoordinate3D(/*radius_z*/ 6 * grid_spacing.z(), /*radius_y*/ 6 * grid_spacing.y(), /*radius_x*/ 6 * grid_spacing.x()), /*centre*/ - CartesianCoordinate3D((image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), - -34 * grid_spacing.y(), 0), + CartesianCoordinate3D( + (image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), -34 * grid_spacing.y(), 0), direction_vectors); ellipsoid.construct_volume(image, make_coordinate(3, 3, 3)); @@ -565,7 +576,8 @@ BlocksTests::run_map_orientation_test(ForwardProjectorByBin& forw_projector1, Fo theta1 = i * _PI / 180; CartesianCoordinate3D origin1((image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z(), - -34 * grid_spacing.y() * cos(theta1), 34 * grid_spacing.y() * sin(theta1)); + -34 * grid_spacing.y() * cos(theta1), + 34 * grid_spacing.y() * sin(theta1)); ellipsoid.set_origin(origin1); ellipsoid.construct_volume(image1, make_coordinate(3, 3, 3)); @@ -652,7 +664,8 @@ BlocksTests::run_map_orientation_test(ForwardProjectorByBin& forw_projector1, Fo proj_data_info_blocks_sptr->find_bin_given_cartesian_coordinates_of_detection(binR1, rb1, rb2); proj_data_info_blocks_sptr->get_det_pos_pair_for_bin(dpR1, binR1); - check_if_equal(projdata1->get_bin_value(bin1), projdata2->get_bin_value(bin2), + check_if_equal(projdata1->get_bin_value(bin1), + projdata2->get_bin_value(bin2), " checking cartesian coordinate y1 are the same on a flat bucket"); check(b1 != rb1, " checking cartesian coordinate of detector 1 are different if we use a reordered map"); check(b2 != rb2, " checking cartesian coordinate of detector 2 are different if we use a reordered map"); @@ -708,19 +721,21 @@ BlocksTests::run_projection_test(ForwardProjectorByBin& forw_projector1, Forward // info(boost::format("Test blocks on Cylindrical: Forward projector used: %1%") % forw_projector1.parameter_info()); forw_projector1.set_up(proj_data_info_blocks_sptr, image1_sptr); - auto projdata1 = std::make_shared(exam_info_sptr, proj_data_info_blocks_sptr, "sino_with_phantom_at_30_0.hs", - std::ios::out | std::ios::trunc | std::ios::in); + auto projdata1 = std::make_shared( + exam_info_sptr, proj_data_info_blocks_sptr, "sino_with_phantom_at_30_0.hs", std::ios::out | std::ios::trunc | std::ios::in); forw_projector1.forward_project(*projdata1, *image1_sptr); - auto projdata2 = std::make_shared(exam_info_sptr, proj_data_info_blocks_sptr, "sino_with_phantom_at_25_0.hs", - std::ios::out | std::ios::trunc | std::ios::in); + auto projdata2 = std::make_shared( + exam_info_sptr, proj_data_info_blocks_sptr, "sino_with_phantom_at_25_0.hs", std::ios::out | std::ios::trunc | std::ios::in); forw_projector1.forward_project(*projdata2, *image2_sptr); forw_projector2.set_up(proj_data_info_blocks_sptr, image1_sptr); - auto projdata1_parallelproj = std::make_shared(exam_info_sptr, proj_data_info_blocks_sptr, + auto projdata1_parallelproj = std::make_shared(exam_info_sptr, + proj_data_info_blocks_sptr, "sino_with_phantom_at_30_0_parallelproj.hs", std::ios::out | std::ios::trunc | std::ios::in); forw_projector2.forward_project(*projdata1_parallelproj, *image1_sptr); - auto projdata2_parallelproj = std::make_shared(exam_info_sptr, proj_data_info_blocks_sptr, + auto projdata2_parallelproj = std::make_shared(exam_info_sptr, + proj_data_info_blocks_sptr, "sino_with_phantom_at_25_0_parallelproj.hs", std::ios::out | std::ios::trunc | std::ios::in); forw_projector2.forward_project(*projdata2_parallelproj, *image2_sptr); @@ -818,13 +833,15 @@ BlocksTests::run_intersection_with_cylinder_test() { bin.segment_num() = seg; 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()) + 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()) + bin.tangential_pos_num() <= proj_data_info->get_max_tangential_pos_num(); + ++bin.tangential_pos_num()) { proj_data_info->get_LOR(lor, bin); if (lor.get_intersections_with_cylinder(lor_points, radius) == Succeeded::yes diff --git a/src/recon_test/test_consistency_with_GATE.cxx b/src/recon_test/test_consistency_with_GATE.cxx index c04abcbc0..fb9db6493 100644 --- a/src/recon_test/test_consistency_with_GATE.cxx +++ b/src/recon_test/test_consistency_with_GATE.cxx @@ -52,16 +52,17 @@ using std::ifstream; START_NAMESPACE_STIR - class WeightedCoordinate // This class is used to store the coordinates and weight { public: WeightedCoordinate() - : coord(CartesianCoordinate3D(0.f,0.f,0.f)), value(0.f) + : coord(CartesianCoordinate3D(0.f, 0.f, 0.f)), + value(0.f) {} WeightedCoordinate(const CartesianCoordinate3D& voxel_centre_v, const float value_v) - : coord(voxel_centre_v), value(value_v) + : coord(voxel_centre_v), + value(value_v) {} //! Coordinate position @@ -70,11 +71,10 @@ class WeightedCoordinate float value; }; - class GATEConsistencyTests : public RunTests { public: - GATEConsistencyTests()= default; + GATEConsistencyTests() = default; /*! * \brief Run the tests with ROOT data @@ -85,7 +85,6 @@ class GATEConsistencyTests : public RunTests void run_tests() override; private: - /*! Initialise the original point source position by generating image and finding the centre of gravity * and sets TOF and non-TOF threshold distances and the number of events passed and failed counters */ @@ -114,7 +113,6 @@ class GATEConsistencyTests : public RunTests */ void post_processing_nonTOF(); - /*! Test if the voxel with the highest value in the LOR (probabilities) is within TOF_distance_threshold to the original_coords. * If it is, pass with true, otherwise fales. * @param probabilities ProjMatrixElemsForOneBin object of a list mode event @@ -134,7 +132,6 @@ class GATEConsistencyTests : public RunTests std::string get_root_header_filename() { return "pretest_output/root_header_test" + std::to_string(test_index) + ".hroot"; } std::string get_generate_image_par_filename() { return "SourceFiles/generate_image" + std::to_string(test_index) + ".par"; } - ///// Class VARIABLES ///// private: @@ -142,14 +139,15 @@ class GATEConsistencyTests : public RunTests int test_index = 0; int num_tests = 8; - // Test results storage. Records if each test failed or not. E.g.`test_index` result is stored in `test_results_nonTOF[test_index -1]` + // Test results storage. Records if each test failed or not. E.g.`test_index` result is stored in + // `test_results_nonTOF[test_index -1]` std::vector test_results_nonTOF; std::vector test_results_TOF; shared_ptr lm_data_sptr; // Original point source position variables - shared_ptr > discretised_density_sptr; + shared_ptr> discretised_density_sptr; CartesianCoordinate3D original_coords; // Stored in class because of dynamic_cast CartesianCoordinate3D grid_spacing; // Stored in class because of dynamic_cast @@ -180,24 +178,23 @@ class GATEConsistencyTests : public RunTests void GATEConsistencyTests::run_tests() { - test_results_nonTOF = std::vector (num_tests, true); - test_results_TOF = std::vector (num_tests, true); + test_results_nonTOF = std::vector(num_tests, true); + test_results_TOF = std::vector(num_tests, true); cerr << "Testing consistency between GATE/ROOT and STIR. \n"; for (int i = 1; i <= num_tests; ++i) - { - test_index = i; // set the class variable to keep track of which test is being run - cerr << "\nTesting dataset " << std::to_string(test_index) << "...\n"; - setup(); - process_list_data(); - post_processing(); - } + { + test_index = i; // set the class variable to keep track of which test is being run + cerr << "\nTesting dataset " << std::to_string(test_index) << "...\n"; + setup(); + process_list_data(); + post_processing(); + } log_results_to_console(); } void -GATEConsistencyTests:: -setup() +GATEConsistencyTests::setup() { // Initialise the list mode data object lm_data_sptr = read_from_file(get_root_header_filename()); @@ -209,8 +206,8 @@ setup() discretised_density_sptr = image_gen_application.get_output_sptr(); // Needs to be cast to VoxelsOnCartesianGrid to be able to calculate the centre of gravity - const VoxelsOnCartesianGrid &discretised_cartesian_grid = - dynamic_cast &>(*discretised_density_sptr); + const VoxelsOnCartesianGrid& discretised_cartesian_grid + = dynamic_cast&>(*discretised_density_sptr); // Find the center of mass and grid spacing of the original data original_coords = find_centre_of_gravity_in_mm(discretised_cartesian_grid); @@ -241,93 +238,89 @@ setup() } void -GATEConsistencyTests:: -process_list_data() +GATEConsistencyTests::process_list_data() { // Configure the list mode reader shared_ptr proj_matrix_sptr(new ProjMatrixByBinUsingRayTracing()); - proj_matrix_sptr->set_up(lm_data_sptr->get_proj_data_info_sptr(), - discretised_density_sptr); + proj_matrix_sptr->set_up(lm_data_sptr->get_proj_data_info_sptr(), discretised_density_sptr); // loop over all events in the listmode file shared_ptr record_sptr = lm_data_sptr->get_empty_record_sptr(); CListRecord& record = *record_sptr; ProjMatrixElemsForOneBin proj_matrix_row; 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 non-TOF probabilities along the bin LOR - proj_matrix_sptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, bin); - - // Test event for non-TOF consistency - if (!test_nonTOF_LOR_closest_approach(proj_matrix_row)) - num_failed_nonTOF_lor_events += 1; - - // Test TOF aspects of the LOR - if (!test_TOF_max_lor_voxel(proj_matrix_row)) - num_failed_TOF_lor_events += 1; - - // Record as tested event - num_events_tested += 1; - } - } - } + { + // 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 non-TOF probabilities along the bin LOR + proj_matrix_sptr->get_proj_matrix_elems_for_one_bin(proj_matrix_row, bin); + + // Test event for non-TOF consistency + if (!test_nonTOF_LOR_closest_approach(proj_matrix_row)) + num_failed_nonTOF_lor_events += 1; + + // Test TOF aspects of the LOR + if (!test_TOF_max_lor_voxel(proj_matrix_row)) + num_failed_TOF_lor_events += 1; + + // Record as tested event + num_events_tested += 1; + } + } + } } - //// NON-TOF TESTING METHODS //// bool GATEConsistencyTests::test_nonTOF_LOR_closest_approach(const ProjMatrixElemsForOneBin& probabilities) { // Loop variables CartesianCoordinate3D closest_LOR_voxel_to_origin; - float min_distance; // shortest distance to the origin along the LOR + float min_distance; // shortest distance to the origin along the LOR bool first_entry = true; // Use this to populate with the initial value ProjMatrixElemsForOneBin::const_iterator element_ptr = probabilities.begin(); // iterate over all to element_ptr to find the minimal distance between LOR and original_coords while (element_ptr != probabilities.end()) - { - CartesianCoordinate3D voxel_coords = - discretised_density_sptr->get_physical_coordinates_for_indices(element_ptr->get_coords()); - - float dist_to_original = norm(voxel_coords - original_coords); - if (first_entry || (dist_to_original < min_distance)) { - closest_LOR_voxel_to_origin = voxel_coords; - min_distance = dist_to_original; - first_entry = false; + CartesianCoordinate3D voxel_coords + = discretised_density_sptr->get_physical_coordinates_for_indices(element_ptr->get_coords()); + + float dist_to_original = norm(voxel_coords - original_coords); + if (first_entry || (dist_to_original < min_distance)) + { + closest_LOR_voxel_to_origin = voxel_coords; + min_distance = dist_to_original; + first_entry = false; + } + ++element_ptr; } - ++element_ptr; - } // Log closest voxel to origin in vector (value doesn't matter) nonTOF_closest_voxels_list.push_back(closest_LOR_voxel_to_origin); if (min_distance > nonTOF_distance_threshold) return false; // Test failed - LOR closest voxel beyond nonTOF_distance_threshold - return true; // Test passed - LOR closest voxel within nonTOF_distance_threshold + return true; // Test passed - LOR closest voxel within nonTOF_distance_threshold } - void -GATEConsistencyTests:: -post_processing_nonTOF() +GATEConsistencyTests::post_processing_nonTOF() { cerr << "\nNon-TOF number of failed events: " << num_failed_nonTOF_lor_events << "\tNumber of tested events: = " << num_events_tested << std::endl; - test_results_nonTOF[test_index-1] = check_if_less(num_failed_nonTOF_lor_events, failure_tolerance_nonTOF * num_events_tested, - "The number of failed TOF events is more than the tolerance(" + - std::to_string(100*failure_tolerance_nonTOF)+ "%)"); + test_results_nonTOF[test_index - 1] = check_if_less(num_failed_nonTOF_lor_events, + failure_tolerance_nonTOF * num_events_tested, + "The number of failed TOF events is more than the tolerance(" + + std::to_string(100 * failure_tolerance_nonTOF) + "%)"); { // Save the closest coordinate for each LOR to file. std::string lor_pos_filename = "non_TOF_voxel_data_" + std::to_string(test_index) + ".csv"; @@ -341,7 +334,7 @@ post_processing_nonTOF() // The second entry is the original coords myfile << "original coordinates," << original_coords.x() << "," << original_coords.y() << "," << original_coords.z() << "\n"; int i = 0; - for (auto & entry : nonTOF_closest_voxels_list) + for (auto& entry : nonTOF_closest_voxels_list) { myfile << i << "," << entry.x() << "," << entry.y() << "," << entry.z() << "\n"; i++; @@ -351,8 +344,7 @@ post_processing_nonTOF() } void -GATEConsistencyTests:: -post_processing() +GATEConsistencyTests::post_processing() { cerr << "\nResults for dataset: " << std::to_string(this->test_index) << std::endl; post_processing_nonTOF(); @@ -361,15 +353,15 @@ post_processing() //// TOF TESTING METHODS //// bool -GATEConsistencyTests:: -test_TOF_max_lor_voxel(const ProjMatrixElemsForOneBin& probabilities) +GATEConsistencyTests::test_TOF_max_lor_voxel(const ProjMatrixElemsForOneBin& probabilities) { // Along a TOF LOR (probabilities), values assigned to voxels (or positions used here). // This method finds highest value voxel(s). // There may be more than one voxel with the highest value. // Everytime a new highest voxel value is found, sum_weighted_position is re-set to that value. // If a voxel is found with the same value as in sum_weighted_position, the coordinates are added. - // At the end of the loop, divide the coordinates by `num_max_value_elements` and add to the list of max_value_voxels, 1 value per event. + // At the end of the loop, divide the coordinates by `num_max_value_elements` and add to the list of max_value_voxels, 1 value + // per event. // Loop variables ProjMatrixElemsForOneBin::const_iterator element_ptr = probabilities.begin(); @@ -377,22 +369,23 @@ test_TOF_max_lor_voxel(const ProjMatrixElemsForOneBin& probabilities) WeightedCoordinate sum_weighted_position(CartesianCoordinate3D(0, 0, 0), 0); while (element_ptr != probabilities.end()) - { - if (element_ptr->get_value() > sum_weighted_position.value) - { - // New highest value found, set sum_weighted_position to new value - sum_weighted_position.coord = discretised_density_sptr->get_physical_coordinates_for_indices(element_ptr->get_coords()); - sum_weighted_position.value = element_ptr->get_value(); - num_max_value_elements = 1; - } - else if (element_ptr->get_value() == sum_weighted_position.value) { - // Same value found, add coordinates to sum_weighted_position (will divide later) - sum_weighted_position.coord += discretised_density_sptr->get_physical_coordinates_for_indices(element_ptr->get_coords()); - num_max_value_elements++; + if (element_ptr->get_value() > sum_weighted_position.value) + { + // New highest value found, set sum_weighted_position to new value + sum_weighted_position.coord = discretised_density_sptr->get_physical_coordinates_for_indices(element_ptr->get_coords()); + sum_weighted_position.value = element_ptr->get_value(); + num_max_value_elements = 1; + } + else if (element_ptr->get_value() == sum_weighted_position.value) + { + // Same value found, add coordinates to sum_weighted_position (will divide later) + sum_weighted_position.coord + += discretised_density_sptr->get_physical_coordinates_for_indices(element_ptr->get_coords()); + num_max_value_elements++; + } + ++element_ptr; } - ++element_ptr; - } // Divide sum_weighted_position by num_max_value_elements to get the COM position sum_weighted_position.coord /= num_max_value_elements; @@ -402,20 +395,19 @@ test_TOF_max_lor_voxel(const ProjMatrixElemsForOneBin& probabilities) // Check if the COM position is within the TOF_distance_threshold tolerance if (norm(original_coords - sum_weighted_position.coord) > TOF_distance_threshold) return false; // Test failed - LOR closest voxel beyond tof_distance_threshold - return true; // Test passed - LOR closest voxel within tof_distance_threshold + return true; // Test passed - LOR closest voxel within tof_distance_threshold } - void -GATEConsistencyTests:: -post_processing_TOF() +GATEConsistencyTests::post_processing_TOF() { - cerr << "\nTOF number of failed events: " << num_failed_TOF_lor_events - << "\tNumber of tested events: = " << num_events_tested << std::endl; + cerr << "\nTOF number of failed events: " << num_failed_TOF_lor_events << "\tNumber of tested events: = " << num_events_tested + << std::endl; - test_results_TOF[test_index-1] = check_if_less(num_failed_TOF_lor_events, failure_tolerance_TOF * num_events_tested, - "The number of failed TOF events is more than the tolerance(" + - std::to_string(100*failure_tolerance_nonTOF)+ "%)"); + test_results_TOF[test_index - 1] = check_if_less(num_failed_TOF_lor_events, + failure_tolerance_TOF * num_events_tested, + "The number of failed TOF events is more than the tolerance(" + + std::to_string(100 * failure_tolerance_nonTOF) + "%)"); { // Save the closest coordinate for each LOR to file. std::string lor_pos_filename = "TOF_voxel_data_" + std::to_string(test_index) + ".csv"; @@ -430,7 +422,7 @@ post_processing_TOF() // The second entry is the original coords myfile << "original coordinates," << original_coords.x() << "," << original_coords.y() << "," << original_coords.z() << "\n"; int i = 0; - for (auto & entry : TOF_LOR_peak_value_coords) + for (auto& entry : TOF_LOR_peak_value_coords) { myfile << i << "," << entry.coord.x() << "," << entry.coord.y() << "," << entry.coord.z() << "\n"; i++; @@ -440,8 +432,7 @@ post_processing_TOF() } void -GATEConsistencyTests:: -log_results_to_console() +GATEConsistencyTests::log_results_to_console() { // Print results for easy readability cerr << "\nTest Results\n" @@ -449,14 +440,14 @@ log_results_to_console() "\tTest Index\t|\tnonTOF\t|\tTOF\n" "------------------------------------------\n"; for (int j = 0; j < num_tests; ++j) - cerr << "\t\t" << std::to_string(j + 1) << "\t\t|\t" - << ((test_results_nonTOF[j]) ? "Pass" : "Fail") << "\t|\t" + cerr << "\t\t" << std::to_string(j + 1) << "\t\t|\t" << ((test_results_nonTOF[j]) ? "Pass" : "Fail") << "\t|\t" << ((test_results_TOF[j]) ? "Pass" : "Fail") << std::endl; } END_NAMESPACE_STIR -int main(int argc, char **argv) +int +main(int argc, char** argv) { USING_NAMESPACE_STIR // Should be called from `${STIR_SOURCE_PATH}/examples/ROOT_files/ROOT_STIR_consistency` diff --git a/src/recon_test/test_data_processor_projectors.cxx b/src/recon_test/test_data_processor_projectors.cxx index 576335843..65ddb50c2 100644 --- a/src/recon_test/test_data_processor_projectors.cxx +++ b/src/recon_test/test_data_processor_projectors.cxx @@ -29,185 +29,187 @@ START_NAMESPACE_STIR 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); - ~TestDataProcessorProjectors() override {} + ~TestDataProcessorProjectors() override {} + + void run_tests() override; - void run_tests() override; 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) +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()); - - 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); + // 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()); + + 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); } -static -void -compare_images(bool &everything_ok, const DiscretisedDensity<3,float> &im_1, const DiscretisedDensity<3,float> &im_2) +static void +compare_images(bool& everything_ok, const DiscretisedDensity<3, float>& im_1, const DiscretisedDensity<3, float>& im_2) { - std::cout << "\nComparing images...\n"; + std::cout << "\nComparing images...\n"; - if (!im_1.has_same_characteristics(im_2)) { - std::cout << "\nImages have different characteristics!\n"; - everything_ok = false; + 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; + 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; + // 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) +static void +compare_sinos(bool& everything_ok, const ProjData& proj_data_1, const ProjData& proj_data_2) { - std::cout << "\nComparing sinograms...\n"; + 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; + 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; + 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() +TestDataProcessorProjectors::run_tests() { - try { - // Open sinogram - _input_sino_sptr = ProjData::read_from_file(_sinogram_filename); + 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(); + // 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]); + // 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 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]); + // 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 (const std::exception& error) + { + std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; + everything_ok = false; } - catch(...) { - everything_ok = false; + catch (...) + { + everything_ok = false; } } -static -void -get_data_processor(shared_ptr > > &data_processor_sptr, const float fwhm) +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); + 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 +static shared_ptr get_back_projector_via_parser(const float fwhm = -1.f) { - std::string buffer; - std::stringstream parameterstream(buffer); + std::string buffer; + std::stringstream parameterstream(buffer); - parameterstream << "Back Projector parameters:=\n"; - if (fwhm > 0) - parameterstream - << "Post Data Processor := Separable Cartesian Metz\n" + 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" @@ -216,29 +218,26 @@ 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 +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" + 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" @@ -247,122 +246,122 @@ 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) +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 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); - - - 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]); + // 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 < sinos.size(); ++i) + { + + // 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()); + + // 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]); + + // 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]); + // Forward project + projectors[i]->set_input(*images[i]); + projectors[i]->forward_project(*sinos[i]); } - return sinos; + return sinos; } -const std::vector > > -TestDataProcessorProjectors:: -post_data_processor_bck_proj() +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]); + // 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) +int +main(int argc, char** argv) { - if (argc < 2 || argc > 3) { - std::cerr << "\n\tUsage: " << argv[0] << " sinogram [fwhm]\n"; - return EXIT_FAILURE; + 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 1b2e33aad..fbdcd903b 100644 --- a/src/recon_test/test_priors.cxx +++ b/src/recon_test/test_priors.cxx @@ -11,13 +11,13 @@ \file \ingroup recon_test - + \brief Test program for stir::QuadraticPrior, stir::RelativeDifferencePrior, and stir::LogcoshPrior \par Usage
      -  test_priors [ density_filename ] 
      +  test_priors [ density_filename ]
         
      where the argument is optional. See the class documentation for more info. @@ -45,13 +45,12 @@ 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. Additionally, the Hessian's convexity is tested, via GeneralisedPrior::accumulate_Hessian_times_input(), by evaluating the x^T Hx > 0 constraint. @@ -62,13 +61,13 @@ 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. */ - explicit GeneralisedPriorTests(char const * density_filename = nullptr); - typedef DiscretisedDensity<3,float> target_type; + explicit GeneralisedPriorTests(char const* density_filename = nullptr); + typedef DiscretisedDensity<3, float> target_type; void construct_input_data(shared_ptr& density_sptr); void run_tests() override; @@ -77,8 +76,8 @@ class GeneralisedPriorTests : public RunTests void configure_prior_tests(bool gradient, bool Hessian_convexity, bool Hessian_numerical); 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 */ @@ -117,8 +116,10 @@ class GeneralisedPriorTests : public RunTests GeneralisedPrior& objective_function, const shared_ptr& target_sptr, float beta, - float input_multiplication, float input_addition, - float current_image_multiplication, float current_image_addition); + float input_multiplication, + float input_addition, + float current_image_multiplication, + float current_image_addition); //! Variables to control which tests are run, see the set methods //@{ @@ -128,9 +129,8 @@ class GeneralisedPriorTests : public RunTests //@} }; -GeneralisedPriorTests:: -GeneralisedPriorTests(char const * const density_filename) - : density_filename(density_filename) +GeneralisedPriorTests::GeneralisedPriorTests(char const* const density_filename) + : density_filename(density_filename) {} void @@ -142,102 +142,100 @@ GeneralisedPriorTests::configure_prior_tests(const bool gradient, const bool Hes } void -GeneralisedPriorTests:: -run_tests_for_objective_function(const std::string& test_name, - GeneralisedPrior& objective_function, - const shared_ptr& target_sptr) +GeneralisedPriorTests::run_tests_for_objective_function(const std::string& test_name, + GeneralisedPrior& objective_function, + const 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; if (do_test_gradient) - { - std::cerr << "----- test " << test_name << " --> Gradient\n"; - test_gradient(test_name, objective_function, target_sptr); - } + { + std::cerr << "----- test " << test_name << " --> Gradient\n"; + test_gradient(test_name, objective_function, target_sptr); + } if (do_test_Hessian_convexity) - { - std::cerr << "----- test " << test_name << " --> Hessian-vector product for convexity\n"; - test_Hessian_convexity(test_name, objective_function, target_sptr); - } + { + std::cerr << "----- test " << test_name << " --> Hessian-vector product for convexity\n"; + test_Hessian_convexity(test_name, objective_function, target_sptr); + } if (do_test_Hessian_against_numerical) - { - std::cerr << "----- test " << test_name << " --> Hessian against numerical\n"; - test_Hessian_against_numerical(test_name, objective_function, target_sptr); - } + { + std::cerr << "----- test " << test_name << " --> Hessian against numerical\n"; + test_Hessian_against_numerical(test_name, objective_function, target_sptr); + } } - void -GeneralisedPriorTests:: -test_gradient(const std::string& test_name, - GeneralisedPrior& objective_function, - const shared_ptr& target_sptr) +GeneralisedPriorTests::test_gradient(const std::string& test_name, + GeneralisedPrior& objective_function, + const shared_ptr& target_sptr) { // setup images target_type& target(*target_sptr); 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); const int verbosity_default = Verbosity::get(); Verbosity::set(0); objective_function.compute_gradient(*gradient_sptr, target); Verbosity::set(verbosity_default); - 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 auto 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("Computing gradient of objective function by numerical differences (this will take a while)", 3); + while (target_iter != target.end_all()) // && testOK) { - ++gradient_2_iter; ++target_iter; ++ gradient_iter; + 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 auto 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) - { - std::cerr << "Numerical gradient test failed with for " + test_name + " prior\n"; - 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); - } + { + std::cerr << "Numerical gradient test failed with for " + test_name + " prior\n"; + 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:: -test_Hessian_convexity(const std::string& test_name, - GeneralisedPrior& objective_function, - const shared_ptr& target_sptr) +GeneralisedPriorTests::test_Hessian_convexity(const std::string& test_name, + GeneralisedPrior& objective_function, + const shared_ptr& target_sptr) { if (!objective_function.is_convex()) return; /// Construct configurations - float beta_array[] = {0.01, 1, 100}; // Penalty strength should only affect scale + float beta_array[] = { 0.01, 1, 100 }; // Penalty strength should only affect scale // Modifications to the input image - float input_multiplication_array[] = {-100, -1, 0.01, 1, 100}; // Test negative, small and large values - float input_addition_array[] = {-10, -1, -0.5, 0.0, 1, 10}; + float input_multiplication_array[] = { -100, -1, 0.01, 1, 100 }; // Test negative, small and large values + float input_addition_array[] = { -10, -1, -0.5, 0.0, 1, 10 }; // Modifications to the current image (Hessian computation) - float current_image_multiplication_array[] = {0.01, 1, 100}; - float current_image_addition_array[] = {0.0, 0.5, 1, 10}; // RDP has constraint that current_image is non-negative + float current_image_multiplication_array[] = { 0.01, 1, 100 }; + float current_image_addition_array[] = { 0.0, 0.5, 1, 10 }; // RDP has constraint that current_image is non-negative bool testOK = true; float initial_beta = objective_function.get_penalisation_factor(); @@ -245,25 +243,32 @@ test_Hessian_convexity(const std::string& test_name, for (float input_multiplication : input_multiplication_array) for (float input_addition : input_addition_array) for (float current_image_multiplication : current_image_multiplication_array) - for (float current_image_addition : current_image_addition_array) { - if (testOK) // only compute configuration if testOK from previous tests - testOK = test_Hessian_convexity_configuration(test_name, objective_function, target_sptr, - beta, - input_multiplication, input_addition, - current_image_multiplication, current_image_addition); - } + for (float current_image_addition : current_image_addition_array) + { + if (testOK) // only compute configuration if testOK from previous tests + testOK = test_Hessian_convexity_configuration(test_name, + objective_function, + target_sptr, + beta, + input_multiplication, + input_addition, + current_image_multiplication, + current_image_addition); + } /// Reset beta to original value objective_function.set_penalisation_factor(initial_beta); } bool -GeneralisedPriorTests:: -test_Hessian_convexity_configuration(const std::string& test_name, - GeneralisedPrior& objective_function, - const shared_ptr& target_sptr, - const float beta, - const float input_multiplication, const float input_addition, - const float current_image_multiplication, const float current_image_addition) +GeneralisedPriorTests::test_Hessian_convexity_configuration( + const std::string& test_name, + GeneralisedPrior& objective_function, + const shared_ptr& target_sptr, + const float beta, + const float input_multiplication, + const float input_addition, + const float current_image_multiplication, + const float current_image_addition) { /// setup targets target_type& target(*target_sptr); @@ -277,14 +282,15 @@ test_Hessian_convexity_configuration(const std::string& test_name, target_type::full_iterator current_image_iter = current_image->begin_all(); target_type::full_iterator target_iter = target.begin_all(); while (input_iter != input->end_all()) - { - *input_iter = input_multiplication * *target_iter + input_addition; - *current_image_iter = current_image_multiplication * *target_iter + current_image_addition; - ++input_iter; ++target_iter; ++current_image_iter; - } + { + *input_iter = input_multiplication * *target_iter + input_addition; + *current_image_iter = current_image_multiplication * *target_iter + current_image_addition; + ++input_iter; + ++target_iter; + ++current_image_iter; + } } - /// Compute H x objective_function.accumulate_Hessian_times_input(*output, *current_image, *input); @@ -294,32 +300,28 @@ test_Hessian_convexity_configuration(const std::string& test_name, const double my_norm2 = std::inner_product(input->begin_all(), input->end_all(), input->begin_all(), double(0)); // test for a CONVEX function: 0 < my_sum, but we allow for some numerical error - if (this->check_if_less(-my_norm2*2E-4, my_sum)) { - return true; - } else { - // print to console the FAILED configuration - info("FAIL: Computation of x^T H x = " + std::to_string(my_sum) + " < 0 and is therefore NOT convex" + - "\ntest_name=" + test_name + - "\nbeta=" + std::to_string(beta) + - "\ninput_multiplication=" + std::to_string(input_multiplication) + - "\ninput_addition=" + std::to_string(input_addition) + - "\ncurrent_image_multiplication=" + std::to_string(current_image_multiplication) + - "\ncurrent_image_addition=" + std::to_string(current_image_addition) + - "\n >input image max=" + std::to_string(input->find_max()) + - "\n >input image min=" + std::to_string(input->find_min()) + - "\n >input image norm^2=" + std::to_string(my_norm2) + - "\n >target image max=" + std::to_string(target.find_max()) + - "\n >target image min=" + std::to_string(target.find_min())); - return false; - } + if (this->check_if_less(-my_norm2 * 2E-4, my_sum)) + { + return true; + } + else + { + // print to console the FAILED configuration + info("FAIL: Computation of x^T H x = " + std::to_string(my_sum) + " < 0 and is therefore NOT convex" + "\ntest_name=" + + test_name + "\nbeta=" + std::to_string(beta) + "\ninput_multiplication=" + std::to_string(input_multiplication) + + "\ninput_addition=" + std::to_string(input_addition) + "\ncurrent_image_multiplication=" + + std::to_string(current_image_multiplication) + "\ncurrent_image_addition=" + std::to_string(current_image_addition) + + "\n >input image max=" + std::to_string(input->find_max()) + "\n >input image min=" + + std::to_string(input->find_min()) + "\n >input image norm^2=" + std::to_string(my_norm2) + "\n >target image max=" + + std::to_string(target.find_max()) + "\n >target image min=" + std::to_string(target.find_min())); + return false; + } } - void -GeneralisedPriorTests:: -test_Hessian_against_numerical(const std::string &test_name, - GeneralisedPrior &objective_function, - const shared_ptr& target_sptr) +GeneralisedPriorTests::test_Hessian_against_numerical(const std::string& test_name, + GeneralisedPrior& objective_function, + const shared_ptr& target_sptr) { if (!objective_function.is_convex()) return; @@ -331,7 +333,7 @@ test_Hessian_against_numerical(const std::string &test_name, // setup images target_type& input(*target_sptr->get_empty_copy()); - input += *target_sptr; // make input have same values as target_sptr + input += *target_sptr; // make input have same values as target_sptr shared_ptr gradient_sptr(target_sptr->get_empty_copy()); shared_ptr pert_grad_and_numerical_Hessian_sptr(target_sptr->get_empty_copy()); shared_ptr Hessian_sptr(target_sptr->get_empty_copy()); @@ -339,7 +341,7 @@ test_Hessian_against_numerical(const std::string &test_name, Verbosity::set(0); objective_function.compute_gradient(*gradient_sptr, input); Verbosity::set(verbosity_default); -// this->set_tolerance(std::max(fabs(double(gradient_sptr->find_min())), fabs(double(gradient_sptr->find_max()))) /10); + // this->set_tolerance(std::max(fabs(double(gradient_sptr->find_min())), fabs(double(gradient_sptr->find_max()))) /10); // Setup coordinates (z,y,x) for perturbation test (Hessian will also be computed w.r.t this voxel, j) BasicCoordinate<3, int> perturbation_coords; @@ -353,63 +355,65 @@ test_Hessian_against_numerical(const std::string &test_name, const int max_x = input[min_z][min_y].get_max_index(); // Loop over each voxel j in the input and check perturbation response. - 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 (testOK) - { - perturbation_coords[1] = z; perturbation_coords[2] = y; perturbation_coords[3] = x; - - // Compute H(x)_j (row of the Hessian at the jth voxel) - objective_function.compute_Hessian(*Hessian_sptr, perturbation_coords, input); - this->set_tolerance(std::max(fabs(double(Hessian_sptr->find_min())), fabs(double(Hessian_sptr->find_max()))) /500); - - // Compute g(x + eps) - Verbosity::set(0); - // Perturb target at jth voxel, compute perturbed gradient, and reset voxel to original value - float perturbed_voxels_original_value = input[perturbation_coords[1]][perturbation_coords[2]][perturbation_coords[3]]; - input[perturbation_coords[1]][perturbation_coords[2]][perturbation_coords[3]] += eps; - objective_function.compute_gradient(*pert_grad_and_numerical_Hessian_sptr, input); - input[perturbation_coords[1]][perturbation_coords[2]][perturbation_coords[3]] = perturbed_voxels_original_value; - - // Now compute the numerical-Hessian = (g(x+eps) - g(x))/eps - *pert_grad_and_numerical_Hessian_sptr -= *gradient_sptr; - *pert_grad_and_numerical_Hessian_sptr /= eps; - - Verbosity::set(verbosity_default); - // Test if pert_grad_and_numerical_Hessian_sptr is all zeros. - // This can happen if the eps is too small. This is a quick test that allows for easier debugging. - if (pert_grad_and_numerical_Hessian_sptr->sum_positive() == 0.0 && Hessian_sptr->sum_positive() > 0.0) { - this->everything_ok = false; - testOK = false; - info("test_Hessian_against_numerical: failed because all values are 0 in numerical Hessian"); + perturbation_coords[1] = z; + perturbation_coords[2] = y; + perturbation_coords[3] = x; + + // Compute H(x)_j (row of the Hessian at the jth voxel) + objective_function.compute_Hessian(*Hessian_sptr, perturbation_coords, input); + this->set_tolerance(std::max(fabs(double(Hessian_sptr->find_min())), fabs(double(Hessian_sptr->find_max()))) / 500); + + // Compute g(x + eps) + Verbosity::set(0); + // Perturb target at jth voxel, compute perturbed gradient, and reset voxel to original value + float perturbed_voxels_original_value = input[perturbation_coords[1]][perturbation_coords[2]][perturbation_coords[3]]; + input[perturbation_coords[1]][perturbation_coords[2]][perturbation_coords[3]] += eps; + objective_function.compute_gradient(*pert_grad_and_numerical_Hessian_sptr, input); + input[perturbation_coords[1]][perturbation_coords[2]][perturbation_coords[3]] = perturbed_voxels_original_value; + + // Now compute the numerical-Hessian = (g(x+eps) - g(x))/eps + *pert_grad_and_numerical_Hessian_sptr -= *gradient_sptr; + *pert_grad_and_numerical_Hessian_sptr /= eps; + + Verbosity::set(verbosity_default); + // Test if pert_grad_and_numerical_Hessian_sptr is all zeros. + // This can happen if the eps is too small. This is a quick test that allows for easier debugging. + if (pert_grad_and_numerical_Hessian_sptr->sum_positive() == 0.0 && Hessian_sptr->sum_positive() > 0.0) + { + this->everything_ok = false; + testOK = false; + info("test_Hessian_against_numerical: failed because all values are 0 in numerical Hessian"); + } + + // Loop over each of the voxels and compare the numerical-Hessian with Hessian + target_type::full_iterator numerical_Hessian_iter = pert_grad_and_numerical_Hessian_sptr->begin_all(); + target_type::full_iterator Hessian_iter = Hessian_sptr->begin_all(); + while (numerical_Hessian_iter != pert_grad_and_numerical_Hessian_sptr->end_all()) + { + testOK = testOK && this->check_if_equal(*Hessian_iter, *numerical_Hessian_iter, "Hessian"); + ++numerical_Hessian_iter; + ++Hessian_iter; + } + + if (!testOK) + { + // Output volumes for debug + std::cerr << "Numerical-Hessian test failed with for " + test_name + " prior\n"; + info("Writing diagnostic files `Hessian_" + test_name + ".hv` and `numerical_Hessian_" + test_name + ".hv`"); + write_to_file("Hessian_" + test_name + ".hv", *Hessian_sptr); + write_to_file("numerical_Hessian_" + test_name + ".hv", *pert_grad_and_numerical_Hessian_sptr); + write_to_file("input_" + test_name + ".hv", input); + } } - - // Loop over each of the voxels and compare the numerical-Hessian with Hessian - target_type::full_iterator numerical_Hessian_iter = pert_grad_and_numerical_Hessian_sptr->begin_all(); - target_type::full_iterator Hessian_iter = Hessian_sptr->begin_all(); - while(numerical_Hessian_iter != pert_grad_and_numerical_Hessian_sptr->end_all()) - { - testOK = testOK && this->check_if_equal(*Hessian_iter, *numerical_Hessian_iter, "Hessian"); - ++numerical_Hessian_iter; ++ Hessian_iter; - } - - if (!testOK) - { - // Output volumes for debug - std::cerr << "Numerical-Hessian test failed with for " + test_name + " prior\n"; - info("Writing diagnostic files `Hessian_" + test_name + ".hv` and `numerical_Hessian_" + test_name + ".hv`"); - write_to_file("Hessian_" + test_name + ".hv", *Hessian_sptr); - write_to_file("numerical_Hessian_" + test_name + ".hv", *pert_grad_and_numerical_Hessian_sptr); - write_to_file("input_" + test_name + ".hv", input); - } - } } void -GeneralisedPriorTests:: -construct_input_data(shared_ptr& density_sptr) +GeneralisedPriorTests::construct_input_data(shared_ptr& density_sptr) { if (this->density_filename == nullptr) { @@ -417,20 +421,18 @@ construct_input_data(shared_ptr& density_sptr) 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)); + 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) + for (target_type::full_iterator iter = density_sptr->begin_all(); iter != density_sptr->end_all(); ++iter) *iter = static_cast(random01()); - } else { @@ -441,8 +443,7 @@ construct_input_data(shared_ptr& density_sptr) } void -GeneralisedPriorTests:: -run_tests() +GeneralisedPriorTests::run_tests() { shared_ptr density_sptr; construct_input_data(density_sptr); @@ -471,7 +472,7 @@ run_tests() std::cerr << "\n\nTests for PLSPrior\n"; { PLSPrior objective_function(false, 1.F); - shared_ptr > anatomical_image_sptr(density_sptr->get_empty_copy()); + 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); // Disabled PLS due to known issue @@ -485,18 +486,18 @@ run_tests() this->configure_prior_tests(true, true, true); 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] : nullptr); + GeneralisedPriorTests tests(argc > 1 ? argv[1] : nullptr); tests.run_tests(); return tests.main_return_value(); } diff --git a/src/scatter_buildblock/CreateTailMaskFromACFs.cxx b/src/scatter_buildblock/CreateTailMaskFromACFs.cxx index f5bdd2c05..65a249dc0 100644 --- a/src/scatter_buildblock/CreateTailMaskFromACFs.cxx +++ b/src/scatter_buildblock/CreateTailMaskFromACFs.cxx @@ -16,179 +16,144 @@ START_NAMESPACE_STIR void -CreateTailMaskFromACFs:: -set_input_projdata_sptr(shared_ptr & arg) +CreateTailMaskFromACFs::set_input_projdata_sptr(shared_ptr& arg) { - this->ACF_sptr = arg; + this->ACF_sptr = arg; } void -CreateTailMaskFromACFs:: -set_input_projdata(std::string& arg) +CreateTailMaskFromACFs::set_input_projdata(std::string& arg) { - this->ACF_sptr = - ProjData::read_from_file(arg); + this->ACF_sptr = ProjData::read_from_file(arg); } void -CreateTailMaskFromACFs:: -set_output_projdata_sptr(shared_ptr& arg) +CreateTailMaskFromACFs::set_output_projdata_sptr(shared_ptr& arg) { - this->mask_proj_data = arg; + this->mask_proj_data = arg; } void -CreateTailMaskFromACFs:: -set_output_projdata(std::string& 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)); + 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() +CreateTailMaskFromACFs::get_output_projdata_sptr() { - return this->mask_proj_data; + return this->mask_proj_data; } void -CreateTailMaskFromACFs:: -set_defaults() +CreateTailMaskFromACFs::set_defaults() { - ACF_threshold = 1.1F; - safety_margin = 4; + ACF_threshold = 1.1F; + safety_margin = 4; } -CreateTailMaskFromACFs:: -CreateTailMaskFromACFs() +CreateTailMaskFromACFs::CreateTailMaskFromACFs() { - this->set_defaults(); + this->set_defaults(); } void -CreateTailMaskFromACFs:: -initialise_keymap() +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); + 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() +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 (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->_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() +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()) + 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()) { - 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 50267c9ab..0356c2be5 100644 --- a/src/scatter_buildblock/ScatterEstimation.cxx +++ b/src/scatter_buildblock/ScatterEstimation.cxx @@ -54,136 +54,100 @@ START_NAMESPACE_STIR void -ScatterEstimation:: -set_defaults() +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->restart_reconstruction_every_scatter_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; + 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->restart_reconstruction_every_scatter_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() +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("restart reconstruction every scatter iteration", - &this->restart_reconstruction_every_scatter_iteration); - 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); + 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("restart reconstruction every scatter iteration", &this->restart_reconstruction_every_scatter_iteration); + 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() +ScatterEstimation::ScatterEstimation() { - this->set_defaults(); + 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())) @@ -192,195 +156,184 @@ ScatterEstimation(const std::string& parameter_filename) } } - -shared_ptr -ScatterEstimation:: -make_2D_projdata_sptr(const shared_ptr in_3d_sptr) +shared_ptr +ScatterEstimation::make_2D_projdata_sptr(const shared_ptr in_3d_sptr) { - shared_ptr out_2d_sptr; - if (in_3d_sptr->get_proj_data_info_sptr()->get_scanner_sptr()->get_scanner_geometry()=="Cylindrical") + shared_ptr out_2d_sptr; + if (in_3d_sptr->get_proj_data_info_sptr()->get_scanner_sptr()->get_scanner_geometry() == "Cylindrical") { - shared_ptr out_info_2d_sptr(SSRB(*in_3d_sptr->get_proj_data_info_sptr(),in_3d_sptr->get_num_segments(), 1, false)); - out_2d_sptr.reset(new ProjDataInMemory(in_3d_sptr->get_exam_info_sptr(), - out_info_2d_sptr)); - - SSRB(*out_2d_sptr, - *in_3d_sptr,false); + shared_ptr out_info_2d_sptr( + SSRB(*in_3d_sptr->get_proj_data_info_sptr(), in_3d_sptr->get_num_segments(), 1, false)); + out_2d_sptr.reset(new ProjDataInMemory(in_3d_sptr->get_exam_info_sptr(), out_info_2d_sptr)); + + SSRB(*out_2d_sptr, *in_3d_sptr, false); } - else - { - shared_ptr out_info_2d_sptr(in_3d_sptr->get_proj_data_info_sptr()->create_shared_clone()); - out_info_2d_sptr->reduce_segment_range(0,0); - out_2d_sptr.reset(new ProjDataInMemory(in_3d_sptr->get_exam_info_sptr(), - out_info_2d_sptr)); - - SegmentBySinogram segment=in_3d_sptr->get_segment_by_sinogram(0); - out_2d_sptr->set_segment(segment); -// std::cout<<" value "<get_sinogram(8,0)[0][0]< out_info_2d_sptr(in_3d_sptr->get_proj_data_info_sptr()->create_shared_clone()); + out_info_2d_sptr->reduce_segment_range(0, 0); + out_2d_sptr.reset(new ProjDataInMemory(in_3d_sptr->get_exam_info_sptr(), out_info_2d_sptr)); + + SegmentBySinogram segment = in_3d_sptr->get_segment_by_sinogram(0); + out_2d_sptr->set_segment(segment); + // std::cout<<" value "<get_sinogram(8,0)[0][0]< -ScatterEstimation:: -make_2D_projdata_sptr(const shared_ptr in_3d_sptr, string template_filename) +shared_ptr +ScatterEstimation::make_2D_projdata_sptr(const shared_ptr in_3d_sptr, string template_filename) { - shared_ptr out_2d_sptr; - if (in_3d_sptr->get_proj_data_info_sptr()->get_scanner_sptr()->get_scanner_geometry()=="Cylindrical") + shared_ptr out_2d_sptr; + if (in_3d_sptr->get_proj_data_info_sptr()->get_scanner_sptr()->get_scanner_geometry() == "Cylindrical") { - shared_ptr out_info_2d_sptr(SSRB(*in_3d_sptr->get_proj_data_info_sptr(),in_3d_sptr->get_num_segments(), 1, false)); - out_2d_sptr = create_new_proj_data(template_filename, - this->input_projdata_2d_sptr->get_exam_info_sptr(), - this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone()); - - SSRB(*out_2d_sptr, - *in_3d_sptr,false); + shared_ptr out_info_2d_sptr( + SSRB(*in_3d_sptr->get_proj_data_info_sptr(), in_3d_sptr->get_num_segments(), 1, false)); + out_2d_sptr = create_new_proj_data(template_filename, + this->input_projdata_2d_sptr->get_exam_info_sptr(), + this->input_projdata_2d_sptr->get_proj_data_info_sptr()->create_shared_clone()); + + SSRB(*out_2d_sptr, *in_3d_sptr, false); } - else - { - shared_ptr out_info_2d_sptr(in_3d_sptr->get_proj_data_info_sptr()->create_shared_clone()); - out_info_2d_sptr->reduce_segment_range(0,0); - out_2d_sptr.reset(new ProjDataInMemory(in_3d_sptr->get_exam_info_sptr(), - out_info_2d_sptr)); - - SegmentBySinogram segment=in_3d_sptr->get_segment_by_sinogram(0); - out_2d_sptr->set_segment(segment); -// std::cout<<" value "<get_sinogram(8,0)[0][0]< out_info_2d_sptr(in_3d_sptr->get_proj_data_info_sptr()->create_shared_clone()); + out_info_2d_sptr->reduce_segment_range(0, 0); + out_2d_sptr.reset(new ProjDataInMemory(in_3d_sptr->get_exam_info_sptr(), out_info_2d_sptr)); + + SegmentBySinogram segment = in_3d_sptr->get_segment_by_sinogram(0); + out_2d_sptr->set_segment(segment); + // std::cout<<" value "<get_sinogram(8,0)[0][0]<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()) + if (!this->input_projdata_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())) + 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; + 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->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->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->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 >); + this->masking_parameters.filter_sptr.reset(new PostFiltering>); - if(!masking_parameters.filter_sptr->parse(this->masking_parameters.filter_filename.c_str())) + 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; + warning(boost::format("ScatterEstimation: Error parsing post filter parameters file %1%. Aborting.") + % this->masking_parameters.filter_filename); + return true; } } - if (!this->scatter_sim_par_filename.empty()) + if (!this->scatter_sim_par_filename.empty()) + { + info("ScatterEstimation: Initialising Scatter Simulation ...", 3); + // Parse locally { - 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."); - } + 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."); - } + // 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); - } + 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; + return false; } -shared_ptr +shared_ptr ScatterEstimation::get_output() const { - return scatter_estimate_sptr; + 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); @@ -391,54 +344,80 @@ 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 > +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_max_scale_value(float value) -{ this->max_scale_value = value; } +void +ScatterEstimation::set_max_scale_value(float value) +{ + this->max_scale_value = value; +} -void ScatterEstimation::set_min_scale_value(float value) -{ this->min_scale_value = value; } +void +ScatterEstimation::set_min_scale_value(float value) +{ + this->min_scale_value = value; +} -void ScatterEstimation::set_mask_projdata_filename(std::string name) -{ this->mask_projdata_filename = name; } +void +ScatterEstimation::set_mask_projdata_filename(std::string name) +{ + this->mask_projdata_filename = name; +} -void ScatterEstimation::set_mask_image_filename(std::string name) -{ this->mask_image_filename = name; } +void +ScatterEstimation::set_mask_image_filename(std::string name) +{ + this->mask_image_filename = name; +} -void ScatterEstimation::set_output_additive_estimate_prefix(std::string name) -{ this->output_additive_estimate_prefix = name; } +void +ScatterEstimation::set_output_additive_estimate_prefix(std::string name) +{ + this->output_additive_estimate_prefix = name; +} -void ScatterEstimation::set_run_debug_mode(bool debug) -{ this->run_debug_mode = debug; } +void +ScatterEstimation::set_run_debug_mode(bool debug) +{ + this->run_debug_mode = debug; +} -void ScatterEstimation::set_restart_reconstruction_every_scatter_iteration(bool setting) -{ this->restart_reconstruction_every_scatter_iteration = setting; } +void +ScatterEstimation::set_restart_reconstruction_every_scatter_iteration(bool setting) +{ + this->restart_reconstruction_every_scatter_iteration = setting; +} -bool ScatterEstimation::get_restart_reconstruction_every_scatter_iteration() const -{ return this->restart_reconstruction_every_scatter_iteration; } +bool +ScatterEstimation::get_restart_reconstruction_every_scatter_iteration() const +{ + return this->restart_reconstruction_every_scatter_iteration; +} 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)); @@ -446,793 +425,772 @@ set_attenuation_correction_proj_data_sptr(const shared_ptr arg) } 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() +ScatterEstimation::set_up() { - if (this->run_debug_mode) + if (this->run_debug_mode) { - info("ScatterEstimation: Debugging mode is activated."); - this->export_scatter_estimates_of_each_iteration = true; + 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) + // Calculate the SSRB + if (input_projdata_sptr->get_num_segments() > 1) { - info("ScatterEstimation: Running SSRB on input data..."); - this->input_projdata_2d_sptr = make_2D_projdata_sptr(this->input_projdata_sptr); + info("ScatterEstimation: Running SSRB on input data..."); + this->input_projdata_2d_sptr = make_2D_projdata_sptr(this->input_projdata_sptr); } - else + else { - input_projdata_2d_sptr = input_projdata_sptr; + 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 ..."); + info("ScatterEstimation: Setting up reconstruction method ..."); - if(is_null_ptr(this->reconstruction_template_sptr)) + if (is_null_ptr(this->reconstruction_template_sptr)) { - warning("ScatterEstimation: Reconstruction method has not been initialised. Aborting."); - return Succeeded::no; + 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); + // 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 (!is_null_ptr(tmp_analytic)) { - if(set_up_analytic() == Succeeded::no) + if (set_up_analytic() == Succeeded::no) { - warning("ScatterEstimation: set_up_analytic reconstruction failed. Aborting."); - return Succeeded::no; + warning("ScatterEstimation: set_up_analytic reconstruction failed. Aborting."); + return Succeeded::no; } - this->iterative_method = false; - tmp_analytic->set_disable_output(!this->run_debug_mode); + this->iterative_method = false; + tmp_analytic->set_disable_output(!this->run_debug_mode); } - else if (!is_null_ptr(tmp_iterative)) + else if (!is_null_ptr(tmp_iterative)) { - if(set_up_iterative(tmp_iterative) == Succeeded::no) + if (set_up_iterative(tmp_iterative) == Succeeded::no) { - warning("ScatterEstimation: set_up_iterative reconstruction failed. Aborting."); - return Succeeded::no; + warning("ScatterEstimation: set_up_iterative reconstruction failed. Aborting."); + return Succeeded::no; } - this->iterative_method = true; - tmp_iterative->set_disable_output(!this->run_debug_mode); + this->iterative_method = true; + tmp_iterative->set_disable_output(!this->run_debug_mode); } - else + else { - warning("ScatterEstimation: Failure to detect a method of reconstruction. Aborting."); - return Succeeded::no; + 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()); + if (iterative_method) + this->current_activity_image_sptr.reset(tmp_iterative->get_initial_data_ptr()); - // - // ScatterSimulation - // + // + // 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: 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); + 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_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) + 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) + 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()); + 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 + 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()); + 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 (this->downsample_scanner_bool) - this->scatter_simulation_sptr->downsample_scanner(); + if (this->downsample_scanner_bool) + this->scatter_simulation_sptr->downsample_scanner(); - // Check if Load a mask proj_data + // 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_projdata_sptr) || this->recompute_mask_projdata) { - if(is_null_ptr(this->mask_image_sptr) || this->recompute_mask_image) + 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); + // 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) + if (project_mask_image() == Succeeded::no) { - warning("ScatterEstimation: Unsuccessful to fwd project the mask image. Aborting."); - return 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) +ScatterEstimation::set_up_iterative(shared_ptr>> iterative_object) { - info("ScatterEstimation: Setting up iterative reconstruction ..."); + info("ScatterEstimation: Setting up iterative reconstruction ..."); - if(run_in_2d_projdata) + if (run_in_2d_projdata) { - iterative_object->set_input_data(this->input_projdata_2d_sptr); + iterative_object->set_input_data(this->input_projdata_2d_sptr); } - else - iterative_object->set_input_data(this->input_projdata_sptr); - + else + iterative_object->set_input_data(this->input_projdata_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; - // - // 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) + if (tmp_atten_projdata_sptr->get_num_segments() > 1) { - info("ScatterEstimation: Running SSRB on attenuation correction coefficients ..."); + info("ScatterEstimation: Running SSRB on attenuation correction coefficients ..."); - std::string out_filename = "tmp_atten_sino_2d.hs"; - atten_projdata_2d_sptr=make_2D_projdata_sptr(tmp_atten_projdata_sptr, out_filename); - + std::string out_filename = "tmp_atten_sino_2d.hs"; + atten_projdata_2d_sptr = make_2D_projdata_sptr(tmp_atten_projdata_sptr, out_filename); } - else + else { - // TODO: this needs more work. -- Setting directly 2D proj_data is buggy right now. - atten_projdata_2d_sptr = tmp_atten_projdata_sptr; + // 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; + 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; - 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)) + 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: Constructing 2D normalisation coefficients ..."); + info("ScatterEstimation: Constructing 2D normalisation coefficients ..."); - 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); + 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); - 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); + 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); - // Essentially since inv_projData_sptr is 1s then this is an inversion. - // inv_projdata_sptr = 1/norm3d - norm3d_sptr->undo(*inv_projdata_3d_sptr); + // Essentially since inv_projData_sptr is 1s then this is an inversion. + // inv_projdata_sptr = 1/norm3d + norm3d_sptr->undo(*inv_projdata_3d_sptr); - info("ScatterEstimation: Performing SSRB on efficiency factors ..."); + info("ScatterEstimation: Performing SSRB on efficiency factors ..."); - norm_projdata_2d_sptr=make_2D_projdata_sptr(inv_projdata_3d_sptr); + norm_projdata_2d_sptr = make_2D_projdata_sptr(inv_projdata_3d_sptr); - // 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); + // 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); - 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); + 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); - norm_coeff_2d_sptr.reset(new BinNormalisationFromProjData(norm_projdata_2d_sptr)); - } - else - { - norm_coeff_2d_sptr = norm3d_sptr; - } + norm_coeff_2d_sptr.reset(new BinNormalisationFromProjData(norm_projdata_2d_sptr)); + } + else + { + norm_coeff_2d_sptr = norm3d_sptr; + } - 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)); + 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."); + 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..."); + // + // 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 (!is_null_ptr(this->back_projdata_sptr)) { - if( back_projdata_sptr->get_num_segments() > 1) + if (back_projdata_sptr->get_num_segments() > 1) { - info("ScatterEstimation: Running SSRB on the background data ..."); + info("ScatterEstimation: Running SSRB on the background data ..."); - - this->back_projdata_2d_sptr=make_2D_projdata_sptr(back_projdata_sptr); + this->back_projdata_2d_sptr = make_2D_projdata_sptr(back_projdata_sptr); } - else + else { - this->back_projdata_2d_sptr = back_projdata_sptr; + 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 + else // We will need a background for the scatter, so let's create a simple empty ProjData { - if (run_in_2d_projdata) + if (run_in_2d_projdata) { - std::string out_filename = "tmp_background_data_2d.hs"; + 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); + 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 + else { - std::string out_filename = "tmp_background_data.hs"; + 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); + 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) + 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 + ""; - this->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()); - this->add_projdata_2d_sptr->fill(*this->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(*this->input_projdata_2d_sptr); - subtract_proj_data(*data_to_fit_projdata_sptr, *this->back_projdata_2d_sptr); + // 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 + ""; + this->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()); + this->add_projdata_2d_sptr->fill(*this->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(*this->input_projdata_2d_sptr); + subtract_proj_data(*data_to_fit_projdata_sptr, *this->back_projdata_2d_sptr); } - else + 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); + // 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; + return Succeeded::yes; } Succeeded -ScatterEstimation:: -set_up_analytic() +ScatterEstimation::set_up_analytic() { - //TODO : I have most stuff in tmp. - error("Analytic recon not implemented yet"); - return Succeeded::yes; + // 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; + float local_min_scale_value = 0.5f; + float local_max_scale_value = 0.5f; - stir::BSpline::BSplineType spline_type = stir::BSpline::quadratic; + 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); + // 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; + // 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) + 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); + 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 + 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); + 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; + info("ScatterEstimation: Start processing..."); + shared_ptr> act_image_for_averaging; - //Recompute the initial y image if the max is equal to the min. + // 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() ) + 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 ..."); + 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); - else - reconstruct_analytic(0); + if (iterative_method) + reconstruct_iterative(0); + else + reconstruct_analytic(0); - if ( run_debug_mode ) + 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); + 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); - - 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++) - { + // 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) + // + // 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 (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 (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; } } - 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->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 + 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()); + 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()); } - // 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) + // 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; + local_max_scale_value = this->max_scale_value; + local_min_scale_value = this->min_scale_value; } - scaled_est_projdata_sptr->fill(0.F); + 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); + 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) + 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()); + 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 ) + // 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; + shared_ptr temp_scatter_projdata; - if(run_in_2d_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()) + 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 { - 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)); + // 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())); } - else + 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)) { - // 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())); + add_proj_data(*temp_additive_projdata, *this->back_projdata_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); - } + + this->multiplicative_binnorm_sptr->apply(*temp_additive_projdata); + } } - // 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) + // 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); + this->add_projdata_2d_sptr->fill(*scaled_est_projdata_sptr); - if (!is_null_ptr(this->back_projdata_2d_sptr)) + if (!is_null_ptr(this->back_projdata_2d_sptr)) { - add_proj_data(*this->add_projdata_2d_sptr, *this->back_projdata_2d_sptr); + add_proj_data(*this->add_projdata_2d_sptr, *this->back_projdata_2d_sptr); } - this->multiplicative_binnorm_2d_sptr->apply(*this->add_projdata_2d_sptr); + this->multiplicative_binnorm_2d_sptr->apply(*this->add_projdata_2d_sptr); } - else + else { - // TODO restructure code to move additive_projdata code from above - error("ScatterEstimation: You should not be here. This is not 2D."); + // TODO restructure code to move additive_projdata code from above + error("ScatterEstimation: You should not be here. This is not 2D."); } - if (this->restart_reconstruction_every_scatter_iteration) - { this->current_activity_image_sptr->fill(1.f); } - - iterative_method ? reconstruct_iterative(i_scat_iter): - reconstruct_analytic(i_scat_iter); + if (this->restart_reconstruction_every_scatter_iteration) + { + this->current_activity_image_sptr->fill(1.f); + } - scatter_simulation_sptr->set_activity_image_sptr(this->current_activity_image_sptr); + iterative_method ? reconstruct_iterative(i_scat_iter) : reconstruct_analytic(i_scat_iter); + scatter_simulation_sptr->set_activity_image_sptr(this->current_activity_image_sptr); } - info("ScatterEstimation: Scatter Estimation finished !!!"); + info("ScatterEstimation: Scatter Estimation finished !!!"); - return Succeeded::yes; + return Succeeded::yes; } void -ScatterEstimation:: -reconstruct_iterative(int _current_iter_num) +ScatterEstimation::reconstruct_iterative(int _current_iter_num) { - shared_ptr > > tmp_iterative = - dynamic_pointer_cast > >(reconstruction_template_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) + // 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."); + error("ScatterEstimation: Failure at set_up() of the reconstruction method. Aborting."); } - tmp_iterative->reconstruct(this->current_activity_image_sptr); + tmp_iterative->reconstruct(this->current_activity_image_sptr); - if(this->run_debug_mode) + 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(), *this->current_activity_image_sptr); + 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(), + *this->current_activity_image_sptr); } } void -ScatterEstimation:: -reconstruct_analytic(int _current_iter_num) +ScatterEstimation::reconstruct_analytic(int _current_iter_num) { - AnalyticReconstruction* analytic_object = - dynamic_cast (this->reconstruction_template_sptr.get()); - analytic_object->reconstruct(this->current_activity_image_sptr); + AnalyticReconstruction* analytic_object = dynamic_cast(this->reconstruction_template_sptr.get()); + analytic_object->reconstruct(this->current_activity_image_sptr); - if(this->run_debug_mode) + 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(), *this->current_activity_image_sptr); - + 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(), + *this->current_activity_image_sptr); } - //TODO: threshold ... to cut the negative values + // TODO: threshold ... to cut the negative values } /****************** functions to help **********************/ void -ScatterEstimation:: -add_proj_data(ProjData& first_addend, const ProjData& second_addend) +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) + 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 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)) + if (!(first_addend.set_segment(first_segment_by_view) == Succeeded::yes)) { - error("Error set_segment %d", segment_num); + error("Error set_segment %d", segment_num); } } } void -ScatterEstimation:: -subtract_proj_data(ProjData& minuend, const ProjData& subtracted) +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) + 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 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)) + if (!(minuend.set_segment(first_segment_by_view) == Succeeded::yes)) { - error("ScatterEstimation: Error set_segment %d", segment_num); + 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) +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) + 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); + 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)) + if (!(data.set_segment(segment_by_view) == Succeeded::yes)) { - error("ScatterEstimation: Error set_segment %d", segment_num); + error("ScatterEstimation: Error set_segment %d", segment_num); } } } @@ -1240,136 +1198,130 @@ apply_to_proj_data(ProjData& data, const pow_times_add& func) Succeeded ScatterEstimation::project_mask_image() { - if (is_null_ptr(this->mask_image_sptr)) + 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; + warning("You cannot forward project if you have not set the mask image. Aborting."); + return Succeeded::no; } - if (run_in_2d_projdata) + if (run_in_2d_projdata) { - if (is_null_ptr(this->input_projdata_2d_sptr)) + if (is_null_ptr(this->input_projdata_2d_sptr)) { - warning("No 2D proj_data have been initialised. Aborting."); - return Succeeded::no; + warning("No 2D proj_data have been initialised. Aborting."); + return Succeeded::no; } } - else + else { - if (is_null_ptr(this->input_projdata_sptr)) + if (is_null_ptr(this->input_projdata_sptr)) { - warning("No 3D proj_data have been initialised. Aborting."); - return Succeeded::no; + 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) + 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 ); + 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())); + 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 + else { - forw_projector_sptr->set_up(this->input_projdata_sptr->get_proj_data_info_sptr(), - this->mask_image_sptr ); + 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) + // 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); + 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)) + if (!(mask_projdata->set_segment(segment_by_view) == Succeeded::yes)) { - warning("ScatterEstimation: Error set_segment %d", segment_num); - return Succeeded::no; + 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())); + 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; + CreateTailMaskFromACFs create_tail_mask_from_acfs; - if(this->tail_mask_par_filename.empty()) + if (this->tail_mask_par_filename.empty()) { - create_tail_mask_from_acfs.ACF_threshold = 1.1; - create_tail_mask_from_acfs.safety_margin = 4; + create_tail_mask_from_acfs.ACF_threshold = 1.1; + create_tail_mask_from_acfs.safety_margin = 4; } - else + 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); + 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(); + + 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) +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) + for (DiscretisedDensity<3, float>::full_iterator iter = arg.begin_all(); iter != arg.end_all(); ++iter) { if (*iter < masking_parameters.min_threshold) - *iter = 0.F; + *iter = 0.F; else - *iter = 1.F; + *iter = 1.F; } } -int ScatterEstimation::get_num_iterations() const +int +ScatterEstimation::get_num_iterations() const { - return num_scatter_iterations; + return num_scatter_iterations; } // deprecated version -int ScatterEstimation::get_iterations_num() const +int +ScatterEstimation::get_iterations_num() const { - return num_scatter_iterations; + return num_scatter_iterations; } void @@ -1403,28 +1355,27 @@ ScatterEstimation::create_multiplicative_binnorm_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()); + const ChainedBinNormalisation* tmp_chain_norm_sptr = dynamic_cast(combined_norm_sptr.get()); - if (!is_null_ptr(tmp_chain_norm_sptr )) + if (!is_null_ptr(tmp_chain_norm_sptr)) { - return tmp_chain_norm_sptr->get_first_norm(); + return tmp_chain_norm_sptr->get_first_norm(); } - else //Just trivial, then .. + 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 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()); + 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 )) + if (!is_null_ptr(tmp_chain_norm_sptr)) { atten_norm_sptr = tmp_chain_norm_sptr->get_second_norm(); } @@ -1433,31 +1384,28 @@ ScatterEstimation::get_attenuation_correction_factors_sptr(const shared_ptr (atten_norm_sptr.get())->get_norm_proj_data_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 +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) + 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)); + 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 + else { - pd_sptr.reset(new ProjDataInMemory(exam_info_sptr, proj_data_info_sptr)); + pd_sptr.reset(new ProjDataInMemory(exam_info_sptr, proj_data_info_sptr)); } - return pd_sptr; + return pd_sptr; } END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 7d28caced..07c568657 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -50,25 +50,25 @@ START_NAMESPACE_STIR -ScatterSimulation:: -ScatterSimulation() +ScatterSimulation::ScatterSimulation() { - this->set_defaults(); + this->set_defaults(); } -ScatterSimulation:: -~ScatterSimulation() +ScatterSimulation::~ScatterSimulation() { - // Sometimes I get a segfault without this line. - scatt_points_vector.clear(); + // Sometimes I get a segfault without this line. + scatt_points_vector.clear(); } -bool ScatterSimulation::get_use_cache() const +bool +ScatterSimulation::get_use_cache() const { return this->use_cache; } -void ScatterSimulation::set_use_cache(bool value) +void +ScatterSimulation::set_use_cache(bool value) { if (value == this->use_cache) return; @@ -79,291 +79,265 @@ void ScatterSimulation::set_use_cache(bool value) } 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 +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_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + axial_bins += this->proj_data_info_sptr->get_num_axial_poss(vs_num.segment_num()); + + const int total_bins + = this->proj_data_info_sptr->get_num_views() * axial_bins * this->proj_data_info_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_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_sptr->get_max_segment_num(); + ++vs_num.segment_num()) { - 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_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - axial_bins += this->proj_data_info_sptr->get_num_axial_poss(vs_num.segment_num()); - - const int total_bins = - this->proj_data_info_sptr->get_num_views() * axial_bins * - this->proj_data_info_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_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - { - for (vs_num.view_num() = this->proj_data_info_sptr->get_min_view_num(); - vs_num.view_num() <= this->proj_data_info_sptr->get_max_view_num(); - ++vs_num.view_num()) + for (vs_num.view_num() = this->proj_data_info_sptr->get_min_view_num(); + vs_num.view_num() <= this->proj_data_info_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_sptr->get_num_axial_poss(vs_num.segment_num()) * - this->proj_data_info_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 //////////////// */ + total_scatter += this->process_data_for_view_segment_num(vs_num); + bin_counter += this->proj_data_info_sptr->get_num_axial_poss(vs_num.segment_num()) + * this->proj_data_info_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)) + 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; + 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_sptr->get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num() <= this->proj_data_info_sptr->get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - { - for (bin.tangential_pos_num() = this->proj_data_info_sptr->get_min_tangential_pos_num(); - bin.tangential_pos_num() <= this->proj_data_info_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_sptr->get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= this->proj_data_info_sptr->get_max_axial_pos_num(bin.segment_num()); + ++bin.axial_pos_num()) + { + for (bin.tangential_pos_num() = this->proj_data_info_sptr->get_min_tangential_pos_num(); + bin.tangential_pos_num() <= this->proj_data_info_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) + for (int i = 0; i < static_cast(all_bins.size()); ++i) { - const Bin bin = all_bins[i]; - const double scatter_ratio = scatter_estimate(bin); + 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); + 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 = -1; - 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; + 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 = -1; + 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() +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", ""); + 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); + // 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() +ScatterSimulation::set_up() { - if (is_null_ptr(proj_data_info_sptr)) - error("ScatterSimulation: projection data info not set. Aborting."); + if (is_null_ptr(proj_data_info_sptr)) + error("ScatterSimulation: projection data info not set. Aborting."); - if (!proj_data_info_sptr->has_energy_information()) - error("ScatterSimulation: scanner energy resolution information not set. Aborting."); + if (!proj_data_info_sptr->has_energy_information()) + error("ScatterSimulation: scanner energy resolution information not set. Aborting."); - if (is_null_ptr(template_exam_info_sptr)) - error("ScatterSimulation: template exam info not set. Aborting."); + if (is_null_ptr(template_exam_info_sptr)) + error("ScatterSimulation: template exam info not set. Aborting."); - if(!template_exam_info_sptr->has_energy_information()) - error("ScatterSimulation: template energy window information 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(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 (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."); + if (downsample_scanner_bool) + { + if (this->_already_set_up) + error("ScatterSimulation: set_up() called twice. This is currently not supported."); - downsample_scanner(); - } + downsample_scanner(); + } - if(is_null_ptr(density_image_for_scatter_points_sptr)) + 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); + 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_sptr->create_shared_clone())); -// this->output_proj_data_sptr->fill(0.0); -// info("ScatterSimulation: output projection data created."); -// } - + // { + // this->output_proj_data_sptr.reset(new ProjDataInMemory(this->template_exam_info_sptr, + // this->proj_data_info_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 @@ -374,75 +348,77 @@ set_up() (sorry) */ #ifndef NDEBUG + { + CartesianCoordinate3D detector_coord_A, detector_coord_B; + // check above statement + if (dynamic_cast(proj_data_info_sptr.get())) + { + auto ptr = dynamic_cast(proj_data_info_sptr.get()); + ptr->find_cartesian_coordinates_of_detection(detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); + } + else + { + auto ptr = dynamic_cast(proj_data_info_sptr.get()); + ptr->find_cartesian_coordinates_of_detection(detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); + } + + // if(this->proj_data_info_sptr->get_scanner_sptr()->get_scanner_geometry()=="Cylindrical"){ + 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_sptr->get_m(Bin(0, 0, this->proj_data_info_sptr->get_min_axial_pos_num(0), 0)); + const float m_last = this->proj_data_info_sptr->get_m(Bin(0, 0, this->proj_data_info_sptr->get_max_axial_pos_num(0), 0)); + // if(this->proj_data_info_sptr->get_scanner_sptr()->get_scanner_geometry()=="Cylindrical") + assert(fabs(m_last + m_first) < m_last * 10E-4); + } +#endif + if (dynamic_cast(proj_data_info_sptr.get())) { - CartesianCoordinate3D detector_coord_A, detector_coord_B; - // check above statement - if(dynamic_cast (proj_data_info_sptr.get())){ - auto ptr = dynamic_cast (proj_data_info_sptr.get()); - ptr->find_cartesian_coordinates_of_detection(detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); - }else{ - auto ptr = dynamic_cast (proj_data_info_sptr.get()); - ptr->find_cartesian_coordinates_of_detection(detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); - } - -// if(this->proj_data_info_sptr->get_scanner_sptr()->get_scanner_geometry()=="Cylindrical"){ - 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_sptr->get_m(Bin(0, 0, this->proj_data_info_sptr->get_min_axial_pos_num(0), 0)); - const float m_last = - this->proj_data_info_sptr->get_m(Bin(0, 0, this->proj_data_info_sptr->get_max_axial_pos_num(0), 0)); -// if(this->proj_data_info_sptr->get_scanner_sptr()->get_scanner_geometry()=="Cylindrical") - assert(fabs(m_last + m_first) < m_last * 10E-4); + this->shift_detector_coordinates_to_origin + = CartesianCoordinate3D(this->proj_data_info_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); } -#endif - if(dynamic_cast (proj_data_info_sptr.get())){ - this->shift_detector_coordinates_to_origin = - CartesianCoordinate3D(this->proj_data_info_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); - }else{ - if(dynamic_cast (proj_data_info_sptr.get())){ - // align BlocksOnCylindrical scanner ring 0 to z=0. - this->shift_detector_coordinates_to_origin = - CartesianCoordinate3D(this->proj_data_info_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); + else + { + if (dynamic_cast(proj_data_info_sptr.get())) + { + // align BlocksOnCylindrical scanner ring 0 to z=0. + this->shift_detector_coordinates_to_origin + = CartesianCoordinate3D(this->proj_data_info_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); } - // align Generic geometry here. + // align Generic geometry here. } #if 1 - // checks on image zooming to avoid 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 avoid 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 +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; + 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 +#if 0 const Scanner& scanner = *this->proj_data_info_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 float z_to_middle_standard = - (act_image.get_max_index() + act_image.get_min_index())*act_image.get_voxel_size().z()/2.F; + 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; 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" @@ -452,195 +428,173 @@ check_z_to_middle_consistent(const DiscretisedDensity<3,float>& _image, const st } void -ScatterSimulation:: -set_activity_image_sptr(const shared_ptr > arg) +ScatterSimulation::set_activity_image_sptr(const shared_ptr> arg) { - if (is_null_ptr(arg) ) - error("ScatterSimulation: Unable to set the activity image"); + 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) +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); + 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) +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; + 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) +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); + 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) +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; + 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 +const DiscretisedDensity<3, float>& +ScatterSimulation::get_activity_image() const { - return *activity_image_sptr; + return *activity_image_sptr; } -const DiscretisedDensity<3,float>& -ScatterSimulation:: -get_attenuation_image() const +const DiscretisedDensity<3, float>& +ScatterSimulation::get_attenuation_image() const { - return *density_image_sptr; + return *density_image_sptr; } -const DiscretisedDensity<3,float>& -ScatterSimulation:: -get_attenuation_image_for_scatter_points() const +const DiscretisedDensity<3, float>& +ScatterSimulation::get_attenuation_image_for_scatter_points() const { - return *density_image_for_scatter_points_sptr; + return *density_image_for_scatter_points_sptr; } -shared_ptr > -ScatterSimulation:: -get_density_image_for_scatter_points_sptr() const +shared_ptr> +ScatterSimulation::get_density_image_for_scatter_points_sptr() const { - return density_image_for_scatter_points_sptr; + return density_image_for_scatter_points_sptr; } void -ScatterSimulation:: -set_density_image_for_scatter_points(const std::string& filename) +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; + 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) +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; + 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) +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_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); + if (is_null_ptr(this->density_image_sptr)) + error("ScatterSimulation: downsampling function called before attenuation image is set"); - 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; + const VoxelsOnCartesianGrid& tmp_att = dynamic_cast&>(*this->density_image_sptr); - // 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++; + 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(); - // adjust zoom_z to cope with ugly "shift to middle of scanner" problem + if (_zoom_xy < 0 || _zoom_z < 0) { - // 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); + VoxelsOnCartesianGrid tmpl_density(this->density_image_sptr->get_exam_info_sptr(), *proj_data_info_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; - 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 @@ -660,443 +614,403 @@ 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) +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)); + 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)) + if (is_null_ptr(this->output_proj_data_sptr)) { - error("ScatterSimulation: No output ProjData set. Aborting."); + 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_sptr)) + if (is_null_ptr(this->proj_data_info_sptr)) { - error("ScatterSimulation: Template ProjData has not been set. Aborting."); + 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)) + if (is_null_ptr(this->template_exam_info_sptr)) { - shared_ptr exam_info_sptr(new ExamInfo); - if (filename.empty()) + shared_ptr exam_info_sptr(new ExamInfo); + if (filename.empty()) { - tmp_sptr.reset(new ProjDataInMemory(exam_info_sptr, - this->proj_data_info_sptr->create_shared_clone())); + tmp_sptr.reset(new ProjDataInMemory(exam_info_sptr, this->proj_data_info_sptr->create_shared_clone())); } - else + else { - tmp_sptr.reset(new ProjDataInterfile(exam_info_sptr, - this->proj_data_info_sptr->create_shared_clone(), - this->output_proj_data_filename, - std::ios::in | std::ios::out | std::ios::trunc)); + tmp_sptr.reset(new ProjDataInterfile(exam_info_sptr, + this->proj_data_info_sptr->create_shared_clone(), + this->output_proj_data_filename, + std::ios::in | std::ios::out | std::ios::trunc)); } - } - else + else { - if (filename.empty()) + if (filename.empty()) { - tmp_sptr.reset(new ProjDataInMemory(this->template_exam_info_sptr, - this->proj_data_info_sptr->create_shared_clone())); + tmp_sptr.reset(new ProjDataInMemory(this->template_exam_info_sptr, this->proj_data_info_sptr->create_shared_clone())); } - else + else { - tmp_sptr.reset(new ProjDataInterfile(this->template_exam_info_sptr, - this->proj_data_info_sptr->create_shared_clone(), - this->output_proj_data_filename, - std::ios::in | std::ios::out | std::ios::trunc)); + tmp_sptr.reset(new ProjDataInterfile(this->template_exam_info_sptr, + this->proj_data_info_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) +ScatterSimulation::set_output_proj_data_sptr(shared_ptr arg) { - this->output_proj_data_sptr = arg; + this->output_proj_data_sptr = arg; } shared_ptr -ScatterSimulation:: -get_template_proj_data_info_sptr() const +ScatterSimulation::get_template_proj_data_info_sptr() const { - return this->proj_data_info_sptr; + return this->proj_data_info_sptr; } shared_ptr ScatterSimulation::get_exam_info_sptr() const { - return this->template_exam_info_sptr; + return this->template_exam_info_sptr; } void -ScatterSimulation:: -set_template_proj_data_info(const std::string& 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->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_sptr.reset(dynamic_cast(arg.clone())); + this->_already_set_up = false; + this->proj_data_info_sptr.reset(dynamic_cast(arg.clone())); - if (is_null_ptr(this->proj_data_info_sptr)){ - this->proj_data_info_sptr.reset(dynamic_cast(arg.clone())); - if (is_null_ptr(this->proj_data_info_sptr)){ - error("ScatterSimulation: Can only handle non-arccorrected data"); + if (is_null_ptr(this->proj_data_info_sptr)) + { + this->proj_data_info_sptr.reset(dynamic_cast(arg.clone())); + if (is_null_ptr(this->proj_data_info_sptr)) + { + error("ScatterSimulation: Can only handle non-arccorrected data"); } } - // find final size of detection_points_vector - this->total_detectors = - this->proj_data_info_sptr->get_scanner_ptr()->get_num_rings()* - this->proj_data_info_sptr->get_scanner_ptr()->get_num_detectors_per_ring (); + // find final size of detection_points_vector + this->total_detectors = this->proj_data_info_sptr->get_scanner_ptr()->get_num_rings() + * this->proj_data_info_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) +ScatterSimulation::set_exam_info_sptr(const shared_ptr arg) { - this->_already_set_up = false; - this->template_exam_info_sptr = arg->create_shared_clone(); + this->_already_set_up = false; + this->template_exam_info_sptr = arg->create_shared_clone(); } - -bool -ScatterSimulation:: -get_downsample_scanner_bool() const +bool +ScatterSimulation::get_downsample_scanner_bool() const { - return this->downsample_scanner_bool; + return this->downsample_scanner_bool; } -void -ScatterSimulation:: -set_downsample_scanner_bool(const bool arg) +void +ScatterSimulation::set_downsample_scanner_bool(const bool arg) { - if (arg != this->get_downsample_scanner_bool()) + if (arg != this->get_downsample_scanner_bool()) { - this->_already_set_up = false; - this->downsample_scanner_bool = arg; + this->_already_set_up = false; + this->downsample_scanner_bool = arg; } } -int -ScatterSimulation:: -get_num_downsample_scanner_rings() const +int +ScatterSimulation::get_num_downsample_scanner_rings() const { - return this->downsample_scanner_rings; + return this->downsample_scanner_rings; } -void -ScatterSimulation:: -set_num_downsample_scanner_rings(const int arg) +void +ScatterSimulation::set_num_downsample_scanner_rings(const int arg) { - if (arg != this->get_num_downsample_scanner_rings()) + if (arg != this->get_num_downsample_scanner_rings()) { - this->_already_set_up = false; - this->downsample_scanner_rings = arg; + this->_already_set_up = false; + this->downsample_scanner_rings = arg; } } -int -ScatterSimulation:: -get_num_downsample_scanner_dets() const +int +ScatterSimulation::get_num_downsample_scanner_dets() const { - return this->downsample_scanner_dets; + return this->downsample_scanner_dets; } -void -ScatterSimulation:: -set_num_downsample_scanner_dets(const int arg) +void +ScatterSimulation::set_num_downsample_scanner_dets(const int arg) { - if (arg != this->get_num_downsample_scanner_dets()) + if (arg != this->get_num_downsample_scanner_dets()) { - this->_already_set_up = false; - this->downsample_scanner_dets = arg; + this->_already_set_up = false; + this->downsample_scanner_dets = arg; } } Succeeded ScatterSimulation::downsample_scanner(int new_num_rings, int new_num_dets) { - if (new_num_rings <= 0) + if (new_num_rings <= 0) { - if(downsample_scanner_rings > 0) - new_num_rings = downsample_scanner_rings; - else if (!is_null_ptr(proj_data_info_sptr)) - { - const float total_axial_length = proj_data_info_sptr->get_scanner_sptr()->get_num_rings() * - proj_data_info_sptr->get_scanner_sptr()->get_ring_spacing(); - - new_num_rings = round(total_axial_length / 20.F + 0.5F); - } - else - return Succeeded::no; + if (downsample_scanner_rings > 0) + new_num_rings = downsample_scanner_rings; + else if (!is_null_ptr(proj_data_info_sptr)) + { + const float total_axial_length = proj_data_info_sptr->get_scanner_sptr()->get_num_rings() + * proj_data_info_sptr->get_scanner_sptr()->get_ring_spacing(); + + new_num_rings = round(total_axial_length / 20.F + 0.5F); + } + else + return Succeeded::no; } - const Scanner *const old_scanner_ptr = this->proj_data_info_sptr->get_scanner_ptr(); - shared_ptr new_scanner_sptr( new Scanner(*old_scanner_ptr)); + const Scanner* const old_scanner_ptr = this->proj_data_info_sptr->get_scanner_ptr(); + shared_ptr new_scanner_sptr(new Scanner(*old_scanner_ptr)); - //make a downsampled scanner with no gaps for blocksOnCylindrical - float approx_num_non_arccorrected_bins; - if (new_scanner_sptr->get_scanner_geometry()!="Cylindrical") + // make a downsampled scanner with no gaps for blocksOnCylindrical + float approx_num_non_arccorrected_bins; + if (new_scanner_sptr->get_scanner_geometry() != "Cylindrical") { - new_num_dets = this->proj_data_info_sptr->get_scanner_ptr()->get_num_detectors_per_ring(); - approx_num_non_arccorrected_bins = this->proj_data_info_sptr->get_num_tangential_poss(); - // preserve the length of the scanner the following includes gaps - float scanner_length_block = new_scanner_sptr->get_num_axial_buckets()* - new_scanner_sptr->get_num_axial_blocks_per_bucket()* - new_scanner_sptr->get_axial_block_spacing(); - new_scanner_sptr->set_num_axial_blocks_per_bucket(1); -// new_scanner_sptr->set_num_transaxial_blocks_per_bucket(1); - - - new_scanner_sptr->set_num_rings(new_num_rings); -// float transaxial_bucket_spacing=old_scanner_ptr->get_transaxial_block_spacing() -// *old_scanner_ptr->get_num_transaxial_blocks_per_bucket(); - float new_ring_spacing=scanner_length_block/new_scanner_sptr->get_num_rings(); -// int num_trans_buckets=old_scanner_ptr->get_num_transaxial_buckets(); -// get a new number of detectors that is a multiple of the number of buckets to preserve scanner shape -// float frac,whole; -// frac = std::modf(float(new_num_dets/new_scanner_sptr->get_num_transaxial_buckets()), &whole); -// int newest_num_dets=whole*new_scanner_sptr->get_num_transaxial_buckets(); -// new_scanner_sptr->set_num_detectors_per_ring(newest_num_dets); -// int new_transaxial_dets_per_bucket=newest_num_dets/num_trans_buckets; -// float new_det_spacing=transaxial_bucket_spacing/new_transaxial_dets_per_bucket; - - new_scanner_sptr->set_axial_crystal_spacing(new_ring_spacing); - new_scanner_sptr->set_ring_spacing(new_ring_spacing); - new_scanner_sptr->set_num_axial_crystals_per_block(new_num_rings); - new_scanner_sptr->set_axial_block_spacing(new_ring_spacing - * new_scanner_sptr->get_num_axial_crystals_per_block()); - -// new_scanner_sptr->set_num_transaxial_crystals_per_block(new_transaxial_dets_per_bucket); -// new_scanner_sptr->set_transaxial_crystal_spacing(new_det_spacing); -// new_scanner_sptr->set_transaxial_block_spacing(new_det_spacing -// * new_scanner_sptr->get_num_transaxial_crystals_per_block()); + new_num_dets = this->proj_data_info_sptr->get_scanner_ptr()->get_num_detectors_per_ring(); + approx_num_non_arccorrected_bins = this->proj_data_info_sptr->get_num_tangential_poss(); + // preserve the length of the scanner the following includes gaps + float scanner_length_block = new_scanner_sptr->get_num_axial_buckets() * new_scanner_sptr->get_num_axial_blocks_per_bucket() + * new_scanner_sptr->get_axial_block_spacing(); + new_scanner_sptr->set_num_axial_blocks_per_bucket(1); + // new_scanner_sptr->set_num_transaxial_blocks_per_bucket(1); + + new_scanner_sptr->set_num_rings(new_num_rings); + // float transaxial_bucket_spacing=old_scanner_ptr->get_transaxial_block_spacing() + // *old_scanner_ptr->get_num_transaxial_blocks_per_bucket(); + float new_ring_spacing = scanner_length_block / new_scanner_sptr->get_num_rings(); + // int num_trans_buckets=old_scanner_ptr->get_num_transaxial_buckets(); + // get a new number of detectors that is a multiple of the number of buckets to preserve scanner shape + // float frac,whole; + // frac = std::modf(float(new_num_dets/new_scanner_sptr->get_num_transaxial_buckets()), &whole); + // int newest_num_dets=whole*new_scanner_sptr->get_num_transaxial_buckets(); + // new_scanner_sptr->set_num_detectors_per_ring(newest_num_dets); + // int new_transaxial_dets_per_bucket=newest_num_dets/num_trans_buckets; + // float new_det_spacing=transaxial_bucket_spacing/new_transaxial_dets_per_bucket; + + new_scanner_sptr->set_axial_crystal_spacing(new_ring_spacing); + new_scanner_sptr->set_ring_spacing(new_ring_spacing); + new_scanner_sptr->set_num_axial_crystals_per_block(new_num_rings); + new_scanner_sptr->set_axial_block_spacing(new_ring_spacing * new_scanner_sptr->get_num_axial_crystals_per_block()); + + // new_scanner_sptr->set_num_transaxial_crystals_per_block(new_transaxial_dets_per_bucket); + // new_scanner_sptr->set_transaxial_crystal_spacing(new_det_spacing); + // new_scanner_sptr->set_transaxial_block_spacing(new_det_spacing + // * new_scanner_sptr->get_num_transaxial_crystals_per_block()); } - else{ - if (new_num_dets <= 0) + else + { + if (new_num_dets <= 0) { - if(downsample_scanner_dets > 0) - new_num_dets = downsample_scanner_dets; - else - new_num_dets=64; + if (downsample_scanner_dets > 0) + new_num_dets = downsample_scanner_dets; + else + new_num_dets = 64; } - // extend the bins by a small amount to avoid edge-effects, at the expense of longer computation time - approx_num_non_arccorrected_bins = ceil(this->proj_data_info_sptr->get_num_tangential_poss() * float(new_num_dets) / - old_scanner_ptr->get_num_detectors_per_ring()) + 1; - - // preserve the length of the scanner the following includes no gaps - float scanner_length_cyl = 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_cyl/new_scanner_sptr->get_num_rings())); + // extend the bins by a small amount to avoid edge-effects, at the expense of longer computation time + approx_num_non_arccorrected_bins = ceil(this->proj_data_info_sptr->get_num_tangential_poss() * float(new_num_dets) + / old_scanner_ptr->get_num_detectors_per_ring()) + + 1; + + // preserve the length of the scanner the following includes no gaps + float scanner_length_cyl = 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_cyl / new_scanner_sptr->get_num_rings())); } - new_scanner_sptr->set_max_num_non_arccorrected_bins(approx_num_non_arccorrected_bins); - 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_sptr->get_num_segments() == 1 ? 0 : - new_scanner_sptr->get_num_rings()-1; - - new_scanner_sptr->set_up(); - 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); - this->set_output_proj_data(this->output_proj_data_filename); + new_scanner_sptr->set_max_num_non_arccorrected_bins(approx_num_non_arccorrected_bins); + 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_sptr->get_num_segments() == 1 ? 0 : new_scanner_sptr->get_num_rings() - 1; + + new_scanner_sptr->set_up(); + 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)); - return Succeeded::yes; + 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); + this->set_output_proj_data(this->output_proj_data_filename); + + return Succeeded::yes; } -Succeeded ScatterSimulation::downsample_images_to_scanner_size() +Succeeded +ScatterSimulation::downsample_images_to_scanner_size() { - if(is_null_ptr(proj_data_info_sptr)) - return Succeeded::no; + if (is_null_ptr(proj_data_info_sptr)) + return Succeeded::no; - // Downsample the activity and attenuation images - shared_ptr > tmpl_image( new VoxelsOnCartesianGrid(*proj_data_info_sptr)); + // Downsample the activity and attenuation images + shared_ptr> tmpl_image(new VoxelsOnCartesianGrid(*proj_data_info_sptr)); - if(!is_null_ptr(activity_image_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(); + 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)) + if (!is_null_ptr(density_image_sptr)) { - const VoxelsOnCartesianGrid* tmp_att = dynamic_cast* >(density_image_sptr.get()); - VoxelsOnCartesianGrid* tmp = tmpl_image->get_empty_copy(); + 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) +ScatterSimulation::set_attenuation_threshold(const float arg) { - attenuation_threshold = arg; - this->_already_set_up = false; + attenuation_threshold = arg; + this->_already_set_up = false; } void -ScatterSimulation:: -set_randomly_place_scatter_points(const bool arg) +ScatterSimulation::set_randomly_place_scatter_points(const bool arg) { - randomly_place_scatter_points = arg; - this->_already_set_up = false; + randomly_place_scatter_points = arg; + this->_already_set_up = false; } void -ScatterSimulation:: -set_cache_enabled(const bool arg) +ScatterSimulation::set_cache_enabled(const bool arg) { - use_cache = arg; + use_cache = arg; } void -ScatterSimulation:: -write_log(const double simulation_time, - const float total_scatter) +ScatterSimulation::write_log(const double simulation_time, const float total_scatter) { - if (this->output_proj_data_filename.empty()) - return; + 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()); + 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; - } + 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"; + 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 309c70258..a7d8fd9e5 100644 --- a/src/scatter_buildblock/SingleScatterSimulation.cxx +++ b/src/scatter_buildblock/SingleScatterSimulation.cxx @@ -11,104 +11,87 @@ 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() +SingleScatterSimulation::SingleScatterSimulation() + : base_type() { - this->set_defaults(); + this->set_defaults(); } -SingleScatterSimulation:: -SingleScatterSimulation(const std::string& parameter_filename) +SingleScatterSimulation::SingleScatterSimulation(const std::string& parameter_filename) { - this->initialise(parameter_filename); + this->initialise(parameter_filename); } -SingleScatterSimulation:: -~SingleScatterSimulation() +SingleScatterSimulation::~SingleScatterSimulation() {} - void -SingleScatterSimulation:: -initialise_keymap() +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"); + 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) +SingleScatterSimulation::initialise(const std::string& parameter_filename) { - if (parameter_filename.size() == 0) + if (parameter_filename.size() == 0) { - this->set_defaults(); - this->ask_parameters(); + this->set_defaults(); + this->ask_parameters(); } - else + else { - this->set_defaults(); - if (!this->parse(parameter_filename.c_str())) + this->set_defaults(); + if (!this->parse(parameter_filename.c_str())) { - error("Error parsing input file %s, exiting", parameter_filename.c_str()); + error("Error parsing input file %s, exiting", parameter_filename.c_str()); } } } void -SingleScatterSimulation:: -set_defaults() +SingleScatterSimulation::set_defaults() { - base_type::set_defaults(); + base_type::set_defaults(); } Succeeded -SingleScatterSimulation:: -set_up() +SingleScatterSimulation::set_up() { - // set to negative value such that this will be recomputed - this->max_single_scatter_cos_angle = -1.F; + // 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() +SingleScatterSimulation::process_data() { - return base_type::process_data(); + return base_type::process_data(); } void -SingleScatterSimulation:: -ask_parameters() +SingleScatterSimulation::ask_parameters() { - base_type::ask_parameters(); + base_type::ask_parameters(); } bool -SingleScatterSimulation:: -post_processing() +SingleScatterSimulation::post_processing() { - if (!base_type::post_processing()) - return false; - return true; + if (!base_type::post_processing()) + return false; + return true; } std::string -SingleScatterSimulation:: -method_info() const +SingleScatterSimulation::method_info() const { - return this->registered_name; + 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 e4f9e6666..32796012e 100644 --- a/src/scatter_buildblock/cached_single_scatter_integrals.cxx +++ b/src/scatter_buildblock/cached_single_scatter_integrals.cxx @@ -3,7 +3,7 @@ Copyright (C) 2013 University College London This file is part of STIR. - SPDX-License-Identifier: Apache-2.0 + SPDX-License-Identifier: Apache-2.0 See STIR/LICENSE.txt for details */ /*! @@ -11,7 +11,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 @@ -19,7 +19,7 @@ \author Kris Thielemans */ #include "stir/scatter/ScatterSimulation.h" -#include "stir/IndexRange.h" +#include "stir/IndexRange.h" #include "stir/Coordinate2D.h" START_NAMESPACE_STIR @@ -27,47 +27,40 @@ 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 @@ -76,15 +69,11 @@ 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. @@ -96,100 +85,90 @@ cached_integral_over_activity_image_between_scattpoint_det(const unsigned scatte if (this->use_cache) { #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 - value = *location_in_cache; -#if defined(STIR_OPENMP) && (_OPENMP <201012) - } +# endif #endif + value = *location_in_cache; +#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) +# if _OPENMP >= 201012 +# pragma omp atomic write +# else +# pragma omp critical(STIRSCATTERESTIMATIONCACHE) { -# endif +# 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 +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* location_in_cache = this->use_cache ? &cached_attenuation_integral_scattpoint_det[scatter_point_num][det_num] : 0; float value; if (this->use_cache) { #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 - value = *location_in_cache; -#if defined(STIR_OPENMP) && (_OPENMP <201012) - } +# endif #endif + value = *location_in_cache; +#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) +# if _OPENMP >= 201012 +# pragma omp atomic write +# else +# pragma omp critical(STIRSCATTERESTIMATIONREADCACHEATTENINT) { -# endif +# 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 3672aaa60..55273245b 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 b49df9ed7..5def61db6 100644 --- a/src/scatter_buildblock/sample_scatter_points.cxx +++ b/src/scatter_buildblock/sample_scatter_points.cxx @@ -4,8 +4,8 @@ Copyright (C) 2013 University College London This file is part of STIR. - SPDX-License-Identifier: Apache-2.0 - + SPDX-License-Identifier: Apache-2.0 + See STIR/LICENSE.txt for details */ /*! @@ -27,63 +27,57 @@ 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) + // 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; + 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.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); } @@ -91,4 +85,4 @@ sample_scatter_points() 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 eb56b4cd5..ba2e182ad 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -5,7 +5,7 @@ Copyright (C) 2021, University of Leeds This file is part of STIR. - SPDX-License-Identifier: Apache-2.0 + SPDX-License-Identifier: Apache-2.0 See STIR/LICENSE.txt for details */ @@ -29,93 +29,83 @@ #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)) - error("More detection points than we think there are!\n"); - - detection_points_vector.push_back(coord); - ret_value = detection_points_vector.size()-1; - } + 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; + } } 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; - auto ptr = dynamic_cast (proj_data_info_sptr.get()); - if(ptr){ - ptr-> - find_cartesian_coordinates_of_detection( - detector_coord_A,detector_coord_B,bin); - }else{ - auto ptr = dynamic_cast (proj_data_info_sptr.get()); - if(ptr){ - ptr-> - find_cartesian_coordinates_of_detection( - detector_coord_A,detector_coord_B,bin); - }else{ - error("wrong type of projection data for scatter simulation"); + auto ptr = dynamic_cast(proj_data_info_sptr.get()); + if (ptr) + { + ptr->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); + else + { + auto ptr = dynamic_cast(proj_data_info_sptr.get()); + if (ptr) + { + ptr->find_cartesian_coordinates_of_detection(detector_coord_A, detector_coord_B, bin); + } + else + { + error("wrong type of projection data for scatter simulation"); + } + } + 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) +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 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 /* motivation for formula: @@ -131,77 +121,61 @@ detection_efficiency(const float energy) const */ // factor 2.35482 is used to convert FWHM to sigma - const float sigma_times_sqrt2= - sqrt(2.*energy*this->proj_data_info_sptr->get_scanner_ptr()->get_reference_energy())* - this->proj_data_info_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_sptr->get_scanner_ptr()->get_reference_energy()) + * this->proj_data_info_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) +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)))) ; + 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) +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.)); + 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); + 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)); + 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 eb6db9a0a..9a339c4cf 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -5,8 +5,8 @@ Copyright (C) 2011-07-01 - 2011, Kris Thielemans This file is part of STIR. - SPDX-License-Identifier: Apache-2.0 - + SPDX-License-Identifier: Apache-2.0 + See STIR/LICENSE.txt for details */ /*! @@ -24,7 +24,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" @@ -32,116 +32,82 @@ 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); double -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_sptr->get_scanner_ptr()->get_energy_resolution()); + this->max_single_scatter_cos_angle = max_cos_angle(this->template_exam_info_sptr->get_low_energy_thres(), + 2.f, + this->proj_data_info_sptr->get_scanner_ptr()->get_energy_resolution()); } - //static const float min_energy=energy_lower_limit(lower_energy_threshold,2.,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]; + 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 detection_efficiency_scatter = detection_efficiency(new_energy); + if (detection_efficiency_scatter == 0) return 0; - 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 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 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; + 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; + 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; 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 - double scatter_ratio=0 ; - - scatter_ratio= - (emiss_to_detA*(1./rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) - +emiss_to_detB*(1./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; - + double scatter_ratio = 0; + + scatter_ratio + = (emiss_to_detA * (1. / rB_squared) * pow(atten_to_detB, total_Compton_cross_section_relative_to_511keV(new_energy) - 1) + + emiss_to_detB * (1. / 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 41e3ba571..9ceaede1a 100644 --- a/src/scatter_buildblock/single_scatter_estimate.cxx +++ b/src/scatter_buildblock/single_scatter_estimate.cxx @@ -3,7 +3,7 @@ /*Copyright (C) 2004- 2009, Hammersmith Imanet This file is part of STIR. - SPDX-License-Identifier: Apache-2.0 + SPDX-License-Identifier: Apache-2.0 See STIR/LICENSE.txt for details */ @@ -19,13 +19,10 @@ */ #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 @@ -33,33 +30,23 @@ scatter_estimate(const Bin& bin) 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) @@ -69,9 +56,8 @@ actual_scatter_estimate(double& scatter_ratio_singles, // is an approximation for the integral over the scatter point. // 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; + const double common_factor + = 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 d270b2f28..e663da3c2 100644 --- a/src/scatter_buildblock/single_scatter_integrals.cxx +++ b/src/scatter_buildblock/single_scatter_integrals.cxx @@ -5,8 +5,8 @@ Copyright (C) 2016, UCL This file is part of STIR. - SPDX-License-Identifier: Apache-2.0 - + SPDX-License-Identifier: Apache-2.0 + See STIR/LICENSE.txt for details */ /*! @@ -14,13 +14,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" @@ -28,111 +28,87 @@ #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()) + 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(); + 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 + // we jump out of the loop as we are now at the other side of // the image - // break; + // break; } - ++element_ptr; - } - } - return sum; -} + ++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 f3a6f2338..f7ad7f5a1 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -3,8 +3,8 @@ Copyright (C) 2014, 2020 University College London This file is part of STIR. - SPDX-License-Identifier: Apache-2.0 - + SPDX-License-Identifier: Apache-2.0 + See STIR/LICENSE.txt for details */ /*! @@ -26,7 +26,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" @@ -41,53 +41,53 @@ 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) +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) { info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); - 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); + 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); 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); { - bool actual_remove_interleaving = remove_interleaving; + bool actual_remove_interleaving = remove_interleaving; - if (remove_interleaving && emission_proj_data.get_proj_data_info_sptr()->get_scanner_sptr()->get_scanner_geometry()!="Cylindrical") + if (remove_interleaving + && emission_proj_data.get_proj_data_info_sptr()->get_scanner_sptr()->get_scanner_geometry() != "Cylindrical") { - warning("upsample_and_fit_scatter_estimate: forcing remove_interleaving to false as non-cylindrical projdata"); - actual_remove_interleaving = false; + warning("upsample_and_fit_scatter_estimate: forcing remove_interleaving to false as non-cylindrical projdata"); + actual_remove_interleaving = false; } - interpolate_projdata(interpolated_direct_scatter, scatter_proj_data, spline_type, actual_remove_interleaving); + interpolate_projdata(interpolated_direct_scatter, scatter_proj_data, spline_type, actual_remove_interleaving); } // now call inverse_SSRB, and normalise/scale if we need to 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()); + 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.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); - Array<2,float> scale_factors; + Array<2, float> scale_factors; if (min_scale_factor == max_scale_factor) - { - if (min_scale_factor == 1.F) + { + if (min_scale_factor == 1.F) { scaled_scatter_proj_data.fill(interpolated_scatter); return; // all done @@ -95,54 +95,35 @@ upsample_and_fit_scatter_estimate(ProjData& scaled_scatter_proj_data, // Set all scale_factors to min_scale_factor (which is equal to max_scale_factor here) // Sadly a bit complicated to get index range ok - 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); - } + 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: 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) + if (scale_sinograms(scaled_scatter_proj_data, interpolated_scatter, scale_factors) != Succeeded::yes) { error("upsample_and_fit_scatter_estimate: writing of scaled sinograms failed"); } diff --git a/src/scatter_utilities/create_tail_mask_from_ACFs.cxx b/src/scatter_utilities/create_tail_mask_from_ACFs.cxx index f499a9a32..0cd5b28f5 100644 --- a/src/scatter_utilities/create_tail_mask_from_ACFs.cxx +++ b/src/scatter_utilities/create_tail_mask_from_ACFs.cxx @@ -4,7 +4,7 @@ Copyright (C) 2016, UCL This file is part of STIR. - SPDX-License-Identifier: Apache-2.0 + SPDX-License-Identifier: Apache-2.0 See STIR/LICENSE.txt for details */ @@ -20,7 +20,7 @@ \author Nikos Efthimiou \author Kris Thielemans - + \par Usage: \verbatim @@ -56,105 +56,106 @@ #include "stir/warning.h" #include "stir/error.h" -/***********************************************************/ +/***********************************************************/ static void -print_usage_and_exit(const char * const prog_name) +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); + 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; - +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) + // 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(); + 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."); + 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) + 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; + warning("Create_tail_mask_from_ACFs aborting because error in parsing. Not writing any output"); + return EXIT_FAILURE; } } - else + else { - // option processing - float ACF_threshold = 1.1F; - int safety_margin=4; - std::string ACF_filename; - std::string output_filename; + // 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] == '-') + while (argc > 2 && argv[1][1] == '-') { - if (strcmp(argv[1], "--ACF-filename")==0) + if (strcmp(argv[1], "--ACF-filename") == 0) { - ACF_filename = (argv[2]); - argc-=2; argv +=2; + ACF_filename = (argv[2]); + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--output-filename")==0) + else if (strcmp(argv[1], "--output-filename") == 0) { - output_filename = (argv[2]); - argc-=2; argv +=2; + output_filename = (argv[2]); + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--ACF-threshold")==0) + else if (strcmp(argv[1], "--ACF-threshold") == 0) { - ACF_threshold = float(atof(argv[2])); - argc-=2; argv +=2; + ACF_threshold = float(atof(argv[2])); + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--safety-margin")==0) + else if (strcmp(argv[1], "--safety-margin") == 0) { - safety_margin = atoi(argv[2]); - argc-=2; argv +=2; + safety_margin = atoi(argv[2]); + argc -= 2; + argv += 2; } - else + else { - std::cerr << "\nUnknown option: " << argv[1]; - print_usage_and_exit(prog_name); + std::cerr << "\nUnknown option: " << argv[1]; + print_usage_and_exit(prog_name); } } - if (argc!=1 || ACF_filename.size()==0 || output_filename.size()==0) + if (argc != 1 || ACF_filename.size() == 0 || output_filename.size() == 0) { - print_usage_and_exit(prog_name); + 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; - + // 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; } - // Onwards the new class will do the job ... + // Onwards the new class will do the job ... - return create_tail_mask_from_ACFs.process_data() == stir::Succeeded::yes ? - EXIT_SUCCESS : EXIT_FAILURE; -} - + 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 372ab6e01..efe88a3fe 100644 --- a/src/scatter_utilities/estimate_scatter.cxx +++ b/src/scatter_utilities/estimate_scatter.cxx @@ -4,7 +4,7 @@ Copyright (C) 2004- 2009, Hammersmith Imanet Ltd This file is part of STIR. - SPDX-License-Identifier: Apache-2.0 + SPDX-License-Identifier: Apache-2.0 See STIR/LICENSE.txt for details */ @@ -15,8 +15,8 @@ \brief Estimates a coarse scatter sinogram \author Kris Thielemans - - + + \par Usage: \code estimate_scatter parfile @@ -27,33 +27,32 @@ #include "stir/scatter/ScatterEstimation.h" #include "stir/Succeeded.h" -/***********************************************************/ +/***********************************************************/ -static void print_usage_and_exit() +static void +print_usage_and_exit() { - std::cerr<<"This executable runs a Scatter simulation method based on the options " + 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; +int +main(int argc, const char* argv[]) +{ + stir::ScatterEstimation scatter_estimation; - if (argc==2) + if (argc == 2) { - if (scatter_estimation.parse(argv[1]) == false) - return EXIT_FAILURE; + if (scatter_estimation.parse(argv[1]) == false) + return EXIT_FAILURE; } - else - print_usage_and_exit(); + else + print_usage_and_exit(); - return - (scatter_estimation.set_up() == stir::Succeeded::yes) - && (scatter_estimation.process_data() == stir::Succeeded::yes) ? - EXIT_SUCCESS : EXIT_FAILURE; + 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 781a257b0..aaf93ac86 100644 --- a/src/scatter_utilities/simulate_scatter.cxx +++ b/src/scatter_utilities/simulate_scatter.cxx @@ -33,12 +33,13 @@ using std::cerr; using std::cout; using std::endl; -static void print_usage_and_exit() +static void +print_usage_and_exit() { - std::cerr<<"This executable runs a Scatter simulation method based on the options " + 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" @@ -47,45 +48,51 @@ 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[]) +int +main(int argc, const char* argv[]) { - USING_NAMESPACE_STIR + USING_NAMESPACE_STIR - HighResWallClockTimer t; - t.reset(); - t.start(); + HighResWallClockTimer t; + t.reset(); + t.start(); - if (argc!=2) - print_usage_and_exit(); + if (argc != 2) + print_usage_and_exit(); - shared_ptr < ScatterSimulation > - simulation_method_sptr; + 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; } + 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->set_up() == Succeeded::no) + { + t.stop(); + return EXIT_FAILURE; + } - if(simulation_method_sptr->process_data() == stir::Succeeded::yes) + 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; - } + 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 48bc6d6bc..115d30198 100644 --- a/src/scatter_utilities/upsample_and_fit_single_scatter.cxx +++ b/src/scatter_utilities/upsample_and_fit_single_scatter.cxx @@ -3,7 +3,7 @@ Copyright (C) 2014, University College London This file is part of STIR. - SPDX-License-Identifier: Apache-2.0 + SPDX-License-Identifier: Apache-2.0 See STIR/LICENSE.txt for details */ @@ -17,20 +17,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 @@ -51,17 +51,18 @@ #include "stir/is_null_ptr.h" #include #include -/***********************************************************/ +/***********************************************************/ static void -print_usage_and_exit(const char * const prog_name) +print_usage_and_exit(const char* const prog_name) { - std::cerr << "\nUsage:\n" << prog_name << "\\\n" + 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" @@ -77,15 +78,16 @@ 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; @@ -93,62 +95,74 @@ int main(int argc, const char *argv[]) stir::shared_ptr normalisation_sptr; // option processing - while (argc>1 && argv[1][1] == '-') + while (argc > 1 && argv[1][1] == '-') { - if (strcmp(argv[1], "--min-scale-factor")==0) + if (strcmp(argv[1], "--min-scale-factor") == 0) { min_scale_factor = static_cast(atof(argv[2])); - argc-=2; argv +=2; + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--max-scale-factor")==0) + else if (strcmp(argv[1], "--max-scale-factor") == 0) { max_scale_factor = static_cast(atof(argv[2])); - argc-=2; argv +=2; + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--BSpline-type")==0) + else if (strcmp(argv[1], "--BSpline-type") == 0) { spline_type = (stir::BSpline::BSplineType)atoi(argv[2]); - argc-=2; argv +=2; + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--half-filter-width")==0) + else if (strcmp(argv[1], "--half-filter-width") == 0) { half_filter_width = (unsigned)atoi(argv[2]); - argc-=2; argv +=2; + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--remove-interleaving")==0) + else if (strcmp(argv[1], "--remove-interleaving") == 0) { - remove_interleaving = atoi(argv[2])!=0; - argc-=2; argv +=2; + remove_interleaving = atoi(argv[2]) != 0; + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--output-filename")==0) + else if (strcmp(argv[1], "--output-filename") == 0) { output_filename = (argv[2]); - argc-=2; argv +=2; + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--data-to-fit")==0) + else if (strcmp(argv[1], "--data-to-fit") == 0) { data_to_fit_filename = argv[2]; - argc-=2; argv +=2; + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--data-to-scale")==0) + else if (strcmp(argv[1], "--data-to-scale") == 0) { data_to_scale_filename = argv[2]; - argc-=2; argv +=2; + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--weights")==0) + else if (strcmp(argv[1], "--weights") == 0) { weights_filename = argv[2]; - argc-=2; argv +=2; + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--norm")==0) + 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"); + parser.add_stop_key("END"); if (!parser.parse(argv[2])) - { return EXIT_FAILURE; } - argc-=2; argv +=2; + { + return EXIT_FAILURE; + } + argc -= 2; + argv += 2; } else { @@ -156,49 +170,46 @@ int main(int argc, const char *argv[]) print_usage_and_exit(prog_name); } } - - if (argc> 1) + + 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) + 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); + 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()); + 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); + 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); return EXIT_SUCCESS; -} +} diff --git a/src/spatial_transformation_buildblock/GatedSpatialTransformation.cxx b/src/spatial_transformation_buildblock/GatedSpatialTransformation.cxx index 51c0d72cc..f44834774 100644 --- a/src/spatial_transformation_buildblock/GatedSpatialTransformation.cxx +++ b/src/spatial_transformation_buildblock/GatedSpatialTransformation.cxx @@ -2,12 +2,12 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details */ -/*! +/*! \file \ingroup spatial_transformation \brief Implementations of inline functions of class stir::GatedSpatialTransformation @@ -26,44 +26,42 @@ 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() //!< default destructor -{ } +GatedSpatialTransformation::~GatedSpatialTransformation() //!< default destructor +{} -Succeeded +Succeeded GatedSpatialTransformation::set_up() { - if (this->_spatial_transformations_are_stored==true) + if (this->_spatial_transformations_are_stored == true) return Succeeded::yes; else return Succeeded::no; } -const TimeGateDefinitions & +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"); @@ -72,12 +70,11 @@ initialise_keymap() } bool -GatedSpatialTransformation:: -post_processing() +GatedSpatialTransformation::post_processing() { if (base_type::post_processing() == true) return true; - if(this->_transformation_filename_prefix=="0") + if (this->_transformation_filename_prefix == "0") { warning("You need to specify a prefix for three files with transformation information."); return true; @@ -85,145 +82,170 @@ post_processing() else { GatedSpatialTransformation::read_from_files(this->_transformation_filename_prefix); - this->_spatial_transformations_are_stored=true; + 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"; - - 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; -} +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); + 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; +} //! Implementation to write the transformation vectors void -GatedSpatialTransformation::write_to_files(const std::string output_string) +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"); + (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 +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()){ - 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()); - 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()); + 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()) + { + 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()); + 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()); 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) + 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); + 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_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_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 eea157a2e..1d80cbd08 100644 --- a/src/spatial_transformation_buildblock/InvertAxis.cxx +++ b/src/spatial_transformation_buildblock/InvertAxis.cxx @@ -2,11 +2,11 @@ /* Copyright (C) 2019 National Physical Laboratory This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details - */ + */ /*! \file \ingroup buildblock @@ -20,72 +20,75 @@ 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(); + + 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]; + } + } } + } +} 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 - } - - +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 88747a7b7..a537174f5 100644 --- a/src/spatial_transformation_buildblock/SpatialTransformation.cxx +++ b/src/spatial_transformation_buildblock/SpatialTransformation.cxx @@ -7,30 +7,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 f0529e12b..2c57de903 100644 --- a/src/spatial_transformation_buildblock/spatial_transformation_registries.cxx +++ b/src/spatial_transformation_buildblock/spatial_transformation_registries.cxx @@ -1,19 +1,19 @@ // - /* - Copyright (C) 2009 -2013, King's College London - This file is part of STIR. - - SPDX-License-Identifier: Apache-2.0 - - See STIR/LICENSE.txt for details -*/ +/* + Copyright (C) 2009 -2013, King's College London + This file is part of STIR. + + SPDX-License-Identifier: Apache-2.0 + + 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" @@ -23,4 +23,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 78ac8cc59..64036598b 100644 --- a/src/spatial_transformation_buildblock/warp_image.cxx +++ b/src/spatial_transformation_buildblock/warp_image.cxx @@ -2,15 +2,15 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + 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 */ @@ -18,27 +18,29 @@ #include "stir/error.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) +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(); + 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) ; @@ -49,30 +51,33 @@ 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 + 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/test/IO/test_IO_DiscretisedDensity.cxx b/src/test/IO/test_IO_DiscretisedDensity.cxx index a129f232b..eefc78092 100644 --- a/src/test/IO/test_IO_DiscretisedDensity.cxx +++ b/src/test/IO/test_IO_DiscretisedDensity.cxx @@ -60,73 +60,75 @@ 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() override; - void read_image() override; - void check_result() override; + void create_image() override; + void read_image() override; + void check_result() override; }; -void IOTests_DiscretisedDensity::create_image() +void +IOTests_DiscretisedDensity::create_image() { - _image_to_write_sptr = create_single_image(); + _image_to_write_sptr = create_single_image(); } -void IOTests_DiscretisedDensity::read_image() +void +IOTests_DiscretisedDensity::read_image() { - // now read it back - unique_ptr > - density_ptr = read_from_file >(_filename); + // 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() +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()); + // 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) +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; - } - + { + 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"; + { + cerr << argv[0] << ": Error opening input file " << argv[1] << "\nExiting.\n"; - return EXIT_FAILURE; - } + return EXIT_FAILURE; + } IOTests_DiscretisedDensity tests(in); tests.run_tests(); diff --git a/src/test/IO/test_IO_DynamicDiscretisedDensity.cxx b/src/test/IO/test_IO_DynamicDiscretisedDensity.cxx index 0322fa50f..7c5683a0a 100644 --- a/src/test/IO/test_IO_DynamicDiscretisedDensity.cxx +++ b/src/test/IO/test_IO_DynamicDiscretisedDensity.cxx @@ -64,74 +64,83 @@ START_NAMESPACE_STIR class IOTests_DynamicDiscretisedDensity : public IOTests { public: - explicit IOTests_DynamicDiscretisedDensity(istream& in) : IOTests(in) {} + explicit IOTests_DynamicDiscretisedDensity(istream& in) + : IOTests(in) + {} protected: - - void create_image() override; - void check_result() override; + void create_image() override; + void check_result() override; }; -void IOTests_DynamicDiscretisedDensity::create_image() +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); + 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() +void +IOTests_DynamicDiscretisedDensity::check_result() { - set_tolerance(.00001); + 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 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_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()); + 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"; - 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)); + // 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)); - if (is_null_ptr(image_to_write_ptr) || is_null_ptr(image_to_read_ptr)) { - everything_ok = false; - return; + 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); + compare_images(*image_to_write_ptr, *image_to_read_ptr); } } @@ -139,23 +148,23 @@ END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) +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; - } + { + 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"; + { + cerr << argv[0] << ": Error opening input file " << argv[1] << "\nExiting.\n"; - return EXIT_FAILURE; - } + return EXIT_FAILURE; + } IOTests_DynamicDiscretisedDensity tests(in); tests.run_tests(); diff --git a/src/test/IO/test_IO_ITKMulticomponent.cxx b/src/test/IO/test_IO_ITKMulticomponent.cxx index e9de82a4c..8db3c6f0a 100644 --- a/src/test/IO/test_IO_ITKMulticomponent.cxx +++ b/src/test/IO/test_IO_ITKMulticomponent.cxx @@ -35,40 +35,43 @@ START_NAMESPACE_STIR 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() override; + void run_tests() override; protected: - - std::string _multi; + std::string _multi; }; -void IOTests_ITKMulticomponent::run_tests() +void +IOTests_ITKMulticomponent::run_tests() { - typedef VoxelsOnCartesianGrid > VoxelsCoords; - - // Read the files - std::cerr << "\nReading: " << _multi << "\n"; + typedef VoxelsOnCartesianGrid> VoxelsCoords; - try { - shared_ptr voxels_coords(read_from_file(_multi)); + // Read the files + std::cerr << "\nReading: " << _multi << "\n"; - check(!is_null_ptr(voxels_coords), "failed reading %s"); + try + { + shared_ptr voxels_coords(read_from_file(_multi)); - // 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(!is_null_ptr(voxels_coords), "failed reading %s"); - // 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 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); - } catch(...) { - everything_ok = false; + // 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; } } @@ -76,16 +79,18 @@ END_NAMESPACE_STD USING_NAMESPACE_STIR -int main(int argc, char **argv) +int +main(int argc, char** argv) { - if (argc != 2) { - std::cerr << "Usage : " << argv[0] << " filename\n"; - return EXIT_FAILURE; + 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 d736992cf..7d42b10a8 100644 --- a/src/test/IO/test_IO_ParametricDiscretisedDensity.cxx +++ b/src/test/IO/test_IO_ParametricDiscretisedDensity.cxx @@ -65,73 +65,83 @@ START_NAMESPACE_STIR class IOTests_ParametricDiscretisedDensity : public IOTests { public: - explicit IOTests_ParametricDiscretisedDensity(istream& in) : IOTests(in) {} + explicit IOTests_ParametricDiscretisedDensity(istream& in) + : IOTests(in) + {} protected: - void create_image() override; - void check_result() override; + void create_image() override; + void check_result() override; }; -void IOTests_ParametricDiscretisedDensity::create_image() +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); + 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() +void +IOTests_ParametricDiscretisedDensity::check_result() { - set_tolerance(.00001); + 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); } } @@ -139,25 +149,27 @@ END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) +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; + 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 a6eb9a5b6..8e3462c99 100644 --- a/src/test/NiftyPET_projector/test_ProjectorNiftyPET_adjoint.cxx +++ b/src/test/NiftyPET_projector/test_ProjectorNiftyPET_adjoint.cxx @@ -38,408 +38,407 @@ using namespace std; 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) +static int +get_rand(const int lower, const int upper) { - return rand() % upper + lower; + return rand() % upper + lower; } -static float get_rand(const float lower, const float upper) +static float +get_rand(const float lower, const float upper) { - return lower + static_cast(rand()) / (static_cast(RAND_MAX/(upper-lower))); + return lower + static_cast(rand()) / (static_cast(RAND_MAX / (upper - lower))); } -static -CartesianCoordinate3D -get_rand_point(const CartesianCoordinate3D &min, const CartesianCoordinate3D &max) +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))); + 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 +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)); + return CartesianCoordinate3D(get_rand(min, max), get_rand(min, max), get_rand(min, max)); } -static float find_max(const ProjDataInMemory &prj) +static float +find_max(const ProjDataInMemory& prj) { - // Get number of elements - unsigned num_elements = prj.size_all(); + // 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() +TestGPUProjectors::set_up() { - std::cerr << "Setting up...\n"; + std::cerr << "Setting up...\n"; - // random seed - srand(time(NULL)); + // random seed + srand(time(NULL)); - set_up_sino(); - set_up_image(); + 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); + 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() +TestGPUProjectors::set_up_image() { - std::cerr << "\tSetting up images...\n"; + 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); + 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)); + _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); + // Fill + _image_sptr->fill(0.f); - // Make projected image a copy - _projected_image_sptr.reset(_image_sptr->clone()); + // Make projected image a copy + _projected_image_sptr.reset(_image_sptr->clone()); } void -TestGPUProjectors:: -set_up_sino() +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); + 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) +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()); + sino.fill_from(arr.begin()); } -static -void -get_random_image(VoxelsOnCartesianGrid &im) +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 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); + // 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"; + // 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) +static void +forward_project(ProjData& sino, const VoxelsOnCartesianGrid& im, ForwardProjectorByBinNiftyPET& projector, double& time) { - std::cerr << "Forward projecting...\n"; - sino.fill(0.f); + 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) +static void +back_project(VoxelsOnCartesianGrid& im, const ProjData& sino, BackProjectorByBinNiftyPET& projector, double& time) { - std::cerr << "Back projecting...\n"; - im.fill(0.f); + 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) +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); + 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) +static float +get_inner_product(const ProjDataInMemory& proj1, const ProjDataInMemory& proj2) { - // Get number of elements - const size_t num_elements = proj1.size_all(); + // 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) +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; + 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; + 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() +TestGPUProjectors::test_adjoints() { - set_up(); + set_up(); - unsigned num_unsuccessful(0); + unsigned num_unsuccessful(0); - while(_results.size() < _num_attempts) { + while (_results.size() < _num_attempts) + { - unsigned i = _results.size(); + unsigned i = _results.size(); - std::cout << "\nPerforming test " << i+1 << " of " << _num_attempts << "\n"; + 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); + // 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); + // 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; + 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"); + else + { + ++num_unsuccessful; + if (num_unsuccessful == 5) + error("Too many (5) unsuccessful comparisons"); } } } void -TestGPUProjectors:: -run_tests() +TestGPUProjectors::run_tests() { - try { - cerr << "Testing whether forward and back projectors are adjoint...\n"; - this->test_adjoints(); + 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 (const std::exception& error) + { + std::cerr << "\nHere's the error:\n\t" << error.what() << "\n\n"; + everything_ok = false; } - catch(...) { - everything_ok = false; + catch (...) + { + everything_ok = false; } } END_NAMESPACE_STIR - USING_NAMESPACE_STIR -void print_usage() +void +print_usage() { - std::cerr << "\n\tUsage: test_ProjectorNiftyPET_adjoint [-h] \n"; + std::cerr << "\n\tUsage: test_ProjectorNiftyPET_adjoint [-h] \n"; } -int main(int argc, char **argv) +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; + set_default_num_threads(); + Verbosity::set(0); + + // 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 9b932a37d..bd1e880d6 100644 --- a/src/test/modelling/test_ParametricDiscretisedDensity.cxx +++ b/src/test/modelling/test_ParametricDiscretisedDensity.cxx @@ -1,23 +1,23 @@ /* Copyright (C) 2006- 2011, Hammersmith Imanet Ltd This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details */ -/*! - +/*! + \file \ingroup test - + \brief testing stir::ParametricDiscretisedDensity class - + \author T. Borgeaud -\author Charalampos Tsoumpas - - - +\author Charalampos Tsoumpas + + + */ #include @@ -54,109 +54,116 @@ START_NAMESPACE_STIR class ParametricDiscretisedDensityTests : public RunTests { public: - ParametricDiscretisedDensityTests() - {} + ParametricDiscretisedDensityTests() {} void run_tests() override; - //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 = - // new ParametricVoxelsOnCartesianGrid(ParametricVoxelsOnCartesianGridBaseType(proj_data_info,zoom,grid_spacing,sizes)); - //ParametricVoxelsOnCartesianGrid & parametric_image = *parametric_image_sptr; + const CartesianCoordinate3D sizes(63, 128, 128); - //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)); + // const shared_ptr parametric_image_sptr = + // new ParametricVoxelsOnCartesianGrid(ParametricVoxelsOnCartesianGridBaseType(proj_data_info,zoom,grid_spacing,sizes)); + // ParametricVoxelsOnCartesianGrid & parametric_image = *parametric_image_sptr; - 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"); + // 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"); 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) + if (num_params != 2) { - warning("test_ParametricDiscretisedDensity test only tests first 2 maps"); + 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; @@ -204,19 +211,20 @@ 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 } @@ -225,7 +233,8 @@ void ParametricDiscretisedDensityTests::run_tests() END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) +int +main(int argc, char** argv) { if (argc != 1) { diff --git a/src/test/modelling/test_modelling.cxx b/src/test/modelling/test_modelling.cxx index 67d9a067c..5bc60b801 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 @@ -17,7 +17,6 @@ See STIR/LICENSE.txt for details */ - #include "stir/RunTests.h" #include "stir/modelling/PatlakPlot.h" #include "stir/modelling/ModelMatrix.h" @@ -39,170 +38,214 @@ class modellingTests : public RunTests explicit modellingTests(const std::string& directory); void run_tests() override; + 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) + + 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(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"); - } + 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) +int +main(int argc, char** argv) { if (argc != 2) - { - std::cerr << "Usage : " << argv[0] << " \n"; - return EXIT_FAILURE; - } + { + std::cerr << "Usage : " << argv[0] << " \n"; + return EXIT_FAILURE; + } modellingTests tests(argv[1]); tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/numerics/BSplines_timing.cxx b/src/test/numerics/BSplines_timing.cxx index 3e6d41b79..87b65367d 100644 --- a/src/test/numerics/BSplines_timing.cxx +++ b/src/test/numerics/BSplines_timing.cxx @@ -5,18 +5,18 @@ This file is part of STIR. SPDX-License-Identifier: Apache-2.0 - + 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" @@ -29,7 +29,6 @@ #include "stir/numerics/BSplines.h" #include "stir/numerics/BSplinesRegularGrid.h" - #include #include #include @@ -40,12 +39,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; @@ -53,115 +49,111 @@ 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++ ) { - cout << " x " << size; - } + 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"; + } - // Set position - 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); } - // 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"; + } - // Set position - 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); } - // Get interpolation. - 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; @@ -172,161 +164,174 @@ 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 ) { + + 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 ) { + } + else if (strcasecmp(optarg, "linear") == 0) + { bs_type = linear; - } else if ( strcasecmp(optarg, "quadratic") == 0 ) { + } + else if (strcasecmp(optarg, "quadratic") == 0) + { bs_type = quadratic; - } else if ( strcasecmp(optarg, "cubic") == 0 ) { + } + else if (strcasecmp(optarg, "cubic") == 0) + { bs_type = cubic; - } else if ( strcasecmp(optarg, "quartic") == 0 ) { + } + else if (strcasecmp(optarg, "quartic") == 0) + { bs_type = quartic; - } else if ( strcasecmp(optarg, "quintic") == 0 ) { + } + else if (strcasecmp(optarg, "quintic") == 0) + { bs_type = quintic; - } else if ( strcasecmp(optarg, "omoms") == 0 ) { + } + 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; - } - + + break; + + case 'd': + dimensions = atoi(optarg); + break; + + case '?': + default: + usage(basename(argv[0])); + exit(0); + break; + } + argc -= optind; - - if ( argc > 0 ) { - usage(basename(argv[0])); - exit(EXIT_FAILURE); - } - - - + + 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 ) { - num = DEF_NUM; - cerr << "Number of interpolations out of range. Reset to: " << num << "\n"; - } - - - - 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++) { - total_elements *= grid_size; + if (num < 1 || num > MAX_NUM) + { + num = DEF_NUM; + cerr << "Number of interpolations out of range. Reset to: " << num << "\n"; } - - if ( total_elements > MAX_TOTAL_GRID_ELEMENTS ) { + + if (grid_size < MIN_SIZE) + { grid_size = DEF_SIZE; - cerr << "Grid size too large for " << dimensions << " dimensions. Reset to: " - << grid_size << "\n"; + cerr << "Grid size too small. Reset to: " << grid_size << "\n"; } - } + else + { + + int total_elements = grid_size; + for (int d = 1; d < dimensions; d++) + { + total_elements *= grid_size; + } + + if (total_elements > MAX_TOTAL_GRID_ELEMENTS) + { + grid_size = DEF_SIZE; + cerr << "Grid size too large for " << dimensions << " dimensions. Reset to: " << grid_size << "\n"; + } + } + if (dimensions < 1 || dimensions > MAX_DIMS) + { + dimensions = DEF_DIMS; + cerr << "Dimensions out of range. Reset to: " << dimensions << "\n"; + } - 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++) + { + size[d] = grid_size; + } - - int size[4] = {0, 0, 0, 0}; - 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++ ) { - data_1[i] = i; - - for (int j = 0 ; j < size[1] ; j++ ) { - data_2[i][j] = i * j; - - - for (int k = 0 ; k < size[2] ; k++) { - data_3[i][j][k] = i * j * k; - - for (int l = 0 ; l < size[3] ; l++) { - data_4[i][j][k][l] = i * j * k * l; + for (int i = 0; i < size[0]; i++) + { + data_1[i] = i; + + for (int j = 0; j < size[1]; j++) + { + data_2[i][j] = i * j; + + for (int k = 0; k < size[2]; k++) + { + data_3[i][j][k] = i * j * k; + + 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 - case 3: - interpolate(num, size[2], bs_type, data_3); - break; + case 1: + interpolate(num, size[0], bs_type, data_1); + break; + + case 2: + interpolate(num, size[1], bs_type, data_2); + break; +#endif + case 3: + interpolate(num, size[2], bs_type, data_3); + break; #ifndef MYLINEAR - case 4: - interpolate(num, size[3], bs_type, data_4); - break; + case 4: + interpolate(num, size[3], bs_type, data_4); + break; #endif - default: - // Do nothing. - break; + default: + // Do nothing. + break; + } - } - - return(0); + return (0); } /* End of Main */ - diff --git a/src/test/numerics/test_BSplines.cxx b/src/test/numerics/test_BSplines.cxx index 77002fc67..46a974095 100644 --- a/src/test/numerics/test_BSplines.cxx +++ b/src/test/numerics/test_BSplines.cxx @@ -9,13 +9,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" @@ -34,414 +34,401 @@ using std::istream; using std::setw; using std::endl; START_NAMESPACE_STIR -namespace BSpline { - /*! - \ingroup test - \brief A simple class to test the BSplines function. - */ - class BSplines_Tests : public RunTests +namespace BSpline +{ +/*! + \ingroup test + \brief A simple class to test the BSplines function. +*/ +class BSplines_Tests : public RunTests +{ +public: + BSplines_Tests() {} + void run_tests() override; + +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"); + } { - public: - BSplines_Tests() - {} - void run_tests() override; - private: - template - bool check_at_sample_points(const std::vector& v, - BSplines1DRegularGrid& interpolator, - const char * const message) + 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"); + } + { + 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"); + } + { + 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; + { + 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"); } { - 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"); + std::vector linear_input; + for (elemT i = 0, imax = 10; i < imax; ++i) + linear_input.push_back(i); + BSplines1DRegularGrid BSplines1DRegularGridTesti(linear_input, linear); + + check_at_sample_points(linear_input, BSplines1DRegularGridTesti, "check BSplines implementation for linear interpolation"); } { - 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 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; { - 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"); + 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_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, quadratic); - 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 quadratic 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, 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: 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(), cubic); + check_at_sample_points( + const_input_sample, BSplines1DRegularGridTest1, "check BSplines implementation for cubic 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"); - } - } + std::vector linear_input; + for (elemT i = 0, imax = 10; i < imax; ++i) + linear_input.push_back(i); + BSplines1DRegularGrid BSplines1DRegularGridTesti(linear_input, cubic); + + check_at_sample_points(linear_input, BSplines1DRegularGridTesti, "check BSplines implementation for cubic 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"); - } - } + BSplines1DRegularGrid 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"); + } { - cerr << "Testing BSplines: o-Moms Interpolation values and constructor using a vector as input..." << endl; + std::vector linear_input; + for (elemT i = 0, imax = 10; i < imax; ++i) + linear_input.push_back(i); + BSplines1DRegularGrid BSplines1DRegularGridTesti(linear_input, oMoms); + + 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) { - 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"); + 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) { - 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"); + STIR_left_output_sample.push_back(BSplines1DRegularGridTests.BSplines_1st_der(i - epsilon)); + STIR_right_output_sample.push_back(BSplines1DRegularGridTests.BSplines_1st_der(i + epsilon)); } - } - { - 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"); - } - { - cerr << "Testing BSplines 1st Derivative Continuity..." << endl; - std::vector new_input_sample, STIR_right_output_sample, STIR_left_output_sample; + 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; - 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"); - } - { - 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 BSplines1DRegularGridTests(input_sample); + for (elemT i = 0, imax = 23; i < imax; ++i) + output_sample_position.push_back((i + 0.5) / 2.4); - std::vector:: iterator cur_iter_stir_out = STIR_output_sample.begin(); + STIR_output_sample = BSplines1DRegularGridTests.BSplines_output_sequence(output_sample_position); - 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(); - out.close(); - }*/ + 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) { - public: - BSplinesRegularGrid_Tests() - {} - void run_tests() override; - private: - template - bool check_at_sample_points(const Array<2,elemT>& v, + 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 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); - } - - 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); - } + 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_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) + 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) { - assign(multidim_epsilon,0); - multidim_epsilon[d]=epsilon; - numerical_gradient[d] = - (interpolator( p+multidim_epsilon) - value) / epsilon; + relative_positions[1] = j + 0.5; + relative_positions[2] = i + 0.5; + out_at_half[j][i] = interpolator(relative_positions); } - return - this->check_if_equal(gradient, numerical_gradient, message); - } + 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_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) + 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) { - 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.); - + 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; + } - { - 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 + 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; + } +}; + +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) { - 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"); + 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 + { + 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 @@ -513,14 +544,15 @@ END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) +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(); + 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 4c126b127..85d0c3e45 100644 --- a/src/test/numerics/test_BSplinesRegularGrid1D.cxx +++ b/src/test/numerics/test_BSplinesRegularGrid1D.cxx @@ -3,17 +3,17 @@ This file is part of STIR. SPDX-License-Identifier: Apache-2.0 - + 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" @@ -26,246 +26,229 @@ using std::cerr; using std::endl; 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 +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() override; + +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 < imax; ++i) + { + relative_positions[1] = i; + out[i] = interpolator(relative_positions); + } + 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.); { - public: - BSplinesRegularGrid1D_Tests() - {} - void run_tests() override; - 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); + 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; - for (int i=0, imax=static_cast(v.size()); i(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; - out[i]=interpolator(relative_positions); - } - std::cout << "IN: " << v << "OUT: " << out; - return - check_if_equal(v, out, message); + 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"); } - - 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.); - { - 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, 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) +int +main(int argc, char** argv) { if (argc != 1) { diff --git a/src/test/numerics/test_Fourier.cxx b/src/test/numerics/test_Fourier.cxx index f0a922334..a615aa87f 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,24 +36,22 @@ 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() +inline float +rand1() { - return 2*(rand()-RAND_MAX/2.F)/RAND_MAX; + return 2 * (rand() - RAND_MAX / 2.F) / RAND_MAX; } /*! @@ -64,91 +61,87 @@ inline float rand1() class FourierTests : public RunTests { public: - FourierTests() - {} + FourierTests() {} void run_tests() override; + private: template void test_single_dimension(const IndexRange& index_range); }; template -void FourierTests::test_single_dimension(const IndexRange& index_range) +void +FourierTests::test_single_dimension(const IndexRange& index_range) { - typedef Array > complex_type; + 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) +int +main(int argc, char** argv) { if (argc != 1) - { - std::cerr << "Usage : " << argv[0] << " \n"; - return EXIT_FAILURE; - } + { + std::cerr << "Usage : " << argv[0] << " \n"; + return EXIT_FAILURE; + } stir::FourierTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/numerics/test_IR_filters.cxx b/src/test/numerics/test_IR_filters.cxx index 35162812a..d4e2fafcd 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 @@ -17,13 +17,11 @@ See STIR/LICENSE.txt for details */ - #include "stir/RunTests.h" #include "stir/numerics/IR_filters.h" #include #include - using std::cerr; using std::endl; @@ -36,115 +34,110 @@ START_NAMESPACE_STIR class IR_filterTests : public RunTests { public: - IR_filterTests() - {} + IR_filterTests() {} void run_tests() override; + 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) + + input_factors.push_back(imax - i); + if (i == 10) break; - - if (i<=5) + + if (i <= 5) poles.push_back(1); 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); + input_factors.push_back(10); } if (i==2) { poles.push_back(1); - input_factors.push_back(9); + 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(); - - 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"); + 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"); } } @@ -152,13 +145,14 @@ END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) +int +main(int argc, char** argv) { if (argc != 1) - { - cerr << "Usage : " << argv[0] << " \n"; - return EXIT_FAILURE; - } + { + cerr << "Usage : " << argv[0] << " \n"; + return EXIT_FAILURE; + } IR_filterTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/numerics/test_erf.cxx b/src/test/numerics/test_erf.cxx index ec1e2f24b..0ffddeed4 100644 --- a/src/test/numerics/test_erf.cxx +++ b/src/test/numerics/test_erf.cxx @@ -9,14 +9,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 "stir/numerics/FastErf.h" @@ -30,8 +30,7 @@ START_NAMESPACE_STIR class erfTests : public RunTests { public: - erfTests() - {} + erfTests() {} void run_tests() override; /*!\brief Tests STIR's erf(x) function against known values */ @@ -39,7 +38,7 @@ class erfTests : public RunTests /*!\brief Tests the FastErf object and its interpolation methods. * This test will construct a FastErf object and compute a range of erf values and compare to erf(x) - */ + */ void test_FastErf(); private: @@ -49,28 +48,28 @@ class erfTests : public RunTests FastErf e; }; - -void erfTests::run_tests() +void +erfTests::run_tests() { std::cerr << "Testing Error Functions..." << std::endl; test_stir_erf(); test_FastErf(); } -void erfTests::test_stir_erf() +void +erfTests::test_stir_erf() { std::cerr << " Testing stir 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; @@ -80,7 +79,7 @@ void erfTests::test_stir_erf() 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; @@ -91,38 +90,29 @@ void erfTests::test_stir_erf() 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; - + output_correct_vector_c[9] = 0.898719406085373116647501836756; - for (int i=0 ; i<10 ; ++i) + for (int i = 0; i < 10; ++i) { - input_vector[i] = 0.01*(static_cast(i)); + input_vector[i] = 0.01 * (static_cast(i)); STIR_vector[i] = erf(input_vector[i]); - STIR_vector_c[i] = erfc(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"); + 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"); + } } void @@ -136,7 +126,7 @@ erfTests::test_FastErf() const float upper_samle_limit = 2 * e.get_maximum_sample_value() + 1; const float lower_samle_limit = -(upper_samle_limit); - double sample_period = _PI/ 10000; // Needed a number that wasn't regular and this worked... + double sample_period = _PI / 10000; // Needed a number that wasn't regular and this worked... // Test the FastErf interpolations 2* beyond the _maximum_sample_value. // The while (-_maximum_sample_value > xp) or (_maximum_sample_value < xp), // xp is clamped to -_maximum_sample_value or _maximum_sample_value @@ -149,12 +139,12 @@ erfTests::test_FastErf() // Test cases where x is just smaller or larger than the lower or upper limits of FastErf // This is an additional sanity check ensure there are no rounding or out of limit errors. - const float epsilon = sample_period/100; + const float epsilon = sample_period / 100; std::vector extremity_test_xps(4); - extremity_test_xps[0] = e.get_maximum_sample_value() + epsilon; // above max - extremity_test_xps[1] = e.get_maximum_sample_value() - epsilon; // under max - extremity_test_xps[2] = -e.get_maximum_sample_value() + epsilon; // above min - extremity_test_xps[3] = -e.get_maximum_sample_value() - epsilon; // under min + extremity_test_xps[0] = e.get_maximum_sample_value() + epsilon; // above max + extremity_test_xps[1] = e.get_maximum_sample_value() - epsilon; // under max + extremity_test_xps[2] = -e.get_maximum_sample_value() + epsilon; // above min + extremity_test_xps[3] = -e.get_maximum_sample_value() - epsilon; // under min for (float xp : extremity_test_xps) { @@ -164,52 +154,52 @@ erfTests::test_FastErf() } } - - -void erfTests::actual_test_FastErf(const float xp) +void +erfTests::actual_test_FastErf(const float xp) { - //BSPlines + // BSPlines check_if_equal(e.get_erf_BSplines_interpolation(xp), erf(xp)); - if (!this->is_everything_ok()){ - std::cerr << "xp = " << xp - << "\tFastErf.get_erf_BSplines_interpolation(xp) = " << e.get_erf_BSplines_interpolation(xp) - << "\terf(xp) = " << erf(xp) << "\n"; - } + if (!this->is_everything_ok()) + { + std::cerr << "xp = " << xp << "\tFastErf.get_erf_BSplines_interpolation(xp) = " << e.get_erf_BSplines_interpolation(xp) + << "\terf(xp) = " << erf(xp) << "\n"; + } // Linear check_if_equal(e.get_erf_linear_interpolation(xp), erf(xp)); - if (!this->is_everything_ok()){ - std::cerr << "linear xp = " << xp - << "\tFastErf.get_erf_linear_interpolation(xp) = " << e.get_erf_linear_interpolation(xp) - << "\terf(xp) = " << erf(xp) << "\n"; - } + if (!this->is_everything_ok()) + { + std::cerr << "linear xp = " << xp << "\tFastErf.get_erf_linear_interpolation(xp) = " << e.get_erf_linear_interpolation(xp) + << "\terf(xp) = " << erf(xp) << "\n"; + } - //NN + // NN check_if_equal(e.get_erf_nearest_neighbour_interpolation(xp), erf(xp)); - if (!this->is_everything_ok()){ - std::cerr << "NN xp = " << xp - << "\tFastErf.get_erf_nearest_neighbour_interpolation(xp) = " << e.get_erf_nearest_neighbour_interpolation(xp) - << "\terf(xp) = " << erf(xp) << "\n"; - } + if (!this->is_everything_ok()) + { + std::cerr << "NN xp = " << xp + << "\tFastErf.get_erf_nearest_neighbour_interpolation(xp) = " << e.get_erf_nearest_neighbour_interpolation(xp) + << "\terf(xp) = " << erf(xp) << "\n"; + } // Operator () - This acts as a wrapper for e.get_erf_linear_interpolation(xp) check_if_equal(e(xp), erf(xp)); - if (!this->is_everything_ok()){ - std::cerr << "NN xp = " << xp - << "\tFastErf(xp) = " << e(xp) - << "\terf(xp) = " << erf(xp) << "\n"; - } + if (!this->is_everything_ok()) + { + std::cerr << "NN xp = " << xp << "\tFastErf(xp) = " << e(xp) << "\terf(xp) = " << erf(xp) << "\n"; + } } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) +int +main(int argc, char** argv) { if (argc != 1) - { - std::cerr << "Usage : " << argv[0] << " \n"; - return EXIT_FAILURE; - } + { + std::cerr << "Usage : " << argv[0] << " \n"; + return EXIT_FAILURE; + } erfTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/numerics/test_integrate_discrete_function.cxx b/src/test/numerics/test_integrate_discrete_function.cxx index 471748265..4dfe59ea2 100644 --- a/src/test/numerics/test_integrate_discrete_function.cxx +++ b/src/test/numerics/test_integrate_discrete_function.cxx @@ -15,9 +15,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" @@ -33,41 +33,42 @@ START_NAMESPACE_STIR class integrate_discrete_functionTests : public RunTests { public: - integrate_discrete_functionTests() - {} + integrate_discrete_functionTests() {} void run_tests() override; }; - -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) + 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); + 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"); + + 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 @@ -76,40 +77,45 @@ 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); + 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); 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) +int +main(int argc, char** argv) { if (argc != 1) - { - std::cerr << "Usage : " << argv[0] << " \n"; - return EXIT_FAILURE; - } + { + std::cerr << "Usage : " << argv[0] << " \n"; + return EXIT_FAILURE; + } integrate_discrete_functionTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/numerics/test_matrices.cxx b/src/test/numerics/test_matrices.cxx index 6efbc49d5..93fd9dcd7 100644 --- a/src/test/numerics/test_matrices.cxx +++ b/src/test/numerics/test_matrices.cxx @@ -8,9 +8,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup numerics_test - + \brief tests for functions in MatrixFunction.h etc. \author Kris Thielemans @@ -27,13 +27,17 @@ #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 @@ -43,6 +47,7 @@ class MatrixTests : public RunTests { public: void run_tests() override; + private: void run_tests_1D(); void run_tests_2D(); @@ -52,29 +57,20 @@ 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> +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)) - ); + 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(); @@ -83,282 +79,218 @@ 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 = + 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)"); +} +} + +{ + 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)"); - } + 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"); - { - // 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)"); - } + 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)"); } -END_NAMESPACE_STIR +{ + // 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() +int +main() { stir::MatrixTests tests; tests.run_tests(); diff --git a/src/test/numerics/test_overlap_interpolate.cxx b/src/test/numerics/test_overlap_interpolate.cxx index c0f1d1ca2..286d46242 100644 --- a/src/test/numerics/test_overlap_interpolate.cxx +++ b/src/test/numerics/test_overlap_interpolate.cxx @@ -27,7 +27,6 @@ START_NAMESPACE_STIR - /*! \brief Test class for stir::overlap_interpolate \ingroup numerics_test @@ -37,73 +36,65 @@ class overlap_interpolateTests : public RunTests { public: void run_tests() override; + 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); + *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; @@ -111,10 +102,7 @@ class overlap_interpolateTests : public RunTests 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; @@ -122,21 +110,18 @@ class overlap_interpolateTests : public RunTests 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) @@ -147,148 +132,147 @@ class overlap_interpolateTests : public RunTests return Succeeded::no; return Succeeded::yes; } - }; void 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(); diff --git a/src/test/test_ArcCorrection.cxx b/src/test/test_ArcCorrection.cxx index e7a5d9b93..cb43fd381 100644 --- a/src/test/test_ArcCorrection.cxx +++ b/src/test/test_ArcCorrection.cxx @@ -41,123 +41,117 @@ 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() override; 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) +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 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 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) + 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"); - } - } + 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() -{ +{ 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); @@ -165,9 +159,7 @@ 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); } } @@ -175,34 +167,35 @@ ArcCorrectionTests::run_tests() 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); - } + 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(); diff --git a/src/test/test_Array.cxx b/src/test/test_Array.cxx index 901c2b460..0baebf827 100644 --- a/src/test/test_Array.cxx +++ b/src/test/test_Array.cxx @@ -11,10 +11,10 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup test \ingroup Array - + \brief tests for the stir::Array class \author Kris Thielemans @@ -23,10 +23,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" @@ -60,21 +60,20 @@ using std::endl; START_NAMESPACE_STIR -namespace detail { +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. */ @@ -84,188 +83,190 @@ class ArrayTests : public RunTests // 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?"); + } 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; - { - 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()); - { - 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 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"); + 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()); + { + 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 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"); + } + //! 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()) + 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; + 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()); + 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()); + 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++; + diff_iter++; + data_read_back_iter++; } return test_failed; } @@ -274,7 +275,6 @@ class ArrayTests : public RunTests void run_tests() override; }; - void ArrayTests::run_tests() { @@ -284,95 +284,99 @@ ArrayTests::run_tests() 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() @@ -380,15 +384,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; @@ -398,89 +401,88 @@ 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; + bool exception_thrown = false; try { t2.at(-4).at(3); } catch (...) { - exception_thrown=true; + 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) + 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"); @@ -488,17 +490,17 @@ ArrayTests::run_tests() } } - 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) + Array<2, int>::full_iterator iter = test.begin_all(); + for (int i = 0; iter != test.end_all(); ++iter, ++i) { *iter = i; } @@ -506,15 +508,15 @@ ArrayTests::run_tests() 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); @@ -524,8 +526,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() @@ -537,97 +539,94 @@ 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)"); } in_place_apply_function(test3ter, std::bind(plus(), std::placeholders::_1, 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)"); // 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) - { - 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"); - } + 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"); + } } // 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 @@ -636,67 +635,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); @@ -704,64 +706,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)"); } { @@ -780,22 +781,22 @@ ArrayTests::run_tests() 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); - - iter_tmp++; - iter_x++; - iter_y++; - iter_by_hand++; - } + { + *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++; + iter_y++; + iter_by_hand++; + } tmp.xapyb(x, 2.0F, y, 3.3F); 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; @@ -817,44 +818,44 @@ ArrayTests::run_tests() 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)); - - iter_tmp++; - iter_x++; - iter_y++; - iter_a++; - iter_b++; - iter_by_hand++; - } + { + *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++; + iter_y++; + iter_a++; + iter_b++; + iter_by_hand++; + } tmp.xapyb(x, a, y, b); 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); } { @@ -862,43 +863,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(); diff --git a/src/test/test_ArrayFilter.cxx b/src/test/test_ArrayFilter.cxx index a931744c0..829cf06a2 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 @@ -30,18 +30,17 @@ #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 @@ -51,322 +50,311 @@ class ArrayFilterTests : public RunTests { public: void run_tests() override; -private: - - -template -void -compare_results_1arg(const ArrayFunctionObject& filter1, - const ArrayFunctionObject& filter2, - const Array& test) -{ +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); - - check_if_equal( out1, out2, "test comparing output of filters, equal length"); - //std::cerr << out1 << out2; + { + 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; + } + { + 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; + } } + + template + void compare_results_2arg(const ArrayFunctionObject& filter1, + const ArrayFunctionObject& filter2, + const Array& test) { - 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.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) + 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) { - 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; + 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() -{ +{ 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); } @@ -374,70 +362,73 @@ 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(); diff --git a/src/test/test_ByteOrder.cxx b/src/test/test_ByteOrder.cxx index 9500e9633..cf40b0568 100644 --- a/src/test/test_ByteOrder.cxx +++ b/src/test/test_ByteOrder.cxx @@ -30,7 +30,6 @@ using std::endl; START_NAMESPACE_STIR - /*! \brief Test class for ByteOrder and the preprocessor defines from ByteOrderDefine.h @@ -51,28 +50,27 @@ ByteOrderTests::run_tests() #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(); diff --git a/src/test/test_DateTime.cxx b/src/test/test_DateTime.cxx index bfaf353ed..830bbae5b 100644 --- a/src/test/test_DateTime.cxx +++ b/src/test/test_DateTime.cxx @@ -10,7 +10,7 @@ */ /*! - \file + \file \ingroup test \ingroup date_time \brief A simple program to test the date-time conversions @@ -23,7 +23,6 @@ #include - START_NAMESPACE_STIR /*! @@ -34,36 +33,40 @@ START_NAMESPACE_STIR class DateTimeTest : public RunTests { void check_round_trip(const double secs, const double tz_offset, const std::string& str); + public: void run_tests() override; }; - void 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("19710202000000+0000") - - (((((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"); - 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"); - 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"); - 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)"); + 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:"); + 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"); + 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"); + 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"); + 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)"); std::cerr << "\nThe next test should throw an error\n"; try @@ -77,23 +80,27 @@ DateTimeTest::run_tests() } // 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"); + 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"); } 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("1971:02:02", "00:00:00+0000")) - - (((((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"); - 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"); - 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"); + 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:"); + 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"); + 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"); + 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"); std::cerr << "\nThe next test should throw an error\n"; try @@ -105,7 +112,6 @@ DateTimeTest::run_tests() { std::cerr << "Test was ok\n"; } - } std::cerr << "\nTesting round-trip\n"; @@ -115,35 +121,32 @@ 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) +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); + check_if_zero(new_secs - secs, str + " : " + time); } { const DateTimeStrings dt = secs_since_Unix_epoch_to_Interfile_datetime(secs, tz_offset); @@ -157,16 +160,12 @@ check_round_trip(const double secs, const double tz_offset, const std::string& s } } - END_NAMESPACE_STIR - - USING_NAMESPACE_STIR - - -int main() +int +main() { DateTimeTest tests; tests.run_tests(); diff --git a/src/test/test_DetectionPosition.cxx b/src/test/test_DetectionPosition.cxx index 915f8ba8c..dff654105 100644 --- a/src/test/test_DetectionPosition.cxx +++ b/src/test/test_DetectionPosition.cxx @@ -2,8 +2,8 @@ // /*! - \file - + \file + \brief A simple program to test the stir::DetectionPosition class \author Kris Thielemans @@ -35,17 +35,16 @@ class DetectionPosition_Tests : public RunTests void run_tests() override; }; - void DetectionPosition_Tests::run_tests() { cerr << "Testing DetectionPosition classes" << endl - <<" (There should be only informative messages here starting with 'Testing')" << endl; + << " (There should be only informative messages here starting with 'Testing')" << endl; - DetectionPosition<> pos012(0,1,2); - DetectionPosition<> pos013(0,1,3); - DetectionPosition<> pos023(0,2,3); - DetectionPosition<> pos103(1,0,3); + DetectionPosition<> pos012(0, 1, 2); + DetectionPosition<> pos013(0, 1, 3); + DetectionPosition<> pos023(0, 2, 3); + DetectionPosition<> pos103(1, 0, 3); check(pos012 != pos013, "012 != 013"); check(pos012 == pos012, "012 == 012"); @@ -58,15 +57,12 @@ DetectionPosition_Tests::run_tests() END_NAMESPACE_STIR - - USING_NAMESPACE_STIR - -int main() +int +main() { DetectionPosition_Tests tests; tests.run_tests(); return tests.main_return_value(); - } diff --git a/src/test/test_DetectorCoordinateMap.cxx b/src/test/test_DetectorCoordinateMap.cxx index f6fa0483b..58e87b68b 100644 --- a/src/test/test_DetectorCoordinateMap.cxx +++ b/src/test/test_DetectorCoordinateMap.cxx @@ -50,149 +50,150 @@ START_NAMESPACE_STIR /*! \ingroup test - \brief Test class for Blocks + \brief Test class for Blocks */ -class DetectionPosMapTests: public RunTests +class DetectionPosMapTests : public RunTests { public: void run_tests() override; float calculate_angle_within_half_bucket(const shared_ptr scanner_ptr, const shared_ptr proj_data_info_ptr); + private: void run_coordinate_test_for_flat_first_bucket(); }; float -DetectionPosMapTests::calculate_angle_within_half_bucket(const shared_ptr scanner_ptr, - const shared_ptr proj_data_info_ptr){ - Bin bin; - LORInAxialAndNoArcCorrSinogramCoordinates lorB; - float csi; - float C_spacing=scanner_ptr->get_transaxial_crystal_spacing(); - float csi_crystal=std::atan((C_spacing)/scanner_ptr->get_effective_ring_radius()); -// float bucket_spacing=scanner_ptr->get_transaxial_block_spacing()*C_spacing; -// float blocks_gap=scanner_ptr->get_transaxial_block_spacing() -// -scanner_ptr->get_num_transaxial_crystals_per_block()*C_spacing; -// float csi_gap=std::atan((blocks_gap)/scanner_ptr->get_effective_ring_radius()); - -// get angle within half bucket - for (int view = 0; view <= scanner_ptr->get_max_num_views(); view++){ - int bucket_num=view/(scanner_ptr->get_num_transaxial_crystals_per_block()*scanner_ptr->get_num_transaxial_blocks_per_bucket()); - if (bucket_num>0) - break; - - bin.segment_num() = 0; - bin.axial_pos_num() = 0; - bin.view_num() = view; - bin.tangential_pos_num() = 0; - - proj_data_info_ptr->get_LOR(lorB,bin); - csi=lorB.phi(); +DetectionPosMapTests::calculate_angle_within_half_bucket( + const shared_ptr scanner_ptr, const shared_ptr proj_data_info_ptr) +{ + Bin bin; + LORInAxialAndNoArcCorrSinogramCoordinates lorB; + float csi; + float C_spacing = scanner_ptr->get_transaxial_crystal_spacing(); + float csi_crystal = std::atan((C_spacing) / scanner_ptr->get_effective_ring_radius()); + // float bucket_spacing=scanner_ptr->get_transaxial_block_spacing()*C_spacing; + // float blocks_gap=scanner_ptr->get_transaxial_block_spacing() + // -scanner_ptr->get_num_transaxial_crystals_per_block()*C_spacing; + // float csi_gap=std::atan((blocks_gap)/scanner_ptr->get_effective_ring_radius()); + + // get angle within half bucket + for (int view = 0; view <= scanner_ptr->get_max_num_views(); view++) + { + int bucket_num + = view / (scanner_ptr->get_num_transaxial_crystals_per_block() * scanner_ptr->get_num_transaxial_blocks_per_bucket()); + if (bucket_num > 0) + break; + + bin.segment_num() = 0; + bin.axial_pos_num() = 0; + bin.view_num() = view; + bin.tangential_pos_num() = 0; + + proj_data_info_ptr->get_LOR(lorB, bin); + csi = lorB.phi(); } - return (csi+csi_crystal)/2; + return (csi + csi_crystal) / 2; } /*! - The following test checks that the y position of the detectors in buckets that are parallel to the x axis are the same. + The following test checks that the y position of the detectors in buckets that are parallel to the x axis are the same. The calculation of csi is only valid for the scanner defined in stir::Scanner, if we modify the number of blocks per bucket csi will be affected. However this does not happen when csi is calculated in the same way we do in the crystal map. */ void DetectionPosMapTests::run_coordinate_test_for_flat_first_bucket() { - CPUTimer timer; - auto scannerBlocks_ptr=std::make_shared (Scanner::SAFIRDualRingPrototype); - - scannerBlocks_ptr->set_scanner_geometry("BlocksOnCylindrical"); - scannerBlocks_ptr->set_num_transaxial_blocks_per_bucket(1); - scannerBlocks_ptr->set_up(); - - - - VectorWithOffset num_axial_pos_per_segment(scannerBlocks_ptr->get_num_rings()*2-1); - VectorWithOffset min_ring_diff_v(scannerBlocks_ptr->get_num_rings()*2-1); - VectorWithOffset max_ring_diff_v(scannerBlocks_ptr->get_num_rings()*2-1); - - for (int i=0; i<2*scannerBlocks_ptr->get_num_rings()-1; i++){ - min_ring_diff_v[i]=-scannerBlocks_ptr->get_num_rings()+1+i; - max_ring_diff_v[i]=-scannerBlocks_ptr->get_num_rings()+1+i; - if (iget_num_rings()) - num_axial_pos_per_segment[i]=i+1; - else - num_axial_pos_per_segment[i]=2*scannerBlocks_ptr->get_num_rings()-i-1; - } - - auto proj_data_info_blocks_ptr=std::make_shared( - scannerBlocks_ptr, - num_axial_pos_per_segment, - min_ring_diff_v, max_ring_diff_v, - scannerBlocks_ptr->get_max_num_views(), - scannerBlocks_ptr->get_max_num_non_arccorrected_bins()); - - Bin bin, bin0=Bin(0,0,0,0); - CartesianCoordinate3D< float> b1,b2,b01,b02; - - // estimate the angle covered by half bucket, csi - float csi; - csi=calculate_angle_within_half_bucket(scannerBlocks_ptr, - proj_data_info_blocks_ptr); - - auto scannerBlocks_firstFlat_ptr=std::make_shared (Scanner::SAFIRDualRingPrototype); - scannerBlocks_firstFlat_ptr->set_scanner_geometry("BlocksOnCylindrical"); - scannerBlocks_firstFlat_ptr->set_num_transaxial_blocks_per_bucket(1); - scannerBlocks_firstFlat_ptr->set_intrinsic_azimuthal_tilt(-csi); - scannerBlocks_firstFlat_ptr->set_up(); - - auto proj_data_info_blocks_firstFlat_ptr=std::make_shared( - scannerBlocks_firstFlat_ptr, - num_axial_pos_per_segment, - min_ring_diff_v, max_ring_diff_v, - scannerBlocks_firstFlat_ptr->get_max_num_views(), - scannerBlocks_firstFlat_ptr->get_max_num_non_arccorrected_bins()); - timer.reset(); timer.start(); - - for (int view = 0; view <= proj_data_info_blocks_firstFlat_ptr->get_max_view_num(); view++) + CPUTimer timer; + auto scannerBlocks_ptr = std::make_shared(Scanner::SAFIRDualRingPrototype); + + scannerBlocks_ptr->set_scanner_geometry("BlocksOnCylindrical"); + scannerBlocks_ptr->set_num_transaxial_blocks_per_bucket(1); + scannerBlocks_ptr->set_up(); + + VectorWithOffset num_axial_pos_per_segment(scannerBlocks_ptr->get_num_rings() * 2 - 1); + VectorWithOffset min_ring_diff_v(scannerBlocks_ptr->get_num_rings() * 2 - 1); + VectorWithOffset max_ring_diff_v(scannerBlocks_ptr->get_num_rings() * 2 - 1); + + for (int i = 0; i < 2 * scannerBlocks_ptr->get_num_rings() - 1; i++) { - int bucket_num=view/(scannerBlocks_firstFlat_ptr->get_num_transaxial_crystals_per_block()* - scannerBlocks_firstFlat_ptr->get_num_transaxial_blocks_per_bucket()); - if (bucket_num>0) - break; - - bin.segment_num() = 0; - bin.axial_pos_num() = 0; - bin.view_num() = view; - bin.tangential_pos_num() = 0; - - - // check cartesian coordinates of detectors - proj_data_info_blocks_firstFlat_ptr->find_cartesian_coordinates_of_detection(b1,b2,bin); - proj_data_info_blocks_firstFlat_ptr->find_cartesian_coordinates_of_detection(b01,b02,bin0); - - - check_if_equal(b1.y(),b01.y(), " checking cartesian coordinate y1 are the same on a flat bucket"); - check_if_equal(b2.y(),b02.y(), " checking cartesian coordinate y2 are the same on a flat bucket"); - check_if_equal(b1.y(),-b2.y(), " checking cartesian coordinate y1 and y2 are of opposite sign on opposite flat buckets"); - + min_ring_diff_v[i] = -scannerBlocks_ptr->get_num_rings() + 1 + i; + max_ring_diff_v[i] = -scannerBlocks_ptr->get_num_rings() + 1 + i; + if (i < scannerBlocks_ptr->get_num_rings()) + num_axial_pos_per_segment[i] = i + 1; + else + num_axial_pos_per_segment[i] = 2 * scannerBlocks_ptr->get_num_rings() - i - 1; } - timer.stop(); std::cerr<< "-- CPU Time " << timer.value() << '\n'; - -} + auto proj_data_info_blocks_ptr + = std::make_shared(scannerBlocks_ptr, + num_axial_pos_per_segment, + min_ring_diff_v, + max_ring_diff_v, + scannerBlocks_ptr->get_max_num_views(), + scannerBlocks_ptr->get_max_num_non_arccorrected_bins()); + + Bin bin, bin0 = Bin(0, 0, 0, 0); + CartesianCoordinate3D b1, b2, b01, b02; + + // estimate the angle covered by half bucket, csi + float csi; + csi = calculate_angle_within_half_bucket(scannerBlocks_ptr, proj_data_info_blocks_ptr); + + auto scannerBlocks_firstFlat_ptr = std::make_shared(Scanner::SAFIRDualRingPrototype); + scannerBlocks_firstFlat_ptr->set_scanner_geometry("BlocksOnCylindrical"); + scannerBlocks_firstFlat_ptr->set_num_transaxial_blocks_per_bucket(1); + scannerBlocks_firstFlat_ptr->set_intrinsic_azimuthal_tilt(-csi); + scannerBlocks_firstFlat_ptr->set_up(); + + auto proj_data_info_blocks_firstFlat_ptr = std::make_shared( + scannerBlocks_firstFlat_ptr, + num_axial_pos_per_segment, + min_ring_diff_v, + max_ring_diff_v, + scannerBlocks_firstFlat_ptr->get_max_num_views(), + scannerBlocks_firstFlat_ptr->get_max_num_non_arccorrected_bins()); + timer.reset(); + timer.start(); + + for (int view = 0; view <= proj_data_info_blocks_firstFlat_ptr->get_max_view_num(); view++) + { + int bucket_num = view + / (scannerBlocks_firstFlat_ptr->get_num_transaxial_crystals_per_block() + * scannerBlocks_firstFlat_ptr->get_num_transaxial_blocks_per_bucket()); + if (bucket_num > 0) + break; + + bin.segment_num() = 0; + bin.axial_pos_num() = 0; + bin.view_num() = view; + bin.tangential_pos_num() = 0; + + // check cartesian coordinates of detectors + proj_data_info_blocks_firstFlat_ptr->find_cartesian_coordinates_of_detection(b1, b2, bin); + proj_data_info_blocks_firstFlat_ptr->find_cartesian_coordinates_of_detection(b01, b02, bin0); + + check_if_equal(b1.y(), b01.y(), " checking cartesian coordinate y1 are the same on a flat bucket"); + check_if_equal(b2.y(), b02.y(), " checking cartesian coordinate y2 are the same on a flat bucket"); + check_if_equal(b1.y(), -b2.y(), " checking cartesian coordinate y1 and y2 are of opposite sign on opposite flat buckets"); + } + timer.stop(); + std::cerr << "-- CPU Time " << timer.value() << '\n'; +} void -DetectionPosMapTests:: -run_tests() +DetectionPosMapTests::run_tests() { - - std::cerr << "-------- Testing DetectorCoordinateMap --------\n"; - run_coordinate_test_for_flat_first_bucket(); + + std::cerr << "-------- Testing DetectorCoordinateMap --------\n"; + run_coordinate_test_for_flat_first_bucket(); } END_NAMESPACE_STIR - USING_NAMESPACE_STIR -int main() +int +main() { DetectionPosMapTests tests; tests.run_tests(); diff --git a/src/test/test_DynamicDiscretisedDensity.cxx b/src/test/test_DynamicDiscretisedDensity.cxx index 5ab4c00b2..9f6b873cb 100644 --- a/src/test/test_DynamicDiscretisedDensity.cxx +++ b/src/test/test_DynamicDiscretisedDensity.cxx @@ -41,258 +41,289 @@ using std::endl; using std::string; START_NAMESPACE_STIR - - class DynamicDiscretisedDensityTests : public RunTests - { - public: - DynamicDiscretisedDensityTests() - {} - void run_tests() override; - //private: - }; - - void DynamicDiscretisedDensityTests::run_tests() + +class DynamicDiscretisedDensityTests : public RunTests +{ +public: + DynamicDiscretisedDensityTests() {} + void run_tests() override; + // 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 - { - 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()) - { - 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()) - { - ok_upto_now = check_if_equal(*dyn_dens_iter++, *dens_iter++, "check full-iterator: frame 1"); - } + 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"); } -#ifndef HAVE_LLN_MATRIX - 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 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()) { - 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"); + ok_upto_now = check_if_equal(*dyn_dens_iter++, *dens_iter++, "check full-iterator: frame 1"); } - 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 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()) + { + 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"); +#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 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"); // 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) +int +main(int argc, char** argv) { if (argc != 1) - { - cerr << "Usage : " << argv[0] << " \n"; - return EXIT_FAILURE; - } + { + cerr << "Usage : " << argv[0] << " \n"; + return EXIT_FAILURE; + } DynamicDiscretisedDensityTests tests; tests.run_tests(); return tests.main_return_value(); diff --git a/src/test/test_GeneralisedPoissonNoiseGenerator.cxx b/src/test/test_GeneralisedPoissonNoiseGenerator.cxx index a40b56779..31d49cdb1 100644 --- a/src/test/test_GeneralisedPoissonNoiseGenerator.cxx +++ b/src/test/test_GeneralisedPoissonNoiseGenerator.cxx @@ -8,10 +8,10 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup test \ingroup buildblock - + \brief tests for the stir::GeneralisedPoissonNoiseGenerator class \author Kris Thielemans @@ -28,7 +28,6 @@ START_NAMESPACE_STIR - /*! \brief Tests GeneralisedPoissonNoiseGenerator functionality \ingroup test @@ -37,40 +36,41 @@ START_NAMESPACE_STIR 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() override; }; void -GeneralisedPoissonNoiseGeneratorTests:: -run_one_test(const int size, const float mu, const float scaling_factor, const bool preserve_mean) +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); + 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()); } @@ -94,7 +94,8 @@ END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() +int +main() { GeneralisedPoissonNoiseGeneratorTests tests; tests.run_tests(); diff --git a/src/test/test_ImagingModality.cxx b/src/test/test_ImagingModality.cxx index d5c84509c..9c40bc466 100644 --- a/src/test/test_ImagingModality.cxx +++ b/src/test/test_ImagingModality.cxx @@ -28,7 +28,6 @@ using std::endl; START_NAMESPACE_STIR - /*! \brief Test class for ImagingModality \ingroup buildblock @@ -62,12 +61,12 @@ ImagingModalityTests::run_tests() } } - END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() +int +main() { ImagingModalityTests tests; tests.run_tests(); diff --git a/src/test/test_IndexRange.cxx b/src/test/test_IndexRange.cxx index 46082f6f4..5f7af5b97 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 @@ -42,103 +42,86 @@ class IndexRange_Tests : public RunTests void run_tests() override; }; - void 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)) - { - 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"); - } + { + 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"); - } + { + 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 3795559b6..d3d650335 100644 --- a/src/test/test_KeyParser.cxx +++ b/src/test/test_KeyParser.cxx @@ -3,7 +3,7 @@ /* Copyright (C) 2020, 2024, University College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 See STIR/LICENSE.txt for details @@ -32,9 +32,8 @@ class TestKP : public KeyParser { public: TestKP() - : - scalar_v(0), - vector_v(2,0) + : scalar_v(0), + vector_v(2, 0) { add_start_key("start"); add_stop_key("stop"); @@ -49,8 +48,7 @@ class TestKP : public KeyParser std::vector vector_v; bool operator==(TestKP& other) const { - return scalar_v == other.scalar_v && - std::equal(vector_v.begin(),vector_v.end(), other.vector_v.begin()); + return scalar_v == other.scalar_v && std::equal(vector_v.begin(), vector_v.end(), other.vector_v.begin()); } }; @@ -62,7 +60,8 @@ class TestKP : public KeyParser class KeyParserTests : public RunTests { public: - template void run_tests_one_type(); + template + void run_tests_one_type(); void run_tests() override; }; @@ -86,8 +85,8 @@ KeyParserTests::run_tests_one_type() { // basic test if parsing ok { - TestKP parser; - TestKP parser2; + TestKP parser; + TestKP parser2; std::stringstream str; str << "start:=\n" << "scalar:=2\n" @@ -101,8 +100,8 @@ KeyParserTests::run_tests_one_type() } // test alias { - TestKP parser; - TestKP parser2; + TestKP parser; + TestKP parser2; std::stringstream str; str << "start:=\n" << "new alias:=2\n" @@ -131,7 +130,7 @@ KeyParserTests::run_tests_one_type() } // test 1 if parsing catches errors { - TestKP parser; + TestKP parser; std::stringstream str; str << "start:=\n" << "scalar[1]:=2\n" @@ -139,7 +138,7 @@ KeyParserTests::run_tests_one_type() << "stop :=\n"; try { - std::cerr << "\nNext test should write an error (but not crash!)" << std::endl; + std::cerr << "\nNext test should write an error (but not crash!)" << std::endl; parser.parse(str); check(false, "parsing non-vectorised key with vector should have failed"); } @@ -150,7 +149,7 @@ KeyParserTests::run_tests_one_type() } // test 2 if parsing catches errors { - TestKP parser; + TestKP parser; std::stringstream str; str << "start:=\n" << "scalar:=2\n" @@ -158,7 +157,7 @@ KeyParserTests::run_tests_one_type() << "stop :=\n"; try { - std::cerr << "\nNext test should write an error (but not crash!)" << std::endl; + std::cerr << "\nNext test should write an error (but not crash!)" << std::endl; parser.parse(str); check(false, "parsing vectorised key with non-vector should have failed"); } @@ -167,16 +166,14 @@ KeyParserTests::run_tests_one_type() // ok } } - } END_NAMESPACE_STIR - USING_NAMESPACE_STIR - -int main() +int +main() { KeyParserTests tests; tests.run_tests(); diff --git a/src/test/test_ML_norm.cxx b/src/test/test_ML_norm.cxx index 5731ed51c..14ed2e2b5 100644 --- a/src/test/test_ML_norm.cxx +++ b/src/test/test_ML_norm.cxx @@ -40,11 +40,12 @@ START_NAMESPACE_STIR \ingroup test \brief Test class for ML_norm.h functions */ -class ML_normTests: public RunTests +class ML_normTests : public RunTests { public: void run_tests() override; -protected: + +protected: template void test_proj_data_info(shared_ptr proj_data_info_sptr); }; @@ -56,22 +57,24 @@ ML_normTests::run_tests() std::cerr << "\n-------- Testing ECAT 953 --------\n"; shared_ptr scanner_sptr(new Scanner(Scanner::E953)); shared_ptr proj_data_info_sptr( - ProjDataInfo::construct_proj_data_info(scanner_sptr, - /*span*/1, scanner_sptr->get_num_rings()-1, - /*views*/ scanner_sptr->get_num_detectors_per_ring()/2, - /*tang_pos*/64, - /*arc_corrected*/ false)); + ProjDataInfo::construct_proj_data_info(scanner_sptr, + /*span*/ 1, + scanner_sptr->get_num_rings() - 1, + /*views*/ scanner_sptr->get_num_detectors_per_ring() / 2, + /*tang_pos*/ 64, + /*arc_corrected*/ false)); test_proj_data_info(dynamic_pointer_cast(proj_data_info_sptr)); } { std::cerr << "\n-------- Testing ECAT E1080 (with gaps) --------\n"; shared_ptr scanner_sptr(new Scanner(Scanner::E1080)); shared_ptr proj_data_info_sptr( - ProjDataInfo::construct_proj_data_info(scanner_sptr, - /*span*/1, scanner_sptr->get_num_rings()-1, - /*views*/ scanner_sptr->get_num_detectors_per_ring()/2, - /*tang_pos*/64, - /*arc_corrected*/ false)); + ProjDataInfo::construct_proj_data_info(scanner_sptr, + /*span*/ 1, + scanner_sptr->get_num_rings() - 1, + /*views*/ scanner_sptr->get_num_detectors_per_ring() / 2, + /*tang_pos*/ 64, + /*arc_corrected*/ false)); test_proj_data_info(dynamic_pointer_cast(proj_data_info_sptr)); } { @@ -80,61 +83,59 @@ ML_normTests::run_tests() scanner_sptr->set_scanner_geometry("BlocksOnCylindrical"); scanner_sptr->set_up(); shared_ptr proj_data_info_sptr( - ProjDataInfo::construct_proj_data_info(scanner_sptr, - /*span*/1, scanner_sptr->get_num_rings()-1, - /*views*/ scanner_sptr->get_num_detectors_per_ring()/2, - /*tang_pos*/64, - /*arc_corrected*/ false)); + ProjDataInfo::construct_proj_data_info(scanner_sptr, + /*span*/ 1, + scanner_sptr->get_num_rings() - 1, + /*views*/ scanner_sptr->get_num_detectors_per_ring() / 2, + /*tang_pos*/ 64, + /*arc_corrected*/ false)); test_proj_data_info(dynamic_pointer_cast(proj_data_info_sptr)); } } template -void ML_normTests:: -test_proj_data_info(shared_ptr proj_data_info_sptr) +void +ML_normTests::test_proj_data_info(shared_ptr proj_data_info_sptr) { if (!check(proj_data_info_sptr != nullptr, "check type of proj_data_info")) return; - //const int num_detectors = proj_data_info.get_scanner_ptr()->get_num_detectors_per_ring(); + // const int num_detectors = proj_data_info.get_scanner_ptr()->get_num_detectors_per_ring(); auto exam_info_sptr = std::make_shared(); ProjDataInMemory proj_data(exam_info_sptr, proj_data_info_sptr); proj_data.fill(1.F); - const int num_virtual_axial_crystals_per_block = - proj_data_info_sptr->get_scanner_sptr()-> - get_num_virtual_axial_crystals_per_block(); - const int num_virtual_transaxial_crystals_per_block = - proj_data_info_sptr->get_scanner_sptr()-> - get_num_virtual_transaxial_crystals_per_block(); - const int num_transaxial_crystals_per_block = - proj_data_info_sptr->get_scanner_sptr()-> - get_num_transaxial_crystals_per_block(); - const int num_axial_crystals_per_block = - proj_data_info_sptr->get_scanner_sptr()-> - get_num_axial_crystals_per_block(); - const int num_physical_transaxial_crystals_per_block = num_transaxial_crystals_per_block - num_virtual_transaxial_crystals_per_block; - //const int num_physical_axial_crystals_per_block = num_axial_crystals_per_block - num_virtual_axial_crystals_per_block; - const int num_physical_rings = - proj_data_info_sptr->get_scanner_sptr()->get_num_rings() - - (proj_data_info_sptr->get_scanner_sptr()->get_num_axial_blocks()-1)*num_virtual_axial_crystals_per_block; - const int num_physical_detectors_per_ring = - proj_data_info_sptr->get_scanner_sptr()->get_num_detectors_per_ring() - - proj_data_info_sptr->get_scanner_sptr()->get_num_transaxial_blocks()*num_virtual_transaxial_crystals_per_block; + const int num_virtual_axial_crystals_per_block + = proj_data_info_sptr->get_scanner_sptr()->get_num_virtual_axial_crystals_per_block(); + const int num_virtual_transaxial_crystals_per_block + = proj_data_info_sptr->get_scanner_sptr()->get_num_virtual_transaxial_crystals_per_block(); + const int num_transaxial_crystals_per_block = proj_data_info_sptr->get_scanner_sptr()->get_num_transaxial_crystals_per_block(); + const int num_axial_crystals_per_block = proj_data_info_sptr->get_scanner_sptr()->get_num_axial_crystals_per_block(); + const int num_physical_transaxial_crystals_per_block + = num_transaxial_crystals_per_block - num_virtual_transaxial_crystals_per_block; + // const int num_physical_axial_crystals_per_block = num_axial_crystals_per_block - num_virtual_axial_crystals_per_block; + const int num_physical_rings + = proj_data_info_sptr->get_scanner_sptr()->get_num_rings() + - (proj_data_info_sptr->get_scanner_sptr()->get_num_axial_blocks() - 1) * num_virtual_axial_crystals_per_block; + const int num_physical_detectors_per_ring + = proj_data_info_sptr->get_scanner_sptr()->get_num_detectors_per_ring() + - proj_data_info_sptr->get_scanner_sptr()->get_num_transaxial_blocks() * num_virtual_transaxial_crystals_per_block; FanProjData fan_data; make_fan_data_remove_gaps(fan_data, proj_data); { ProjDataInMemory proj_data2(proj_data); proj_data2.fill(0.F); - set_fan_data_add_gaps(proj_data2, fan_data, /*gap_value=*/ 1.F); + set_fan_data_add_gaps(proj_data2, fan_data, /*gap_value=*/1.F); { // test if the same after round-trip if we fill the gap // proj_data2 -= proj_data; proj_data2.sapyb(1.F, proj_data, -1.F); - check_if_zero(norm_squared(proj_data2.begin(), proj_data2.end())/square(static_cast(proj_data_info_sptr->size_all())), "projdata <-> fandata with gap filled"); + check_if_zero(norm_squared(proj_data2.begin(), proj_data2.end()) + / square(static_cast(proj_data_info_sptr->size_all())), + "projdata <-> fandata with gap filled"); } - set_fan_data_add_gaps(proj_data2, fan_data, /*gap_value=*/ 0.F); + set_fan_data_add_gaps(proj_data2, fan_data, /*gap_value=*/0.F); { // test round-trip if we do not fill the gap { @@ -142,15 +143,16 @@ test_proj_data_info(shared_ptr proj_data_info_sptr) // test view 0, should have a values 1,1,1,...,0 (starting from the middle) const int view_num = 0; const int axial_pos_num = 0; - for (int seg_num = -1; seg_num<=1; ++seg_num) - for (int tangential_pos_num = 0; tangential_pos_num<=proj_data2.get_max_tangential_pos_num(); ++tangential_pos_num) + for (int seg_num = -1; seg_num <= 1; ++seg_num) + for (int tangential_pos_num = 0; tangential_pos_num <= proj_data2.get_max_tangential_pos_num(); ++tangential_pos_num) { Bin bin(seg_num, view_num, axial_pos_num, tangential_pos_num); proj_data2.get_bin_value(bin); const float value = bin.get_bin_value(); proj_data.get_bin_value(bin); const float org_value = bin.get_bin_value(); - const bool in_gap = (tangential_pos_num%num_transaxial_crystals_per_block) >= num_physical_transaxial_crystals_per_block; + const bool in_gap + = (tangential_pos_num % num_transaxial_crystals_per_block) >= num_physical_transaxial_crystals_per_block; if (in_gap) check_if_zero(value, "projdata <-> fandata with gap zero: in gap (sino)"); else @@ -160,10 +162,10 @@ test_proj_data_info(shared_ptr proj_data_info_sptr) if (num_virtual_axial_crystals_per_block > 0) { // test a sinogram in segment 0 in the gap - const Sinogram sino = proj_data2.get_sinogram(num_axial_crystals_per_block-1, /* segment*/ 0); + const Sinogram sino = proj_data2.get_sinogram(num_axial_crystals_per_block - 1, /* segment*/ 0); if (!check_if_zero(sino.find_max(), "projdata <-> fandata with gap zero: in gap (axial)")) { - const std::string filename = "test_gaps_" + proj_data_info_sptr->get_scanner_sptr()->get_name() + ".hs"; + const std::string filename = "test_gaps_" + proj_data_info_sptr->get_scanner_sptr()->get_name() + ".hs"; std::cerr << "writing filled data with gaps to file for debugging " << filename << "\n"; proj_data2.write_to_file(filename); } @@ -173,7 +175,7 @@ test_proj_data_info(shared_ptr proj_data_info_sptr) // test make_fan_sum_data if there are no gaps. In this case, all fan sums should be equal if (num_virtual_transaxial_crystals_per_block == 0 && num_virtual_axial_crystals_per_block == 0) { - Array<2,float> data_fan_sums(IndexRange2D(num_physical_rings, num_physical_detectors_per_ring)); + Array<2, float> data_fan_sums(IndexRange2D(num_physical_rings, num_physical_detectors_per_ring)); make_fan_sum_data(data_fan_sums, fan_data); check_if_equal(data_fan_sums.find_min(), data_fan_sums.find_max(), "make_fan_sum_data (no gaps)"); } @@ -183,10 +185,10 @@ test_proj_data_info(shared_ptr proj_data_info_sptr) END_NAMESPACE_STIR - USING_NAMESPACE_STIR -int main() +int +main() { set_default_num_threads(); diff --git a/src/test/test_NestedIterator.cxx b/src/test/test_NestedIterator.cxx index 82ea273c0..f6977651c 100644 --- a/src/test/test_NestedIterator.cxx +++ b/src/test/test_NestedIterator.cxx @@ -8,9 +8,9 @@ */ /*! - \file + \file \ingroup test - + \brief tests for the stir::NestedIterator class \author Kris Thielemans @@ -39,12 +39,10 @@ START_NAMESPACE_STIR class NestedIteratorTests : public RunTests { private: - public: void run_tests() override; }; - void NestedIteratorTests::run_tests() { @@ -53,378 +51,351 @@ NestedIteratorTests::run_tests() { 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(); - ) + 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"); + check(*fiter++ == *iter++, "fiter=="); } - - check(fiter==fiter_end,"fiter end"); + + 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(); - ) + for (Array<2, elemT>::full_iterator iter = test2.begin_all(); iter != test2.end_all();) { - *iter++ = make_coordinate(value,value+.3F); + *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(); - ) + 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"); + 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(); - ) + for (Array<2, elemT>::full_iterator iter = test.begin_all(); iter != test.end_all();) { - *iter++ = make_coordinate(value,value+.3F); + *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(); - ) + 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"); + 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(); - ) + for (Array<2, elemT>::full_iterator iter = test2.begin_all(); iter != test2.end_all();) { - *iter++ = make_coordinate(value,value+.3F); + *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(); - ) + 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"); + 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(); - ) + for (Array<2, elemT>::full_iterator iter = test.begin_all(); iter != test.end_all();) { - *iter++ = make_coordinate(value,value+.3F); + *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(); - ) + 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"); + 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(); - ) + for (Array<2, elemT>::full_iterator iter = test2.begin_all(); iter != test2.end_all();) { - *iter++ = make_coordinate(value,value+.3F); + *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(); - ) + 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"); + 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; + 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(*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; + 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(*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; + 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(*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; + 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(*fiter++, count++, "nestiterator of vector< list *>"); + } check_if_equal(count, 6, "nestiterator of vector: num elements"); } delete c[0]; 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; + 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(*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"); } // const iterator { - typedef NestedIterator > FullIter; - FullIter fiter(c.begin(),c.end()); - const FullIter fiter_end(c.end(),c.end()); - count=1; + 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(*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"); } } - } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() +int +main() { NestedIteratorTests tests; tests.run_tests(); diff --git a/src/test/test_OutputFileFormat.cxx b/src/test/test_OutputFileFormat.cxx index e7c1f2ec2..2709bd365 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. @@ -30,11 +30,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" @@ -66,30 +66,30 @@ 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 { public: - OutputFileFormatTests(istream& in) ; + OutputFileFormatTests(istream& in); void run_tests() override; + 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"); @@ -97,16 +97,16 @@ OutputFileFormatTests(istream& in) : 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" @@ -115,7 +115,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 @@ -123,116 +123,102 @@ void OutputFileFormatTests::run_tests() USING_NAMESPACE_ECAT6 // 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; - const bool supports_origin_z_shift = - dynamic_cast(output_file_format_ptr.get()) == 0 - ? true : false; - const bool supports_origin_xy_shift = - true; + const bool supports_different_xy_pixel_sizes + = 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; #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); + CartesianCoordinate3D origin(0.F, 0.F, 0.F); if (supports_origin_xy_shift) - { origin.x()=2.4F; origin.y() = -3.5F; } + { + 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); + { + 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")) + 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"); - } + // 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"; - + cerr << "You can check what was written in STIRtmp.*\n"; } - - - } - END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main(int argc, char **argv) +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; - } - + { + 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"; + { + cerr << argv[0] << ": Error opening input file " << argv[1] << "\nExiting.\n"; - return EXIT_FAILURE; - } + return EXIT_FAILURE; + } OutputFileFormatTests tests(in); tests.run_tests(); diff --git a/src/test/test_ROIs.cxx b/src/test/test_ROIs.cxx index 77f20e061..f31801eeb 100644 --- a/src/test/test_ROIs.cxx +++ b/src/test/test_ROIs.cxx @@ -12,15 +12,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 */ @@ -44,7 +44,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 @@ -57,155 +57,149 @@ 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 { public: void run_tests() override; + 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, - const bool do_separate_translate_test=true); + VoxelsOnCartesianGrid& image, + const bool do_rotated_ROI_test = true, + const bool do_separate_translate_test = true); }; void ROITests::run_tests_one_shape(Shape3D& shape, - VoxelsOnCartesianGrid& image, - const bool do_rotated_ROI_test, - const bool do_separate_translate_test) + VoxelsOnCartesianGrid& image, + const bool do_rotated_ROI_test, + const bool do_separate_translate_test) { - shape.construct_volume(image, Coordinate3D(1,1,1)); + 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)); + 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 + *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 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 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) + { + 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); + } + // test on translation (image and shape translate separately) + if (do_separate_translate_test) { - 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); - } - } - // 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 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); - } - // test on translation (image and shape translate separately) - if (do_separate_translate_test) - { - 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)); + 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) + // 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]; + 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)); - + + 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 + // 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); - } + 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)); + new_shape_sptr->construct_volume(image2, Coordinate3D(1, 1, 1)); image2 *= 4; image2 -= image; image2 += 2; @@ -213,53 +207,49 @@ ROITests::run_tests_one_shape(Shape3D& shape, #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())); + 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(); + // std::cerr << new_shape_sptr->parameter_info(); + + const ROIValues ROI_values = compute_total_ROI_values(image, *new_shape_sptr, Coordinate3D(1, 1, 1)); - 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_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 + // 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); - } + 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); + } #ifdef test_ROIs_DISPLAY VoxelsOnCartesianGrid image2 = image; - new_shape_sptr->construct_volume(image2, Coordinate3D(1,1,1)); + 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) + // test on parsing + if (dynamic_cast(&shape) == 0) { shared_ptr shape_sptr(shape.clone()); KeyParser parser; @@ -270,36 +260,31 @@ ROITests::run_tests_one_shape(Shape3D& shape, 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(); - } - } - } + 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. @@ -307,76 +292,74 @@ 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); } // need to fill in image again, as the tests change it @@ -389,20 +372,15 @@ ROITests::run_tests() discretised_shape.set_label_index(2); this->run_tests_one_shape(discretised_shape, image, false, false); } - - - } - } END_NAMESPACE_STIR - USING_NAMESPACE_STIR - -int main() +int +main() { ROITests tests; tests.run_tests(); diff --git a/src/test/test_Scanner.cxx b/src/test/test_Scanner.cxx index ef44e8192..c4582b4f0 100644 --- a/src/test/test_Scanner.cxx +++ b/src/test/test_Scanner.cxx @@ -24,12 +24,13 @@ #include "stir/shared_ptr.h" #include "stir/warning.h" #ifdef HAVE_LLN_MATRIX -#include "ecat_model.h" -extern "C" { - EcatModel *ecat_model(int); +# include "ecat_model.h" +extern "C" +{ + EcatModel* ecat_model(int); } -#include "stir/IO/stir_ecat_common.h" +# include "stir/IO/stir_ecat_common.h" #endif #include #include @@ -44,47 +45,44 @@ START_NAMESPACE_STIR \ingroup test \brief Test class for Scanner */ -class ScannerTests: public RunTests +class ScannerTests : public RunTests { -public: +public: void run_tests() override; + private: void test_scanner(const Scanner&); }; - void -ScannerTests:: -run_tests() +ScannerTests::run_tests() { - Scanner::Type type= Scanner::E931; + Scanner::Type type = Scanner::E931; while (type != Scanner::Unknown_scanner) - { - if (type!=Scanner::User_defined_scanner && - type!=Scanner::UPENN_5rings) - test_scanner(Scanner(type)); - // tricky business to find next type - int int_type = type; - ++int_type; - type = static_cast(int_type); - } + { + if (type != Scanner::User_defined_scanner && type != Scanner::UPENN_5rings) + test_scanner(Scanner(type)); + // tricky business to find next type + int int_type = type; + ++int_type; + type = static_cast(int_type); + } } 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. @@ -97,70 +95,69 @@ test_scanner(const Scanner& scanner) scanner.get_type() != Scanner::DiscoverySTE && 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) - 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()); - } + { + 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()); + } // (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 - { - // compare with info from ecat_model - - cerr << "Comparing STIR scanner info with LLN matrix\n"; - short ecat_type = ecat::find_ECAT_system_type(scanner); - if (ecat_type==0) - return; - - 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"); - 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_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"); - check_if_equal(scanner.get_num_axial_crystals_per_block(), ecat_scanner_info->axialCrystalsPerBlock, - "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)"); - } + { + // compare with info from ecat_model + + cerr << "Comparing STIR scanner info with LLN matrix\n"; + short ecat_type = ecat::find_ECAT_system_type(scanner); + if (ecat_type == 0) + return; + + 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"); + 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_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"); + check_if_equal(scanner.get_num_axial_crystals_per_block(), + ecat_scanner_info->axialCrystalsPerBlock, + "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)"); + } #endif -} +} END_NAMESPACE_STIR - -int main() +int +main() { -USING_NAMESPACE_STIR + USING_NAMESPACE_STIR ScannerTests tests; tests.run_tests(); diff --git a/src/test/test_ScatterSimulation.cxx b/src/test/test_ScatterSimulation.cxx index 60dcac69c..d8d4e5b16 100644 --- a/src/test/test_ScatterSimulation.cxx +++ b/src/test/test_ScatterSimulation.cxx @@ -30,11 +30,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" @@ -55,189 +55,193 @@ START_NAMESPACE_STIR \ingroup scatter \brief Test class for ScatterSimulation */ -class ScatterSimulationTests: public RunTests +class ScatterSimulationTests : public RunTests { -public: - bool write_output; - void run_tests() override; -private: +public: + bool write_output; + void run_tests() override; - //! 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)); - - // 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))); + 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))); - unique_ptr sss(new SingleScatterSimulation()); - sss->set_template_proj_data_info(*original_projdata); - { - auto sss_projdata = dynamic_cast(sss->get_template_proj_data_info_sptr().get()); - check(*original_projdata == *sss_projdata, "Check the ProjDataInfo has been set correctly."); - } + unique_ptr sss(new SingleScatterSimulation()); + sss->set_template_proj_data_info(*original_projdata); + { + auto sss_projdata = dynamic_cast(sss->get_template_proj_data_info_sptr().get()); + 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); - - sss->downsample_scanner(down_rings, down_dets); - auto sss_projdata = dynamic_cast(sss->get_template_proj_data_info_sptr().get()); - 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)"); - } + // 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 = dynamic_cast(sss->get_template_proj_data_info_sptr().get()); + 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() +void +ScatterSimulationTests::test_downsampling_DiscretisedDensity() { - 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))); - // Create an appropriate image for the projdata. - shared_ptr > tmpl_density( new VoxelsOnCartesianGrid(*original_projdata)); + // Create an appropriate image for the projdata. + shared_ptr> tmpl_density(new VoxelsOnCartesianGrid(*original_projdata)); + 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()); - 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()); + CartesianCoordinate3D num_samples(3, 3, 3); + shared_ptr> water_density(tmpl_density->clone()); + 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); -// int total_scatter_points_orig = sss.get_num_scatter_points(); + auto downed_image = sss->get_density_image_for_scatter_points_sptr(); - sss->downsample_density_image_for_scatter_points(0.5f, 0.5f, 1); - - auto downed_image = sss->get_density_image_for_scatter_points_sptr(); + float mean_value_atten = 0.0f; + int atten_counter = 0; + 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; - - 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())); - 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 @@ -252,9 +256,9 @@ ScatterSimulationTests::test_symmetric(ScatterSimulation& ss, const std::string& 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()); + 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"; @@ -264,12 +268,13 @@ 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); } @@ -284,36 +289,31 @@ void 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_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 = 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); } @@ -327,227 +327,223 @@ ScatterSimulationTests::test_output_is_symmetric(const ProjData& proj_data, cons void ScatterSimulationTests::test_scatter_simulation() { - unique_ptr sss(new SingleScatterSimulation()); + 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(); + 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; + 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()) + if (!test_scanner->has_energy_information()) { - test_scanner->set_reference_energy(511); - test_scanner->set_energy_resolution(0.34f); + test_scanner->set_reference_energy(511); + test_scanner->set_energy_resolution(0.34f); } - check(test_scanner->has_energy_information() == true, "Check the scanner has energy information."); + check(test_scanner->has_energy_information() == true, "Check the scanner has energy information."); - shared_ptr exam(new ExamInfo); - exam->set_low_energy_thres(450); - exam->set_high_energy_thres(650); - exam->imaging_modality = ImagingModality::PT; + shared_ptr exam(new ExamInfo); + exam->set_low_energy_thres(450); + exam->set_high_energy_thres(650); + exam->imaging_modality = ImagingModality::PT; - check(exam->has_energy_information() == true, "Check the ExamInfo has energy information."); + check(exam->has_energy_information() == true, "Check the ExamInfo has energy information."); - sss->set_exam_info(*exam); + sss->set_exam_info(*exam); - // 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))); + // 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))); - check(original_projdata_info->has_energy_information() == true, "Check the ProjDataInfo has energy information."); + check(original_projdata_info->has_energy_information() == true, "Check the ProjDataInfo has energy information."); - shared_ptr > tmpl_density( new VoxelsOnCartesianGrid(exam, *original_projdata_info)); + shared_ptr> tmpl_density(new VoxelsOnCartesianGrid(exam, *original_projdata_info)); - //// 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 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); + 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); + //// 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); - ////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); + ////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 settings - sss->set_randomly_place_scatter_points(false); + //// 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); + 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() +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(); + 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(); } diff --git a/src/test/test_SeparableGaussianArrayFilter.cxx b/src/test/test_SeparableGaussianArrayFilter.cxx index f59984812..2a3ccc67f 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 @@ -33,7 +33,6 @@ START_NAMESPACE_STIR - #define num_dimensions 3 /*! @@ -47,27 +46,26 @@ class SeparableGaussianArrayFilterTests : public RunTests { public: void run_tests() override; + 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); - + 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); @@ -76,11 +74,11 @@ 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) + 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]); + 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); @@ -88,37 +86,44 @@ test_one(Array& test, void 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(); diff --git a/src/test/test_SeparableMetzArrayFilter.cxx b/src/test/test_SeparableMetzArrayFilter.cxx index 994ef263b..108471e99 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 @@ -31,7 +31,6 @@ START_NAMESPACE_STIR - /*! \brief Tests SeparableMetzArrayFilter functionality \ingroup test @@ -43,53 +42,59 @@ class SeparableMetzArrayFilterTests : public RunTests { public: void run_tests() override; -private: - - +private: }; void 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(); @@ -98,14 +103,15 @@ SeparableMetzArrayFilterTests::run_tests() set_tolerance(old_tol); } } - } + } } END_NAMESPACE_STIR USING_NAMESPACE_STIR -int main() +int +main() { SeparableMetzArrayFilterTests tests; tests.run_tests(); diff --git a/src/test/test_VectorWithOffset.cxx b/src/test/test_VectorWithOffset.cxx index 3a1b96be8..3e1010a4d 100644 --- a/src/test/test_VectorWithOffset.cxx +++ b/src/test/test_VectorWithOffset.cxx @@ -21,10 +21,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" @@ -43,7 +43,6 @@ using std::size_t; START_NAMESPACE_STIR - /*! \brief Test class for VectorWithOffset \ingroup test @@ -60,57 +59,54 @@ 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"); } @@ -122,7 +118,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()); @@ -131,514 +127,432 @@ 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 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 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 - // 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 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 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"); - } +/**********************************************************************/ +// 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) { - 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()"); + 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 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& ) - { - } - } - } +// 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"); +} - // 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 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 -3 +// tests on at() with out-of-range +{ { VectorWithOffset test; +try { - 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"); + 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 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(); diff --git a/src/test/test_VoxelsOnCartesianGrid.cxx b/src/test/test_VoxelsOnCartesianGrid.cxx index 7229a3f96..86012f4d4 100644 --- a/src/test/test_VoxelsOnCartesianGrid.cxx +++ b/src/test/test_VoxelsOnCartesianGrid.cxx @@ -2,27 +2,27 @@ // /* 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 part of STIR. + SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license - + 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" @@ -53,215 +53,199 @@ class VoxelsOnCartesianGridTests : public RunTests void run_tests() override; }; - 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"); - } - 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), + { + 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), "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"); } } - } { @@ -270,28 +254,24 @@ 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(), @@ -336,31 +316,26 @@ VoxelsOnCartesianGridTests::run_tests() // Check inverse consistency check_if_equal(indices, - hfs_image.get_indices_closest_to_LPS_coordinates( - hfs_image.get_LPS_coordinates_for_indices(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)), + 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)), + 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)), + 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(); diff --git a/src/test/test_convert_array.cxx b/src/test/test_convert_array.cxx index f24a26d3f..e444402ee 100644 --- a/src/test/test_convert_array.cxx +++ b/src/test/test_convert_array.cxx @@ -10,8 +10,8 @@ See STIR/LICENSE.txt for details */ /*! - \file - \ingroup test + \file + \ingroup test \brief tests for the stir::convert_array functions \author Kris Thielemans @@ -39,102 +39,96 @@ class convert_array_Tests : public RunTests void run_tests() override; }; - void 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); } @@ -142,98 +136,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(); diff --git a/src/test/test_coordinates.cxx b/src/test/test_coordinates.cxx index 68f1fd293..116cf2b1d 100644 --- a/src/test/test_coordinates.cxx +++ b/src/test/test_coordinates.cxx @@ -11,9 +11,9 @@ */ /*! - \file + \file \ingroup test - + \brief A simple program to test the Coordinate classes \author Kris Thielemans @@ -34,7 +34,6 @@ using std::cerr; using std::endl; - START_NAMESPACE_STIR /*! @@ -47,55 +46,61 @@ class coordinateTests : public RunTests void run_tests() override; }; - void 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; @@ -109,46 +114,52 @@ 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 - { - float *p=std::find(b.begin(), b.end(), -3); + { + float* p = std::find(b.begin(), b.end(), -3); 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; - std::sort(b.begin(), b.end()); - check_if_zero(norm(b-b_sorted), "testing iterators via STL sort"); + b_sorted[1] = -3; + b_sorted[2] = -1; + b_sorted[3] = 5; + std::sort(b.begin(), b.end()); + 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"); @@ -159,47 +170,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!="); } } @@ -209,36 +232,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; @@ -246,17 +275,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 @@ -264,36 +292,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; @@ -301,24 +335,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; @@ -326,39 +359,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(); diff --git a/src/test/test_display.cxx b/src/test/test_display.cxx index 82e2b2039..6b2e51bfa 100644 --- a/src/test/test_display.cxx +++ b/src/test/test_display.cxx @@ -30,72 +30,71 @@ int 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++) + 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); + 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 6364803c4..4e6f8ebd6 100644 --- a/src/test/test_export_array.cxx +++ b/src/test/test_export_array.cxx @@ -42,56 +42,47 @@ START_NAMESPACE_STIR class ExportArrayTests : public RunTests { public: - void run_tests() override; + void run_tests() override; 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() +void +ExportArrayTests ::run_tests() { - test_static_data(); - test_dynamic_data(); + 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) +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) + 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 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); + 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) + 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); + 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 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) + 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."); + 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."); } } } @@ -105,201 +96,188 @@ 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() +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("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); + info(boost::format("Allocating and filling the %1% gate... ") % i_gate); - shared_ptr test_proj_data_gate_ptr( - new ProjDataInMemory(test_exam_info_sptr, - tmp_proj_data_info_sptr)); + 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_gate_ptr->get_min_segment_num(); - segment_num <= test_proj_data_gate_ptr->get_max_segment_num(); - ++segment_num) + 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); + SegmentByView segment_by_view_data = test_proj_data_gate_ptr->get_segment_by_view(segment_num); - // 1000 is an arbitary number to distiguish data in different gates. - segment_by_view_data.fill(static_cast(segment_num + (i_gate * 1000))); + // 1000 is an arbitary number to distiguish data in different gates. + segment_by_view_data.fill(static_cast(segment_num + (i_gate * 1000))); - if (!(test_proj_data_gate_ptr->set_segment(segment_by_view_data) == Succeeded::yes)) - warning("Error set_segment %d\n", segment_num); + if (!(test_proj_data_gate_ptr->set_segment(segment_by_view_data) == Succeeded::yes)) + warning("Error set_segment %d\n", segment_num); } - info("Populating the Dynamic ProjData... "); - test_dynamic_projData_sptr->set_proj_data_sptr(test_proj_data_gate_ptr, i_gate); + info("Populating the Dynamic ProjData... "); + test_dynamic_projData_sptr->set_proj_data_sptr(test_proj_data_gate_ptr, i_gate); } - 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()); + 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(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(); + 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(); - // Copy data to array. - info("Copying test dynamic projdata to array ..."); - copy_to(*test_dynamic_projData_sptr, test_array_iter); + // Copy data to array. + info("Copying test dynamic projdata to array ..."); + copy_to(*test_dynamic_projData_sptr, test_array_iter); - // Convert it to ProjData - info("Copying data from array to check dynamic projdata ..."); + // 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)); + shared_ptr check_dynamic_projData_sptr(new DynamicProjData(test_exam_info_sptr, num_of_gates)); - for (int i_gate = 0; i_gate < num_of_gates; i_gate++) + 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(boost::format("Allocating and filling the %1% gate... ") % (i_gate + 1)); - shared_ptr test_proj_data_gate_ptr( - new ProjDataInMemory(test_exam_info_sptr, - tmp_proj_data_info_sptr)); + shared_ptr test_proj_data_gate_ptr(new ProjDataInMemory(test_exam_info_sptr, tmp_proj_data_info_sptr)); - info("Populating the Dynamic ProjData... "); - check_dynamic_projData_sptr->set_proj_data_sptr(test_proj_data_gate_ptr, (i_gate+1)); + info("Populating the Dynamic ProjData... "); + check_dynamic_projData_sptr->set_proj_data_sptr(test_proj_data_gate_ptr, (i_gate + 1)); } - fill_from(*check_dynamic_projData_sptr, test_array.begin_all_const(), test_array.end_all_const()); + fill_from(*check_dynamic_projData_sptr, test_array.begin_all_const(), test_array.end_all_const()); - info ("Checking if data are the same..."); - for(int i_gate = 1; i_gate <= num_of_gates; i_gate++) + 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)); + 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) + 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 _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); + 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) + 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); + 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 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) + 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_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."); } } } } } - } -void ExportArrayTests :: run_static_test(ProjData& test_proj_data, - ProjData& check_proj_data, - const std::string& test_name) +void +ExportArrayTests ::run_static_test(ProjData& test_proj_data, ProjData& check_proj_data, const std::string& test_name) { - std::cerr << "Running " << test_name << '\n'; + std::cerr << "Running " << test_name << '\n'; - //. Fill ProjData with the number of the segment - info("Filling test ProjData with the segment number ... "); + //. 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) + 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(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)); + 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); + 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 + //- Get the total size of the ProjData - const unsigned int total_size = test_proj_data.size_all(); + const unsigned int total_size = test_proj_data.size_all(); - //- Allocate 1D array and get iterator + //- 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("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); + //- + 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; - } - } - } - } + //- 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); } //! @@ -307,64 +285,68 @@ 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() +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)); - + 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) +int +main(int argc, char** argv) { - ExportArrayTests tests; - tests.run_tests(); - return tests.main_return_value(); + 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 cb694bd3f..2b174f056 100644 --- a/src/test/test_filename_functions.cxx +++ b/src/test/test_filename_functions.cxx @@ -39,7 +39,8 @@ class FilenameTests : public RunTests void run_tests() override; }; -void FilenameTests::run_tests() +void +FilenameTests::run_tests() { char filename_with_directory[max_filename_length]; @@ -47,9 +48,9 @@ void FilenameTests::run_tests() #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"); @@ -57,13 +58,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"; @@ -72,39 +73,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"); @@ -118,7 +110,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"); @@ -127,193 +119,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); - - FilePath filename_with_directory("b\\c.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); - filename_with_directory.prepend_directory_name("a"); - check( filename_with_directory == "a\\b\\c.v"); + FilePath filename_with_directory("b\\c.v", false); - filename_with_directory = "b\\c.v"; - 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 = "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 == "\\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 == "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 == "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 == "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__) @@ -321,7 +290,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"); @@ -334,134 +303,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"); @@ -476,13 +433,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"); @@ -495,136 +452,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"); @@ -639,16 +583,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(); diff --git a/src/test/test_find_fwhm_in_image.cxx b/src/test/test_find_fwhm_in_image.cxx index 70afe437b..b5c118835 100644 --- a/src/test/test_find_fwhm_in_image.cxx +++ b/src/test/test_find_fwhm_in_image.cxx @@ -3,7 +3,7 @@ This file is part of STIR. SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details */ /*! @@ -15,17 +15,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" @@ -48,256 +48,229 @@ START_NAMESPACE_STIR class find_fwhm_in_imageTests : public RunTests { public: - find_fwhm_in_imageTests() - {} + find_fwhm_in_imageTests() {} void run_tests() override; + 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); - VoxelsOnCartesianGrid image(range,origin, grid_spacing); + IndexRange<3> range(CartesianCoordinate3D(0, -65, -64), CartesianCoordinate3D(24, 64, 65)); + + 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(); - - 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"); + 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"); } { 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(); - - 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"); + 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"); } { // 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(); - - 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"); + 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"); ++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_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"); //++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; + } } { @@ -306,56 +279,51 @@ 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) + 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); + 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) +int +main(int argc, char** argv) { if (argc != 1) - { - cerr << "Usage : " << argv[0] << " \n"; - return EXIT_FAILURE; - } + { + cerr << "Usage : " << argv[0] << " \n"; + return EXIT_FAILURE; + } find_fwhm_in_imageTests tests; tests.run_tests(); diff --git a/src/test/test_interpolate.cxx b/src/test/test_interpolate.cxx index 9d5c96988..6565f2cf6 100644 --- a/src/test/test_interpolate.cxx +++ b/src/test/test_interpolate.cxx @@ -32,122 +32,114 @@ using std::endl; USING_NAMESPACE_STIR -int -main(int argc, char *argv[]) +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 + if (ask("1D", false)) { - 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; - - 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; - } - } while (ask("More ?", true)); - } - - - 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; - + 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); - - 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; - } - + { + 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; + + 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; + } } while (ask("More ?", true)); - } - - + } + + 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; + { + 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)); + } + return EXIT_SUCCESS; } diff --git a/src/test/test_interpolate_projdata.cxx b/src/test/test_interpolate_projdata.cxx index 9d7a71808..46925eba9 100644 --- a/src/test/test_interpolate_projdata.cxx +++ b/src/test/test_interpolate_projdata.cxx @@ -59,10 +59,12 @@ class InterpolationTests : public RunTests void check_symmetry(const SegmentBySinogram& segment); void compare_segment(const SegmentBySinogram& segment1, const SegmentBySinogram& segment2, float maxDiff); - void compare_segment_shape(const SegmentBySinogram& shape_segment, const SegmentBySinogram& test_segment, int erosion); + void + compare_segment_shape(const SegmentBySinogram& shape_segment, const SegmentBySinogram& test_segment, int erosion); }; -void InterpolationTests::check_symmetry(const SegmentBySinogram& segment) +void +InterpolationTests::check_symmetry(const SegmentBySinogram& segment) { // compare lower half of slices with upper half - image should be axially symmetric auto maxAbsDifference = 0.0; @@ -71,135 +73,150 @@ void InterpolationTests::check_symmetry(const SegmentBySinogram& segment) auto increasing_index = segment.get_min_axial_pos_num(); auto decreasing_index = segment.get_max_axial_pos_num(); while (increasing_index < decreasing_index) - { - for (auto view = segment.get_min_view_num(); view <= segment.get_max_view_num(); view++) { - for (auto tang = segment.get_min_tangential_pos_num(); tang <= segment.get_max_tangential_pos_num(); tang++) - { - auto voxel1 = abs(segment[increasing_index][view][tang]); - auto voxel2 = abs(segment[decreasing_index][view][tang]); - if (abs(voxel1 - voxel2) > maxAbsDifference) - maxAbsDifference = abs(voxel1 - voxel2); - if (voxel1 > 0) - { - sumAbsValues += voxel1; - summedEntries++; - } - if (voxel2 > 0) + for (auto view = segment.get_min_view_num(); view <= segment.get_max_view_num(); view++) { - sumAbsValues += voxel2; - summedEntries++; + for (auto tang = segment.get_min_tangential_pos_num(); tang <= segment.get_max_tangential_pos_num(); tang++) + { + auto voxel1 = abs(segment[increasing_index][view][tang]); + auto voxel2 = abs(segment[decreasing_index][view][tang]); + if (abs(voxel1 - voxel2) > maxAbsDifference) + maxAbsDifference = abs(voxel1 - voxel2); + if (voxel1 > 0) + { + sumAbsValues += voxel1; + summedEntries++; + } + if (voxel2 > 0) + { + sumAbsValues += voxel2; + summedEntries++; + } + } } - } + increasing_index++; + decreasing_index--; } - increasing_index++; - decreasing_index--; - } // if the largest symmetry error is larger than 0.01% of the mean absolute value, then there is something wrong - check_if_less(maxAbsDifference, 0.0001 * sumAbsValues / summedEntries, "symmetry errors larger than 0.01\% of absolute values in axial direction"); + check_if_less(maxAbsDifference, + 0.0001 * sumAbsValues / summedEntries, + "symmetry errors larger than 0.01\% of absolute values in axial direction"); // compare the first half of the views with the second half - even for the BlocksOnCylindrical scanner they should be identical maxAbsDifference = 0.0; sumAbsValues = 0.0; summedEntries = 0.0; - for (auto view = 0; view < segment.get_num_views()/2; view++) - { - for (auto axial = segment.get_min_axial_pos_num(); axial <= segment.get_max_axial_pos_num(); axial++) + for (auto view = 0; view < segment.get_num_views() / 2; view++) { - for (auto tang = segment.get_min_tangential_pos_num(); tang <= segment.get_max_tangential_pos_num(); tang++) - { - auto voxel1 = segment[axial][view][tang]; - auto voxel2 = segment[axial][view + segment.get_num_views()/2][tang]; - if (abs(voxel1 - voxel2) > maxAbsDifference) - maxAbsDifference = abs(voxel1 - voxel2); - if (voxel1 > 0) - { - sumAbsValues += voxel1; - summedEntries++; - } - if (voxel2 > 0) + for (auto axial = segment.get_min_axial_pos_num(); axial <= segment.get_max_axial_pos_num(); axial++) { - sumAbsValues += voxel2; - summedEntries++; + for (auto tang = segment.get_min_tangential_pos_num(); tang <= segment.get_max_tangential_pos_num(); tang++) + { + auto voxel1 = segment[axial][view][tang]; + auto voxel2 = segment[axial][view + segment.get_num_views() / 2][tang]; + if (abs(voxel1 - voxel2) > maxAbsDifference) + maxAbsDifference = abs(voxel1 - voxel2); + if (voxel1 > 0) + { + sumAbsValues += voxel1; + summedEntries++; + } + if (voxel2 > 0) + { + sumAbsValues += voxel2; + summedEntries++; + } + } } - } } - } // if the largest symmetry error is larger than 0.1% of the mean absolute value, then there is something wrong // TODO: this tolerance can be tightened to 0.01% if https://github.com/UCL/STIR/issues/1176 is resolved - check_if_less(maxAbsDifference, 0.001 * sumAbsValues / summedEntries, "symmetry errors larger than 0.1\% of absolute values across views"); + check_if_less(maxAbsDifference, + 0.001 * sumAbsValues / summedEntries, + "symmetry errors larger than 0.1\% of absolute values across views"); } -void InterpolationTests::compare_segment(const SegmentBySinogram& segment1, const SegmentBySinogram& segment2, float maxDiff) +void +InterpolationTests::compare_segment(const SegmentBySinogram& segment1, + const SegmentBySinogram& segment2, + float maxDiff) { // compute difference and compare against empirically found value from visually validated sinograms auto sumAbsDifference = 0.0; for (auto axial = segment1.get_min_axial_pos_num(); axial <= segment1.get_max_axial_pos_num(); axial++) - { - for (auto view = segment1.get_min_view_num(); view <= segment1.get_max_view_num(); view++) { - for (auto tang = segment1.get_min_tangential_pos_num(); tang <= segment1.get_max_tangential_pos_num(); tang++) - { - sumAbsDifference += abs(segment1[axial][view][tang] - segment2[axial][view][tang]); - } + for (auto view = segment1.get_min_view_num(); view <= segment1.get_max_view_num(); view++) + { + for (auto tang = segment1.get_min_tangential_pos_num(); tang <= segment1.get_max_tangential_pos_num(); tang++) + { + sumAbsDifference += abs(segment1[axial][view][tang] - segment2[axial][view][tang]); + } + } } - } // confirm that the difference is smaller than an empirically found value check_if_less(sumAbsDifference, maxDiff, "difference between segments is larger than expected"); } -void InterpolationTests::compare_segment_shape(const SegmentBySinogram& shape_segment, const SegmentBySinogram& test_segment, int erosion) +void +InterpolationTests::compare_segment_shape(const SegmentBySinogram& shape_segment, + const SegmentBySinogram& test_segment, + int erosion) { auto maxTestValue = test_segment.find_max(); // compute difference and compare against empirically found value from visually validated sinograms auto sumVoxelsOutsideMask = 0U; for (auto axial = test_segment.get_min_axial_pos_num(); axial <= test_segment.get_max_axial_pos_num(); axial++) - { - for (auto view = test_segment.get_min_view_num(); view <= test_segment.get_max_view_num(); view++) { - for (auto tang = test_segment.get_min_tangential_pos_num(); tang <= test_segment.get_max_tangential_pos_num(); tang++) - { - if (test_segment[axial][view][tang] < 0.1 * maxTestValue) - continue; - - // now go through the erosion neighbourhood of the voxel to see if it is near a non-zero voxel - bool isNearNonZero = false; - for (auto axialShape = std::max(axial - erosion, test_segment.get_min_axial_pos_num()); - axialShape <= std::min(axial + erosion, test_segment.get_max_axial_pos_num()); axialShape++) + for (auto view = test_segment.get_min_view_num(); view <= test_segment.get_max_view_num(); view++) { - for (auto viewShape = std::max(view - erosion, test_segment.get_min_view_num()); - viewShape <= std::min(view + erosion, test_segment.get_max_view_num()); viewShape++) - { - for (auto tangShape = std::max(tang - erosion, test_segment.get_min_tangential_pos_num()); - tangShape <= std::min(tang + erosion, test_segment.get_max_tangential_pos_num()); tangShape++) + for (auto tang = test_segment.get_min_tangential_pos_num(); tang <= test_segment.get_max_tangential_pos_num(); tang++) { - if (shape_segment[axialShape][viewShape][tangShape] > 0) - isNearNonZero = true; + if (test_segment[axial][view][tang] < 0.1 * maxTestValue) + continue; + + // now go through the erosion neighbourhood of the voxel to see if it is near a non-zero voxel + bool isNearNonZero = false; + for (auto axialShape = std::max(axial - erosion, test_segment.get_min_axial_pos_num()); + axialShape <= std::min(axial + erosion, test_segment.get_max_axial_pos_num()); + axialShape++) + { + for (auto viewShape = std::max(view - erosion, test_segment.get_min_view_num()); + viewShape <= std::min(view + erosion, test_segment.get_max_view_num()); + viewShape++) + { + for (auto tangShape = std::max(tang - erosion, test_segment.get_min_tangential_pos_num()); + tangShape <= std::min(tang + erosion, test_segment.get_max_tangential_pos_num()); + tangShape++) + { + if (shape_segment[axialShape][viewShape][tangShape] > 0) + isNearNonZero = true; + } + } + } + if (isNearNonZero == false) + sumVoxelsOutsideMask++; } - } } - if (isNearNonZero == false) - sumVoxelsOutsideMask++; - } } - } // confirm that the difference is smaller than an empirically found value check_if_equal(sumVoxelsOutsideMask, 0U, "there were non-zero voxels outside the masked area"); } -static void make_symmetric_object(VoxelsOnCartesianGrid& emission_map) +static void +make_symmetric_object(VoxelsOnCartesianGrid& emission_map) { const float z_voxel_size = emission_map.get_grid_spacing()[1]; - const float z_centre = (emission_map.get_min_z() + emission_map.get_max_z())/2.F * z_voxel_size; + const float z_centre = (emission_map.get_min_z() + emission_map.get_max_z()) / 2.F * z_voxel_size; // choose a length that isn't exactly equal to a number of planes (or half), as that // is sensitive to rounding error - auto cylinder = EllipsoidalCylinder(z_voxel_size*4.5, 80, 80, CartesianCoordinate3D(z_centre, 0, 0)); + auto cylinder = EllipsoidalCylinder(z_voxel_size * 4.5, 80, 80, CartesianCoordinate3D(z_centre, 0, 0)); cylinder.construct_volume(emission_map, CartesianCoordinate3D(1, 1, 1)); } -void InterpolationTests::scatter_interpolation_test_blocks() +void +InterpolationTests::scatter_interpolation_test_blocks() { info("Performing symmetric interpolation test for BlocksOnCylindrical scanner"); auto time_frame_def = TimeFrameDefinitions(); @@ -211,13 +228,67 @@ void InterpolationTests::scatter_interpolation_test_blocks() exam_info.set_time_frame_definitions(time_frame_def); // define the original scanner and a downsampled one, as it would be used for scatter simulation - auto scanner = Scanner(Scanner::User_defined_scanner, "Some_symmetric_scanner", 192, 30, 150, 150, 127, 4.3, 4.0, 2.0, -0.38956 /* 0.0 */, - 5, 4, 6, 6, 1, 1, 1, 0.17, 511, -1, 01.F, -1.F, "BlocksOnCylindrical", 4.0, 4.0, 24.0, 24.0); - auto downsampled_scanner = Scanner(Scanner::User_defined_scanner, "Some_symmetric_scanner", 192, 6, 150, 150, 127, 4.3, 20.0, 2.0, -0.38956 /* 0.0 */, - 1, 4, 6, 6, 1, 1, 1, 0.17, 511, -1, 01.F, -1.F, "BlocksOnCylindrical", 20.0, 4.0, 120.0, 24.0); - - auto proj_data_info = shared_ptr(std::move(ProjDataInfo::construct_proj_data_info(std::make_shared(scanner), 1, 29, 96, 150, false))); - auto downsampled_proj_data_info = shared_ptr(std::move(ProjDataInfo::construct_proj_data_info(std::make_shared(downsampled_scanner), 1, 0, 96, 150, false))); + auto scanner = Scanner(Scanner::User_defined_scanner, + "Some_symmetric_scanner", + 192, + 30, + 150, + 150, + 127, + 4.3, + 4.0, + 2.0, + -0.38956 /* 0.0 */, + 5, + 4, + 6, + 6, + 1, + 1, + 1, + 0.17, + 511, + -1, + 01.F, + -1.F, + "BlocksOnCylindrical", + 4.0, + 4.0, + 24.0, + 24.0); + auto downsampled_scanner = Scanner(Scanner::User_defined_scanner, + "Some_symmetric_scanner", + 192, + 6, + 150, + 150, + 127, + 4.3, + 20.0, + 2.0, + -0.38956 /* 0.0 */, + 1, + 4, + 6, + 6, + 1, + 1, + 1, + 0.17, + 511, + -1, + 01.F, + -1.F, + "BlocksOnCylindrical", + 20.0, + 4.0, + 120.0, + 24.0); + + auto proj_data_info = shared_ptr( + std::move(ProjDataInfo::construct_proj_data_info(std::make_shared(scanner), 1, 29, 96, 150, false))); + auto downsampled_proj_data_info = shared_ptr( + std::move(ProjDataInfo::construct_proj_data_info(std::make_shared(downsampled_scanner), 1, 0, 96, 150, false))); auto proj_data = ProjDataInMemory(std::make_shared(exam_info), proj_data_info); auto downsampled_proj_data = ProjDataInMemory(std::make_shared(exam_info), downsampled_proj_data_info); @@ -251,7 +322,8 @@ void InterpolationTests::scatter_interpolation_test_blocks() check_symmetry(interpolated_proj_data.get_segment_by_sinogram(0)); } -void InterpolationTests::scatter_interpolation_test_cyl() +void +InterpolationTests::scatter_interpolation_test_cyl() { info("Performing symmetric interpolation test for Cylindrical scanner"); auto time_frame_def = TimeFrameDefinitions(); @@ -263,13 +335,67 @@ void InterpolationTests::scatter_interpolation_test_cyl() exam_info.set_time_frame_definitions(time_frame_def); // define the original scanner and a downsampled one, as it would be used for scatter simulation - auto scanner = Scanner(Scanner::User_defined_scanner, "Some_symmetric_scanner", 192, 30, 150, 150, 127, 4.3, 4.0, 2.0, -0.38956 /* 0.0 */, - 5, 4, 6, 6, 1, 1, 1, 0.17, 511, -1, 01.F, -1.F, "Cylindrical", 4.0, 4.0, 24.0, 24.0); - auto downsampled_scanner = Scanner(Scanner::User_defined_scanner, "Some_symmetric_scanner", 64, 6, int(150 * 64 / 192), int(150 * 64 / 192), 127, 4.3, - 20.0, 133 * 3.14 / 64, -0.38956 /* 0.0 */, 1, 1, 6, 64, 1, 1, 1, 0.17, 511, -1, 01.F, -1.F, "Cylindrical", 20.0, 12.0, 120.0, 72.0); - - auto proj_data_info = shared_ptr(std::move(ProjDataInfo::construct_proj_data_info(std::make_shared(scanner), 1, 29, 96, 150, false))); - auto downsampled_proj_data_info = shared_ptr(std::move(ProjDataInfo::construct_proj_data_info(std::make_shared(downsampled_scanner), 1, 0, 32, int(150 * 64 / 192), false))); + auto scanner = Scanner(Scanner::User_defined_scanner, + "Some_symmetric_scanner", + 192, + 30, + 150, + 150, + 127, + 4.3, + 4.0, + 2.0, + -0.38956 /* 0.0 */, + 5, + 4, + 6, + 6, + 1, + 1, + 1, + 0.17, + 511, + -1, + 01.F, + -1.F, + "Cylindrical", + 4.0, + 4.0, + 24.0, + 24.0); + auto downsampled_scanner = Scanner(Scanner::User_defined_scanner, + "Some_symmetric_scanner", + 64, + 6, + int(150 * 64 / 192), + int(150 * 64 / 192), + 127, + 4.3, + 20.0, + 133 * 3.14 / 64, + -0.38956 /* 0.0 */, + 1, + 1, + 6, + 64, + 1, + 1, + 1, + 0.17, + 511, + -1, + 01.F, + -1.F, + "Cylindrical", + 20.0, + 12.0, + 120.0, + 72.0); + + auto proj_data_info = shared_ptr( + std::move(ProjDataInfo::construct_proj_data_info(std::make_shared(scanner), 1, 29, 96, 150, false))); + auto downsampled_proj_data_info = shared_ptr(std::move(ProjDataInfo::construct_proj_data_info( + std::make_shared(downsampled_scanner), 1, 0, 32, int(150 * 64 / 192), false))); auto proj_data = ProjDataInMemory(std::make_shared(exam_info), proj_data_info); auto downsampled_proj_data = ProjDataInMemory(std::make_shared(exam_info), downsampled_proj_data_info); @@ -303,7 +429,8 @@ void InterpolationTests::scatter_interpolation_test_cyl() check_symmetry(interpolated_proj_data.get_segment_by_sinogram(0)); } -void InterpolationTests::scatter_interpolation_test_blocks_asymmetric() +void +InterpolationTests::scatter_interpolation_test_blocks_asymmetric() { info("Performing asymmetric interpolation test for BlocksOnCylindrical scanner"); auto time_frame_def = TimeFrameDefinitions(); @@ -315,13 +442,67 @@ void InterpolationTests::scatter_interpolation_test_blocks_asymmetric() exam_info.set_time_frame_definitions(time_frame_def); // define the original scanner and a downsampled one, as it would be used for scatter simulation - auto scanner = Scanner(Scanner::User_defined_scanner, "Some_symmetric_scanner", 96, 30, 150, 150, 127, 4.3, 4.0, 8.0, -0.38956 /* 0.0 */, - 5, 1, 6, 6, 1, 1, 1, 0.17, 511, -1, 01.F, -1.F, "BlocksOnCylindrical", 4.0, 16.0, 24.0, 96.0); - auto downsampled_scanner = Scanner(Scanner::User_defined_scanner, "Some_symmetric_scanner", 96, 12, 150, 150, 127, 4.3, 10.0, 8.0, -0.38956 /* 0.0 */, - 1, 1, 12, 6, 1, 1, 1, 0.17, 511, -1, 01.F, -1.F, "BlocksOnCylindrical", 10.0, 16.0, 60.0, 96.0); - - auto proj_data_info = shared_ptr(std::move(ProjDataInfo::construct_proj_data_info(std::make_shared(scanner), 1, 29, 48, 75, false))); - auto downsampled_proj_data_info = shared_ptr(std::move(ProjDataInfo::construct_proj_data_info(std::make_shared(downsampled_scanner), 1, 0, 48, 75, false))); + auto scanner = Scanner(Scanner::User_defined_scanner, + "Some_symmetric_scanner", + 96, + 30, + 150, + 150, + 127, + 4.3, + 4.0, + 8.0, + -0.38956 /* 0.0 */, + 5, + 1, + 6, + 6, + 1, + 1, + 1, + 0.17, + 511, + -1, + 01.F, + -1.F, + "BlocksOnCylindrical", + 4.0, + 16.0, + 24.0, + 96.0); + auto downsampled_scanner = Scanner(Scanner::User_defined_scanner, + "Some_symmetric_scanner", + 96, + 12, + 150, + 150, + 127, + 4.3, + 10.0, + 8.0, + -0.38956 /* 0.0 */, + 1, + 1, + 12, + 6, + 1, + 1, + 1, + 0.17, + 511, + -1, + 01.F, + -1.F, + "BlocksOnCylindrical", + 10.0, + 16.0, + 60.0, + 96.0); + + auto proj_data_info = shared_ptr( + std::move(ProjDataInfo::construct_proj_data_info(std::make_shared(scanner), 1, 29, 48, 75, false))); + auto downsampled_proj_data_info = shared_ptr( + std::move(ProjDataInfo::construct_proj_data_info(std::make_shared(downsampled_scanner), 1, 0, 48, 75, false))); auto proj_data = ProjDataInMemory(std::make_shared(exam_info), proj_data_info); auto downsampled_proj_data = ProjDataInMemory(std::make_shared(exam_info), downsampled_proj_data_info); @@ -371,7 +552,8 @@ void InterpolationTests::scatter_interpolation_test_blocks_asymmetric() compare_segment_shape(full_size_model_sino.get_segment_by_sinogram(0), interpolated_proj_data.get_segment_by_sinogram(0), 2); } -void InterpolationTests::scatter_interpolation_test_cyl_asymmetric() +void +InterpolationTests::scatter_interpolation_test_cyl_asymmetric() { info("Performing asymmetric interpolation test for Cylindrical scanner"); auto time_frame_def = TimeFrameDefinitions(); @@ -383,13 +565,67 @@ void InterpolationTests::scatter_interpolation_test_cyl_asymmetric() exam_info.set_time_frame_definitions(time_frame_def); // define the original scanner and a downsampled one, as it would be used for scatter simulation - auto scanner = Scanner(Scanner::User_defined_scanner, "Some_symmetric_scanner", 96, 30, 150, 150, 127, 4.3, 4.0, 8.0, -0.38956 /* 0.0 */, - 5, 1, 6, 6, 1, 1, 1, 0.17, 511, -1, 01.F, -1.F, "Cylindrical", 4.0, 16.0, 24.0, 96.0); - auto downsampled_scanner = Scanner(Scanner::User_defined_scanner, "Some_symmetric_scanner", 64, 12, 150, 150, 127, 4.3, - 10.0, 133 * 3.14 / 64, -0.38956 /* 0.0 */, 1, 1, 12, 64, 1, 1, 1, 0.17, 511, -1, 01.F, -1.F, "Cylindrical", 10.0, 12.0, 60.0, 72.0); - - auto proj_data_info = shared_ptr(std::move(ProjDataInfo::construct_proj_data_info(std::make_shared(scanner), 1, 29, 48, int(150 * 96 / 192), false))); - auto downsampled_proj_data_info = shared_ptr(std::move(ProjDataInfo::construct_proj_data_info(std::make_shared(downsampled_scanner), 1, 0, 32, int(150 * 64 / 192), false))); + auto scanner = Scanner(Scanner::User_defined_scanner, + "Some_symmetric_scanner", + 96, + 30, + 150, + 150, + 127, + 4.3, + 4.0, + 8.0, + -0.38956 /* 0.0 */, + 5, + 1, + 6, + 6, + 1, + 1, + 1, + 0.17, + 511, + -1, + 01.F, + -1.F, + "Cylindrical", + 4.0, + 16.0, + 24.0, + 96.0); + auto downsampled_scanner = Scanner(Scanner::User_defined_scanner, + "Some_symmetric_scanner", + 64, + 12, + 150, + 150, + 127, + 4.3, + 10.0, + 133 * 3.14 / 64, + -0.38956 /* 0.0 */, + 1, + 1, + 12, + 64, + 1, + 1, + 1, + 0.17, + 511, + -1, + 01.F, + -1.F, + "Cylindrical", + 10.0, + 12.0, + 60.0, + 72.0); + + auto proj_data_info = shared_ptr(std::move( + ProjDataInfo::construct_proj_data_info(std::make_shared(scanner), 1, 29, 48, int(150 * 96 / 192), false))); + auto downsampled_proj_data_info = shared_ptr(std::move(ProjDataInfo::construct_proj_data_info( + std::make_shared(downsampled_scanner), 1, 0, 32, int(150 * 64 / 192), false))); auto proj_data = ProjDataInMemory(std::make_shared(exam_info), proj_data_info); auto downsampled_proj_data = ProjDataInMemory(std::make_shared(exam_info), downsampled_proj_data_info); diff --git a/src/test/test_linear_regression.cxx b/src/test/test_linear_regression.cxx index 9047d2fe7..f8c712759 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. @@ -26,7 +26,7 @@ See STIR/LICENSE.txt for details */ - + #include "stir/linear_regression.h" #include "stir/RunTests.h" #include "stir/ArrayFunction.h" @@ -54,8 +54,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
      @@ -63,7 +63,7 @@ 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
      @@ -71,165 +71,157 @@ START_NAMESPACE_STIR class linear_regressionTests : public RunTests { public: - linear_regressionTests(istream& in) - : in(in) + linear_regressionTests(istream& in) + : in(in) {} void run_tests() override; + 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) - { - // first get rid of EOL - in.getline(text,200); - // now get real text - in.get(text,200); - test_case ++; - - int size = 0; - in >> size; - 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[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; - 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"); - - // KT 24/01/2001 changed tolerance for this comparisons - /* 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 - 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) - */ - double error_on_chi_square = 0; { - for (int i=0; i> size; + 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 < size; i++) + in >> coordinates[i]; + for (int i = 0; i < size; i++) + in >> measured_data[i]; + for (int i = 0; i < size; i++) + in >> 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; + 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"); + + // KT 24/01/2001 changed tolerance for this comparisons + /* 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 + 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) */ - check_if_equal(expected_covariance_of_constant_with_scale, - covariance_of_constant_with_scale, - "for parameter covariance_of_constant_with_scale should be equal"); - set_tolerance(old_tolerance); + double error_on_chi_square = 0; + { + for (int i = 0; i < size; ++i) + error_on_chi_square += fabs(weights[i] * measured_data[i]); + error_on_chi_square *= 10.E-5; + } + { + 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"); + + // first check if chi_square is really 0 (upto rounding errors) + if (fabs(expected_chi_square) < error_on_chi_square) + set_tolerance(old_tolerance); + + // next variances are proportional to chi_square + if (expected_chi_square != 0) + set_tolerance(fabs(expected_variance_of_constant / expected_chi_square * error_on_chi_square)); + check_if_equal( + expected_variance_of_constant, variance_of_constant, "for parameter variance_of_constant, should be equal"); + if (expected_chi_square != 0) + set_tolerance(fabs(expected_variance_of_scale / expected_chi_square * error_on_chi_square)); + check_if_equal(expected_variance_of_scale, variance_of_scale, "for parameter variance_of_scale, should be equal"); + if (expected_chi_square != 0) + set_tolerance(fabs(expected_covariance_of_constant_with_scale / expected_chi_square * error_on_chi_square)); + /* + std::cerr << "chi_square " << chi_square + << "\nexpected_chi_square " << expected_chi_square + << "\error on chi_square " << error_on_chi_square + << "\nRelative error on chi_square " << 1/expected_chi_square*error_on_chi_square + << "\n cov_const_scale_tolerance " << get_tolerance() + < 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(); + 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; + 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"); + // 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"); + // 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"); + 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 92d2ca18d..6ef621baf 100644 --- a/src/test/test_proj_data.cxx +++ b/src/test/test_proj_data.cxx @@ -38,73 +38,73 @@ START_NAMESPACE_STIR - /*! \ingroup test \brief Test class for ProjData and ProjDataInMemory */ -class ProjDataTests: public RunTests +class ProjDataTests : public RunTests { public: void run_tests() override; + 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 to ProjDataInMemory\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 fill(ProjDataInMemory)\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()); // fill with values 0, 1, 2, ... to have something non-trivial @@ -113,71 +113,78 @@ run_tests_on_proj_data(ProjData& proj_data) ProjDataInMemory proj_data3(proj_data2); // check if equal by subtracting proj_data3.sapyb(1.F, proj_data2, -1.F); - check(norm(proj_data3.begin(), proj_data3.end()) <= 0.0001F*norm(proj_data2.begin(), proj_data2.end()), - "fill(ProjDataInMemory&"); + check(norm(proj_data3.begin(), proj_data3.end()) <= 0.0001F * norm(proj_data2.begin(), proj_data2.end()), + "fill(ProjDataInMemory&"); } - timer.stop(); std::cerr<< "-- CPU Time " << timer.value() << '\n'; + timer.stop(); + std::cerr << "-- CPU Time " << timer.value() << '\n'; std::cerr << "\ntest fill(ProjDataInterfile)\n"; - timer.reset(); timer.start(); + timer.reset(); + timer.start(); { - ProjDataInterfile proj_data2(proj_data.get_exam_info_sptr(), proj_data.get_proj_data_info_sptr(), - "test_proj_data_fill.hs", std::ios::in|std::ios::out|std::ios::trunc); + ProjDataInterfile proj_data2(proj_data.get_exam_info_sptr(), + proj_data.get_proj_data_info_sptr(), + "test_proj_data_fill.hs", + std::ios::in | std::ios::out | std::ios::trunc); proj_data2.fill(value); - for (int seg=proj_data.get_min_segment_num(); seg<=proj_data.get_max_segment_num(); ++seg) + for (int seg = proj_data.get_min_segment_num(); seg <= proj_data.get_max_segment_num(); ++seg) { - auto viewgram = proj_data.get_empty_viewgram(1,seg, false, proj_data.get_max_tof_pos_num()); - viewgram.fill(value*seg); - check(proj_data2.set_viewgram(viewgram) == Succeeded::yes, - "test set_viewgram succeeded"); - auto sinogram = proj_data.get_empty_sinogram(1,seg, false, proj_data.get_min_tof_pos_num()); - sinogram.fill(value*3.12*seg); - check(proj_data2.set_sinogram(sinogram) == Succeeded::yes, - "test set_sinogram succeeded"); + auto viewgram = proj_data.get_empty_viewgram(1, seg, false, proj_data.get_max_tof_pos_num()); + viewgram.fill(value * seg); + check(proj_data2.set_viewgram(viewgram) == Succeeded::yes, "test set_viewgram succeeded"); + auto sinogram = proj_data.get_empty_sinogram(1, seg, false, proj_data.get_min_tof_pos_num()); + sinogram.fill(value * 3.12 * seg); + check(proj_data2.set_sinogram(sinogram) == Succeeded::yes, "test set_sinogram succeeded"); } proj_data.fill(proj_data2); // check if equal by subtracting ProjDataInMemory proj_data3(proj_data); const auto proj_data_norm = norm(proj_data3.begin(), proj_data3.end()); proj_data3.sapyb(1.F, proj_data2, -1.F); - check(norm(proj_data3.begin(), proj_data3.end()) <= 0.0001F*proj_data_norm, - "fill(ProjDataInterfile&)"); + check(norm(proj_data3.begin(), proj_data3.end()) <= 0.0001F * proj_data_norm, "fill(ProjDataInterfile&)"); if (!this->is_everything_ok()) exit(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\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 consistency of copy_to and fill_from\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()); // fill with values 0, 1, 2, ... to have something non-trivial @@ -187,34 +194,45 @@ run_tests_on_proj_data(ProjData& proj_data) proj_data.copy_to(proj_data3.begin()); // check if equal by subtracting proj_data3.sapyb(1.F, proj_data2, -1.F); - check(norm(proj_data3.begin(), proj_data3.end()) <= 0.0001F*norm(proj_data2.begin(), proj_data2.end()), + check(norm(proj_data3.begin(), proj_data3.end()) <= 0.0001F * norm(proj_data2.begin(), proj_data2.end()), "copy_to/fill_from consistency"); } - timer.stop(); std::cerr<< "-- CPU Time " << timer.value() << '\n'; + timer.stop(); + std::cerr << "-- CPU Time " << timer.value() << '\n'; std::cerr << "\ntest copy_to order\n"; - timer.reset(); timer.start(); + timer.reset(); + timer.start(); { - Array<4,float> test_array(IndexRange4D(proj_data.get_min_tof_pos_num(), proj_data.get_max_tof_pos_num(), - 0, proj_data.get_num_non_tof_sinograms()-1, - proj_data.get_min_view_num(), proj_data.get_max_view_num(), - proj_data.get_min_tangential_pos_num(), proj_data.get_max_tangential_pos_num())); + Array<4, float> test_array(IndexRange4D(proj_data.get_min_tof_pos_num(), + proj_data.get_max_tof_pos_num(), + 0, + proj_data.get_num_non_tof_sinograms() - 1, + proj_data.get_min_view_num(), + proj_data.get_max_view_num(), + proj_data.get_min_tangential_pos_num(), + proj_data.get_max_tangential_pos_num())); // copy to the array copy_to(proj_data, test_array.begin_all()); - for (int k=proj_data.get_min_tof_pos_num(); k<=proj_data.get_max_tof_pos_num(); ++k) + for (int k = proj_data.get_min_tof_pos_num(); k <= proj_data.get_max_tof_pos_num(); ++k) { int total_ax_pos_num = 0; for (int segment_num : proj_data.standard_segment_sequence(*proj_data.get_proj_data_info_sptr())) { - 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, ++total_ax_pos_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, ++total_ax_pos_num) { - if (!check_if_equal(proj_data.get_sinogram(ax_pos_num, segment_num, false, k), test_array[k][total_ax_pos_num], "test copy_to order")) + if (!check_if_equal(proj_data.get_sinogram(ax_pos_num, segment_num, false, k), + test_array[k][total_ax_pos_num], + "test copy_to order")) break; // get out, at least of this loop } } } } - timer.stop(); std::cerr<< "-- CPU Time " << timer.value() << '\n'; + timer.stop(); + std::cerr << "-- CPU Time " << timer.value() << '\n'; // find original span and max ring diff int span, max_ring_diff; @@ -223,45 +241,48 @@ run_tests_on_proj_data(ProjData& proj_data) const auto& pdi = dynamic_cast(*proj_data.get_proj_data_info_sptr()); max_ring_diff = pdi.get_max_ring_difference(pdi.get_max_segment_num()); span = max_ring_diff - pdi.get_min_ring_difference(pdi.get_max_segment_num()) + 1; - arc_corrected = !is_null_ptr(dynamic_cast(proj_data.get_proj_data_info_sptr().get())); + arc_corrected = !is_null_ptr(dynamic_cast(proj_data.get_proj_data_info_sptr().get())); } std::cerr << "\ntest fill with larger input\n"; - timer.reset(); timer.start(); - { - shared_ptr proj_data_info_sptr2 - (ProjDataInfo::construct_proj_data_info(proj_data.get_proj_data_info_sptr()->get_scanner_sptr(), - span, std::max(max_ring_diff-span , 0), - proj_data.get_num_views(), proj_data.get_num_tangential_poss(), - arc_corrected, - proj_data.get_proj_data_info_sptr()->get_tof_mash_factor()) - ); - - + timer.reset(); + timer.start(); + { + shared_ptr proj_data_info_sptr2( + ProjDataInfo::construct_proj_data_info(proj_data.get_proj_data_info_sptr()->get_scanner_sptr(), + span, + std::max(max_ring_diff - span, 0), + proj_data.get_num_views(), + proj_data.get_num_tangential_poss(), + arc_corrected, + proj_data.get_proj_data_info_sptr()->get_tof_mash_factor())); + // 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::construct_proj_data_info(proj_data.get_proj_data_info_sptr()->get_scanner_sptr(), - span, max_ring_diff+2, - proj_data.get_num_views(), proj_data.get_num_tangential_poss(), - arc_corrected, - proj_data.get_proj_data_info_sptr()->get_tof_mash_factor()) - ); - - + timer.reset(); + timer.start(); + { + shared_ptr proj_data_info_sptr2( + ProjDataInfo::construct_proj_data_info(proj_data.get_proj_data_info_sptr()->get_scanner_sptr(), + span, + max_ring_diff + 2, + proj_data.get_num_views(), + proj_data.get_num_tangential_poss(), + arc_corrected, + proj_data.get_proj_data_info_sptr()->get_tof_mash_factor())); + // 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 @@ -276,7 +297,8 @@ run_tests_on_proj_data(ProjData& proj_data) // ok } } - timer.stop(); std::cerr<< "-- CPU Time " << timer.value() << '\n'; + timer.stop(); + std::cerr << "-- CPU Time " << timer.value() << '\n'; } void @@ -284,30 +306,32 @@ 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<4,float> test_array(IndexRange4D(proj_data.get_num_tof_poss(), proj_data.get_num_non_tof_sinograms(), proj_data.get_num_views(), proj_data.get_num_tangential_poss())); + Array<4, float> test_array(IndexRange4D(proj_data.get_num_tof_poss(), + proj_data.get_num_non_tof_sinograms(), + proj_data.get_num_views(), + proj_data.get_num_tangential_poss())); // copy to the array copy_to(proj_data, test_array.begin_all()); @@ -329,82 +353,81 @@ ProjDataTests::run_tests_in_memory_only(ProjDataInMemory& proj_data) } void -ProjDataTests:: -run_tests() +ProjDataTests::run_tests() { std::cerr << "-------- Testing ProjData --------\n"; shared_ptr exam_info_sptr(new ExamInfo); exam_info_sptr->imaging_modality = ImagingModality::PT; - std::cerr<< "\n--------------------------------non-TOF tests\n"; + std::cerr << "\n--------------------------------non-TOF tests\n"; { shared_ptr scanner_sptr(new Scanner(Scanner::E953)); // the test uses a non-standard number of views at the moment. // Just to see if that works as well :-) - shared_ptr proj_data_info_sptr - (ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span*/1, 10,/*views*/ 95, /*tang_pos*/132, /*arc_corrected*/ true) - ); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span*/ 1, + 10, + /*views*/ 95, + /*tang_pos*/ 132, + /*arc_corrected*/ true)); // 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); } - std::cerr<< "\n--------------------------------TOF tests\n"; + std::cerr << "\n--------------------------------TOF tests\n"; { shared_ptr scanner_sptr(new Scanner(Scanner::Discovery690)); - shared_ptr proj_data_info_sptr - (ProjDataInfo::construct_proj_data_info(scanner_sptr, - /*span*/ 2, 5,/*views*/ scanner_sptr->get_num_detectors_per_ring()/4, /*tang_pos*/22, /*arc_corrected*/ false, /* Tof_mashing */ 11) - ); + shared_ptr proj_data_info_sptr( + ProjDataInfo::construct_proj_data_info(scanner_sptr, + /*span*/ 2, + 5, + /*views*/ scanner_sptr->get_num_detectors_per_ring() / 4, + /*tang_pos*/ 22, + /*arc_corrected*/ false, + /* Tof_mashing */ 11)); // 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"); } - std::cerr<< "\n----------------- Tests with ProjDataInMemory\n"; + std::cerr << "\n----------------- Tests with ProjDataInMemory\n"; 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 proj_data_interfile(exam_info_sptr, proj_data_info_sptr, - "test_proj_data.hs", std::ios::in|std::ios::out|std::ios::trunc); + ProjDataInterfile proj_data_interfile( + 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_interfile); } - } END_NAMESPACE_STIR - USING_NAMESPACE_STIR -int main() +int +main() { ProjDataTests tests; tests.run_tests(); diff --git a/src/test/test_proj_data_in_memory.cxx b/src/test/test_proj_data_in_memory.cxx index ade318c1e..cca884dc3 100644 --- a/src/test/test_proj_data_in_memory.cxx +++ b/src/test/test_proj_data_in_memory.cxx @@ -38,12 +38,11 @@ START_NAMESPACE_STIR - /*! \ingroup test \brief Test class for ProjDataInMemory */ -class ProjDataInMemoryTests: public RunTests +class ProjDataInMemoryTests : public RunTests { public: void run_tests(); @@ -51,103 +50,95 @@ class ProjDataInMemoryTests: public RunTests void run_tests_tof(); }; - void -ProjDataInMemoryTests:: -run_tests() +ProjDataInMemoryTests::run_tests() { - this->run_tests_no_tof(); - this->run_tests_tof(); + this->run_tests_no_tof(); + this->run_tests_tof(); } void -ProjDataInMemoryTests:: -run_tests_no_tof() +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 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"); + 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"); + 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"); + 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 + // 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(), + 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"); 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"); } // 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) - ); - - + { + 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(), + 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(), + 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) - ); - - + { + 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 @@ -165,117 +156,101 @@ run_tests_no_tof() } void -ProjDataInMemoryTests:: -run_tests_tof() +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 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"); + 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"); + 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"); + 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"); + 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(), + 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(), + 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"); + 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()) - ); - + 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(), + 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(), + 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) - ); + 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); @@ -290,16 +265,15 @@ run_tests_tof() { // ok } - } } END_NAMESPACE_STIR - USING_NAMESPACE_STIR -int main() +int +main() { ProjDataInMemoryTests tests; tests.run_tests(); diff --git a/src/test/test_proj_data_info.cxx b/src/test/test_proj_data_info.cxx index 61d937144..c02ada1f1 100644 --- a/src/test/test_proj_data_info.cxx +++ b/src/test/test_proj_data_info.cxx @@ -128,9 +128,12 @@ ProjDataInfoTests::set_blocks_projdata_info(shared_ptr scanner_sptr) num_axial_pos_per_segment[i] = 2 * scanner_sptr->get_num_rings() - i - 1; } - auto proj_data_info_blocks_sptr - = std::make_shared(scanner_sptr, num_axial_pos_per_segment, min_ring_diff_v, max_ring_diff_v, - scanner_sptr->get_max_num_views(), scanner_sptr->get_max_num_non_arccorrected_bins()); + auto proj_data_info_blocks_sptr = std::make_shared(scanner_sptr, + num_axial_pos_per_segment, + min_ring_diff_v, + max_ring_diff_v, + scanner_sptr->get_max_num_views(), + scanner_sptr->get_max_num_non_arccorrected_bins()); return proj_data_info_blocks_sptr; } @@ -140,22 +143,29 @@ 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"); + 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, + 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(), + 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"); + 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_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"); + 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; @@ -185,15 +195,18 @@ ProjDataInfoTests::test_generic_proj_data_info(ProjDataInfo& proj_data_info) - 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) + 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) + 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 + 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); @@ -203,15 +216,27 @@ ProjDataInfoTests::test_generic_proj_data_info(ProjDataInfo& proj_data_info) { const Bin new_bin = proj_data_info.get_bin(lor, delta_time); #if 1 - // the differences need to also consider wrap-around in views, which would flip tangential pos and segment and TOF bin - const int diff_segment_num = intabs(org_bin.view_num() - new_bin.view_num()) < proj_data_info.get_num_views() - intabs(org_bin.view_num() - new_bin.view_num()) ? - intabs(org_bin.segment_num() - new_bin.segment_num()) : intabs(org_bin.segment_num() + new_bin.segment_num()); - const int diff_view_num = min(intabs(org_bin.view_num() - new_bin.view_num()), proj_data_info.get_num_views() - intabs(org_bin.view_num() - new_bin.view_num())); + // the differences need to also consider wrap-around in views, which would flip tangential pos and segment + // and TOF bin + const int diff_segment_num + = intabs(org_bin.view_num() - new_bin.view_num()) + < proj_data_info.get_num_views() - intabs(org_bin.view_num() - new_bin.view_num()) + ? intabs(org_bin.segment_num() - new_bin.segment_num()) + : intabs(org_bin.segment_num() + new_bin.segment_num()); + const int diff_view_num + = min(intabs(org_bin.view_num() - new_bin.view_num()), + proj_data_info.get_num_views() - 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.view_num() - new_bin.view_num()) < proj_data_info.get_num_views() - intabs(org_bin.view_num() - new_bin.view_num()) ? - intabs(org_bin.tangential_pos_num() - new_bin.tangential_pos_num()) : intabs(org_bin.tangential_pos_num() + new_bin.tangential_pos_num()); - const int diff_timing_pos_num = intabs(org_bin.view_num() - new_bin.view_num()) < proj_data_info.get_num_views() - intabs(org_bin.view_num() - new_bin.view_num()) ? - intabs(org_bin.timing_pos_num() - new_bin.timing_pos_num()) : intabs(org_bin.timing_pos_num() + new_bin.timing_pos_num()); + const int diff_tangential_pos_num + = intabs(org_bin.view_num() - new_bin.view_num()) + < proj_data_info.get_num_views() - intabs(org_bin.view_num() - new_bin.view_num()) + ? intabs(org_bin.tangential_pos_num() - new_bin.tangential_pos_num()) + : intabs(org_bin.tangential_pos_num() + new_bin.tangential_pos_num()); + const int diff_timing_pos_num + = intabs(org_bin.view_num() - new_bin.view_num()) + < proj_data_info.get_num_views() - intabs(org_bin.view_num() - new_bin.view_num()) + ? intabs(org_bin.timing_pos_num() - new_bin.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) @@ -263,35 +288,47 @@ ProjDataInfoTests::test_generic_proj_data_info(ProjDataInfo& proj_data_info) const Bin new_bin = proj_data_info.get_bin(lor_as_points, proj_data_info.get_tof_delta_time(org_bin)); #if 1 - // the differences need to also consider wrap-around in views, which would flip tangential pos and segment - const int diff_segment_num = intabs(org_bin.view_num() - new_bin.view_num()) < proj_data_info.get_num_views() - intabs(org_bin.view_num() - new_bin.view_num()) ? - intabs(org_bin.segment_num() - new_bin.segment_num()) : intabs(org_bin.segment_num() + new_bin.segment_num()); - const int diff_view_num = min(intabs(org_bin.view_num() - new_bin.view_num()), proj_data_info.get_num_views() - 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.view_num() - new_bin.view_num()) < proj_data_info.get_num_views() - intabs(org_bin.view_num() - new_bin.view_num()) ? - intabs(org_bin.tangential_pos_num() - new_bin.tangential_pos_num()) : intabs(org_bin.tangential_pos_num() + new_bin.tangential_pos_num()); - const int diff_timing_pos_num = intabs(org_bin.view_num() - new_bin.view_num()) < proj_data_info.get_num_views() - intabs(org_bin.view_num() - new_bin.view_num()) ? - intabs(org_bin.timing_pos_num() - new_bin.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: timing_pos")) + // the differences need to also consider wrap-around in views, which would flip tangential pos and segment + const int diff_segment_num + = intabs(org_bin.view_num() - new_bin.view_num()) + < proj_data_info.get_num_views() - intabs(org_bin.view_num() - new_bin.view_num()) + ? intabs(org_bin.segment_num() - new_bin.segment_num()) + : intabs(org_bin.segment_num() + new_bin.segment_num()); + const int diff_view_num + = min(intabs(org_bin.view_num() - new_bin.view_num()), + proj_data_info.get_num_views() - 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.view_num() - new_bin.view_num()) + < proj_data_info.get_num_views() - intabs(org_bin.view_num() - new_bin.view_num()) + ? intabs(org_bin.tangential_pos_num() - new_bin.tangential_pos_num()) + : intabs(org_bin.tangential_pos_num() + new_bin.tangential_pos_num()); + const int diff_timing_pos_num + = intabs(org_bin.view_num() - new_bin.view_num()) + < proj_data_info.get_num_views() - intabs(org_bin.view_num() - new_bin.view_num()) + ? intabs(org_bin.timing_pos_num() - new_bin.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: timing_pos")) #else if (!check(org_bin == new_bin, "round-trip get_LOR then get_bin")) @@ -358,11 +395,15 @@ ProjDataInfoCylindricalTests::test_cylindrical_proj_data_info(ProjDataInfoCylind { 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), + 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), + 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 @@ -371,29 +412,33 @@ ProjDataInfoCylindricalTests::test_cylindrical_proj_data_info(ProjDataInfoCylind 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))), + 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), + 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), + 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))), + 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); @@ -426,11 +471,14 @@ ProjDataInfoCylindricalTests::test_cylindrical_proj_data_info(ProjDataInfoCylind 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), + 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, + 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, + 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"); } } @@ -443,15 +491,16 @@ ProjDataInfoCylindricalTests::test_cylindrical_proj_data_info(ProjDataInfoCylind 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) + 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) + 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"); @@ -495,12 +544,15 @@ ProjDataInfoTests::run_Blocks_DOI_test() timer.start(); for (int seg = proj_data_info_blocks_doi0_ptr->get_min_segment_num(); - seg <= proj_data_info_blocks_doi0_ptr->get_max_segment_num(); ++seg) + seg <= proj_data_info_blocks_doi0_ptr->get_max_segment_num(); + ++seg) for (int ax = proj_data_info_blocks_doi0_ptr->get_min_axial_pos_num(seg); - ax <= proj_data_info_blocks_doi0_ptr->get_max_axial_pos_num(seg); ++ax) + ax <= proj_data_info_blocks_doi0_ptr->get_max_axial_pos_num(seg); + ++ax) for (int view = 0; view <= proj_data_info_blocks_doi0_ptr->get_max_view_num(); view++) for (int tang = proj_data_info_blocks_doi0_ptr->get_min_tangential_pos_num(); - tang <= proj_data_info_blocks_doi0_ptr->get_max_tangential_pos_num(); ++tang) + tang <= proj_data_info_blocks_doi0_ptr->get_max_tangential_pos_num(); + ++tang) { bin.segment_num() = seg; bin.axial_pos_num() = ax; @@ -593,10 +645,12 @@ ProjDataInfoTests::run_coordinate_test() for (int seg = proj_data_info_blocks_ptr->get_min_segment_num(); seg <= proj_data_info_blocks_ptr->get_max_segment_num(); ++seg) for (int ax = proj_data_info_blocks_ptr->get_min_axial_pos_num(seg); - ax <= proj_data_info_blocks_ptr->get_max_axial_pos_num(seg); ++ax) + ax <= proj_data_info_blocks_ptr->get_max_axial_pos_num(seg); + ++ax) for (int view = 0; view <= proj_data_info_blocks_ptr->get_max_view_num(); view++) for (int tang = proj_data_info_blocks_ptr->get_min_tangential_pos_num(); - tang <= proj_data_info_blocks_ptr->get_max_tangential_pos_num(); ++tang) + tang <= proj_data_info_blocks_ptr->get_max_tangential_pos_num(); + ++tang) { bin.segment_num() = seg; bin.axial_pos_num() = ax; @@ -609,16 +663,18 @@ ProjDataInfoTests::run_coordinate_test() const int num_detectors = proj_data_info_cyl_ptr->get_scanner_ptr()->get_num_detectors_per_ring(); int det_num1 = 0, det_num2 = 0; - proj_data_info_cyl_ptr->get_det_num_pair_for_view_tangential_pos_num(det_num1, det_num2, bin.view_num(), - bin.tangential_pos_num()); + proj_data_info_cyl_ptr->get_det_num_pair_for_view_tangential_pos_num( + det_num1, det_num2, bin.view_num(), bin.tangential_pos_num()); float phi; phi = static_cast((det_num1 + det_num2) * _PI / num_detectors - _PI / 2 + proj_data_info_cyl_ptr->get_azimuthal_angle_offset()); - lorC1 = LORInAxialAndNoArcCorrSinogramCoordinates(lorC.z1(), lorC.z2(), + lorC1 = LORInAxialAndNoArcCorrSinogramCoordinates(lorC.z1(), + lorC.z2(), phi, // lorC.phi(), - lorC.beta(), proj_data_info_cyl_ptr->get_ring_radius()); + lorC.beta(), + proj_data_info_cyl_ptr->get_ring_radius()); const float old_phi = proj_data_info_cyl_ptr->get_phi(bin); if (fabs(phi - old_phi) >= 2 * _PI / num_detectors) @@ -626,9 +682,11 @@ ProjDataInfoTests::run_coordinate_test() // float ang=2*_PI/num_detectors/2; // warning("view %d old_phi %g new_phi %g\n",bin.view_num(), old_phi, phi); - lorC1 = LORInAxialAndNoArcCorrSinogramCoordinates(lorC.z2(), lorC.z1(), + lorC1 = LORInAxialAndNoArcCorrSinogramCoordinates(lorC.z2(), + lorC.z1(), phi, // lorC.phi(), - -lorC.beta(), proj_data_info_cyl_ptr->get_ring_radius()); + -lorC.beta(), + proj_data_info_cyl_ptr->get_ring_radius()); } // check det_pos instead proj_data_info_blocks_ptr->get_det_pair_for_bin(Bdet1, Bring1, Bdet2, Bring2, bin); @@ -642,8 +700,8 @@ ProjDataInfoTests::run_coordinate_test() check_if_equal(Bring2, Cring2, ""); // test round trip from detector ID to coordinates and from cordinates to detecto IDs - proj_data_info_blocks_ptr->find_cartesian_coordinates_given_scanner_coordinates(roundt1, roundt2, Bring1, Bring2, - Bdet1, Bdet2); + proj_data_info_blocks_ptr->find_cartesian_coordinates_given_scanner_coordinates( + roundt1, roundt2, Bring1, Bring2, Bdet1, Bdet2); proj_data_info_blocks_ptr->find_bin_given_cartesian_coordinates_of_detection(binRT, roundt1, roundt2); proj_data_info_blocks_ptr->get_det_pair_for_bin(RTdet1, RTring1, RTdet2, RTring2, bin); @@ -664,23 +722,28 @@ ProjDataInfoTests::run_coordinate_test() if (abs(lorB.phi() - lorC1.phi()) < tolerance) { - check_if_equal(proj_data_info_blocks_ptr->get_s(bin), lorB.s(), + check_if_equal(proj_data_info_blocks_ptr->get_s(bin), + lorB.s(), "A get_s() from projdata is different from Block on Cylindrical LOR.s()"); - check_if_equal(lorB.s(), lorC1.s(), + check_if_equal(lorB.s(), + lorC1.s(), "tang_pos=" + std::to_string(tang) + " PHI-C=" + std::to_string(lorC1.phi()) + " PHI-B=" + std::to_string(lorB.phi()) + " view=" + std::to_string(view) + " Atest if BlocksOnCylindrical LOR.s is the same as the LOR produced by Cylindrical"); //) - check_if_equal(lorB.beta(), lorC1.beta(), + check_if_equal(lorB.beta(), + lorC1.beta(), "tang_pos=" + std::to_string(tang) + " ax_pos=" + std::to_string(ax) + " segment=" + std::to_string(seg) + " view=" + std::to_string(view) + " test if BlocksOnCylindrical LOR.beta is the same as the LOR produced by Cylindrical"); - check_if_equal(lorB.z1(), lorC1.z1(), + check_if_equal(lorB.z1(), + lorC1.z1(), "tang_pos=" + std::to_string(tang) + " ax_pos=" + std::to_string(ax) + " segment=" + std::to_string(seg) + " view=" + std::to_string(view) + " test if BlocksOnCylindrical LOR.z1 is the same as the LOR produced by Cylindrical"); - check_if_equal(lorB.z2(), lorC1.z2(), + check_if_equal(lorB.z2(), + lorC1.z2(), "tang_pos=" + std::to_string(tang) + " ax_pos=" + std::to_string(ax) + " segment=" + std::to_string(seg) + " view=" + std::to_string(view) + " test if BlocksOnCylindrical LOR.z2 is the same as the LOR produced by Cylindrical"); @@ -690,23 +753,28 @@ ProjDataInfoTests::run_coordinate_test() else if (abs(lorB.phi() - lorC1.phi()) + _PI < tolerance || abs(lorB.phi() - lorC1.phi()) - _PI < tolerance) { - check_if_equal(proj_data_info_blocks_ptr->get_s(bin), lorB.s(), + check_if_equal(proj_data_info_blocks_ptr->get_s(bin), + lorB.s(), "B get_s() from projdata is different from Block on Cylindrical LOR.s()"); - check_if_equal(proj_data_info_blocks_ptr->get_phi(bin), phi, + check_if_equal(proj_data_info_blocks_ptr->get_phi(bin), + phi, "B get_phi() from projdata Cylinder is different from Block on Cylindrical"); - check_if_equal(lorB.s(), -lorC1.s(), + check_if_equal(lorB.s(), + -lorC1.s(), "tang_pos=" + std::to_string(tang) + " PHYC=" + std::to_string(lorC1.phi()) + " PHIB=" + std::to_string(lorB.phi()) + " view=" + std::to_string(view) + " Btest if BlocksOnCylindrical LOR.s is the same as the LOR produced by Cylindrical"); //) - check_if_equal(lorB.beta(), -lorC1.beta(), + check_if_equal(lorB.beta(), + -lorC1.beta(), " Btest if BlocksOnCylindrical LOR.beta is the same as the LOR produced by Cylindrical"); - check_if_equal(lorB.z1(), lorC1.z2(), + check_if_equal(lorB.z1(), + lorC1.z2(), "tang_pos=" + std::to_string(tang) + " ax_pos=" + std::to_string(ax) + " segment=" + std::to_string(seg) + " view=" + std::to_string(view) + " Btest if BlocksOnCylindrical LOR.z1 is the same as the LOR produced by Cylindrical"); - check_if_equal(lorB.z2(), lorC1.z1(), - " Btest if BlocksOnCylindrical LOR.z2 is the same as the LOR produced by Cylindrical"); + check_if_equal( + lorB.z2(), lorC1.z1(), " Btest if BlocksOnCylindrical LOR.z2 is the same as the LOR produced by Cylindrical"); } else { @@ -770,10 +838,12 @@ ProjDataInfoTests::run_coordinate_test_for_realistic_scanner() for (int seg = proj_data_info_blocks_ptr->get_min_segment_num(); seg <= proj_data_info_blocks_ptr->get_max_segment_num(); ++seg) for (int ax = proj_data_info_blocks_ptr->get_min_axial_pos_num(seg); - ax <= proj_data_info_blocks_ptr->get_max_axial_pos_num(seg); ++ax) + ax <= proj_data_info_blocks_ptr->get_max_axial_pos_num(seg); + ++ax) for (int view = 0; view <= proj_data_info_blocks_ptr->get_max_view_num(); view++) for (int tang = proj_data_info_blocks_ptr->get_min_tangential_pos_num(); - tang <= proj_data_info_blocks_ptr->get_max_tangential_pos_num(); ++tang) + tang <= proj_data_info_blocks_ptr->get_max_tangential_pos_num(); + ++tang) { bin.segment_num() = seg; bin.axial_pos_num() = ax; @@ -784,8 +854,8 @@ ProjDataInfoTests::run_coordinate_test_for_realistic_scanner() proj_data_info_blocks_ptr->get_LOR(lorB, bin); int det_num1 = 0, det_num2 = 0; - proj_data_info_cyl_ptr->get_det_num_pair_for_view_tangential_pos_num(det_num1, det_num2, bin.view_num(), - bin.tangential_pos_num()); + proj_data_info_cyl_ptr->get_det_num_pair_for_view_tangential_pos_num( + det_num1, det_num2, bin.view_num(), bin.tangential_pos_num()); // check det_pos instead proj_data_info_blocks_ptr->get_det_pair_for_bin(Bdet1, Bring1, Bdet2, Bring2, bin); @@ -883,10 +953,10 @@ ProjDataInfoTests::run_lor_get_s_test() proj_data_info_blocks_ptr->get_bin_for_det_pos_pair(bin, det_pos_pair); proj_data_info_blocks_ptr->get_LOR(lorB, bin); - check_if_equal(0., lorC.s(), - std::to_string(i) + " Cylinder get_s() should be zero when the LOR passes at the center of the scanner"); - check_if_equal(0., lorB.s(), - std::to_string(i) + " Blocks get_s() should be zero when the LOR passes at the center of the scanner"); + check_if_equal( + 0., lorC.s(), std::to_string(i) + " Cylinder get_s() should be zero when the LOR passes at the center of the scanner"); + check_if_equal( + 0., lorB.s(), std::to_string(i) + " Blocks get_s() should be zero when the LOR passes at the center of the scanner"); } // Check get_s() (for BlocksOnCylindrical) when the line is at a given angle. We consider two blocks at a relative angle of @@ -927,8 +997,8 @@ ProjDataInfoTests::run_lor_get_s_test() if (i > 0) { check_if_equal(s_step, lorB.s() - prev_s, std::to_string(i) + " Blocks get_s() the step is different"); - check_if_equal(0.F, lorB.phi() - prev_phi, - " Blocks get_phi() should be always the same as we are considering parallel LORs"); + check_if_equal( + 0.F, lorB.phi() - prev_phi, " Blocks get_phi() should be always the same as we are considering parallel LORs"); } prev_s = lorB.s(); prev_phi = lorB.phi(); @@ -998,8 +1068,8 @@ ProjDataInfoCylindricalArcCorrTests::run_tests() 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); + 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"); @@ -1079,7 +1149,8 @@ ProjDataInfoCylindricalArcCorrTests::run_tests() // 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, + /*span*/ 1, + scanner_ptr->get_num_rings() - 1, /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2, /*tang_pos*/ 64, /*arc_corrected*/ true)); @@ -1087,7 +1158,8 @@ ProjDataInfoCylindricalArcCorrTests::run_tests() 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, + /*span*/ 5, + scanner_ptr->get_num_rings() - 1, /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2 / 8, /*tang_pos*/ 64, /*arc_corrected*/ true); @@ -1095,7 +1167,8 @@ ProjDataInfoCylindricalArcCorrTests::run_tests() 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, + /*span*/ 4, + scanner_ptr->get_num_rings() - 1, /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2 / 8, /*tang_pos*/ 64, /*arc_corrected*/ true); @@ -1131,7 +1204,8 @@ ProjDataInfoCylindricalNoArcCorrTests::run_tests() // 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, + /*span*/ 1, + scanner_ptr->get_num_rings() - 1, /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2, /*tang_pos*/ 64, /*arc_corrected*/ false)); @@ -1140,7 +1214,8 @@ ProjDataInfoCylindricalNoArcCorrTests::run_tests() 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, + /*span*/ 5, + scanner_ptr->get_num_rings() - 1, /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2 / 8, /*tang_pos*/ 64, /*arc_corrected*/ false); @@ -1148,7 +1223,8 @@ ProjDataInfoCylindricalNoArcCorrTests::run_tests() 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, + /*span*/ 2, + scanner_ptr->get_num_rings() - 7, /*views*/ scanner_ptr->get_num_detectors_per_ring() / 2 / 8, /*tang_pos*/ 64, /*arc_corrected*/ false); @@ -1157,7 +1233,8 @@ ProjDataInfoCylindricalNoArcCorrTests::run_tests() 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, + /*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, @@ -1327,12 +1404,15 @@ ProjDataInfoCylindricalNoArcCorrTests::test_proj_data_info(ProjDataInfoCylindric 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) + 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()) + 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()) + 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 @@ -1381,25 +1461,27 @@ ProjDataInfoCylindricalNoArcCorrTests::test_proj_data_info(ProjDataInfoCylindric bin.set_bin_value(0); // parallel loop for testing // Note that the omp construct cannot handle bin.segment_num() etc as loop variable, making this ugly -# ifdef STIR_OPENMP -# if _OPENMP <201107 -# pragma omp parallel for schedule(dynamic) firstprivate(bin) -# else -# pragma omp parallel for collapse(2) firstprivate(bin) -# endif -# endif +# ifdef STIR_OPENMP +# if _OPENMP < 201107 +# pragma omp parallel for schedule(dynamic) firstprivate(bin) +# else +# pragma omp parallel for collapse(2) firstprivate(bin) +# endif +# 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) + for (int view_num = proj_data_info.get_min_view_num(); view_num <= proj_data_info.get_max_view_num(); ++view_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) + axial_pos_num <= proj_data_info.get_max_axial_pos_num(segment_num); + ++axial_pos_num) for (int tangential_pos_num = proj_data_info.get_min_tangential_pos_num(); - tangential_pos_num <= proj_data_info.get_max_tangential_pos_num(); ++tangential_pos_num) + tangential_pos_num <= proj_data_info.get_max_tangential_pos_num(); + ++tangential_pos_num) 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) + 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) { bin.segment_num() = segment_num; bin.axial_pos_num() = axial_pos_num; @@ -1411,16 +1493,17 @@ ProjDataInfoCylindricalNoArcCorrTests::test_proj_data_info(ProjDataInfoCylindric // 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) + 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; + = 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")) { # ifdef STIR_OPENMP // add a pragma to avoid cerr output being jumbled up if there are any errors -# pragma omp critical(TESTPROJDATAINFO) +# pragma omp critical(TESTPROJDATAINFO) # endif { cerr << "Problem at segment = " << bin.segment_num() << ", axial pos " << bin.axial_pos_num() @@ -1457,15 +1540,16 @@ ProjDataInfoCylindricalNoArcCorrTests::test_proj_data_info(ProjDataInfoCylindric 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, 1); // use timing_pos_num>=0 as pre-TOF test + proj_data_info.find_cartesian_coordinates_given_scanner_coordinates( + coord_1, coord_2, Ring_A, Ring_B, det1, det2, 1); // use timing_pos_num>=0 as pre-TOF test 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) + 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) { diff --git a/src/test/test_proj_data_info_subsets.cxx b/src/test/test_proj_data_info_subsets.cxx index 442a4d385..a8d1348ce 100644 --- a/src/test/test_proj_data_info_subsets.cxx +++ b/src/test/test_proj_data_info_subsets.cxx @@ -66,21 +66,27 @@ class TestProjDataInfoSubsets : public RunTests ~TestProjDataInfoSubsets() override {} void run_tests() override; - void run_tests( - const std::shared_ptr& proj_data_sptr, const std::shared_ptr>& test_image_sptr); + void run_tests(const std::shared_ptr& proj_data_sptr, + const std::shared_ptr>& test_image_sptr); void test_split(const ProjData& proj_data); // void test_split_and_combine(const ProjData &proj_data, int num_subsets=2); void test_forward_projection_is_consistent(const shared_ptr>& input_image_sptr, - const shared_ptr& template_sino_sptr, bool use_z_symmetries = false, - bool use_other_symmetries = false, int num_subsets = 10); + const shared_ptr& template_sino_sptr, + bool use_z_symmetries = false, + bool use_other_symmetries = false, + int num_subsets = 10); void test_forward_projection_is_consistent_with_unbalanced_subset( const shared_ptr>& input_image_sptr, - const shared_ptr& template_sino_sptr, bool use_z_symmetries = false, bool use_other_symmetries = false, + const shared_ptr& template_sino_sptr, + bool use_z_symmetries = false, + bool use_other_symmetries = false, int num_subsets = 10); void test_forward_projection_is_consistent_with_reduced_segment_range( const shared_ptr>& input_image_sptr, - const shared_ptr& template_sino_sptr, bool use_z_symmetries = false, bool use_other_symmetries = false, + const shared_ptr& template_sino_sptr, + bool use_z_symmetries = false, + bool use_other_symmetries = false, int num_subsets = 10); void test_back_projection_is_consistent(const shared_ptr& input_sino_sptr, const shared_ptr>& template_image_sptr, @@ -93,32 +99,40 @@ class TestProjDataInfoSubsets : public RunTests static shared_ptr construct_projector_pair(const shared_ptr& template_projdatainfo_sptr, const shared_ptr>& template_image_sptr, - bool use_z_symmetries = false, bool use_other_symmetries = false); + bool use_z_symmetries = false, + bool use_other_symmetries = false); static void fill_proj_data_with_forward_projection(const std::shared_ptr& proj_data_sptr, const std::shared_ptr>& test_image_sptr); - void check_viewgrams(const ProjData& proj_data, const ProjData& subset_proj_data, + void check_viewgrams(const ProjData& proj_data, + const ProjData& subset_proj_data, const std::vector& subset_views, const std::string& str); ProjDataInMemory generate_full_forward_projection(const shared_ptr>& input_image_sptr, const shared_ptr& template_sino_sptr, - bool use_z_symmetries = false, bool use_other_symmetries = false); + bool use_z_symmetries = false, + bool use_other_symmetries = false); ProjDataInMemory generate_full_forward_projection(const shared_ptr>& input_image_sptr, const shared_ptr& template_projdata_info_sptr, const shared_ptr& template_examinfo_sptr, - bool use_z_symmetries = false, bool use_other_symmetries = false); + bool use_z_symmetries = false, + bool use_other_symmetries = false); shared_ptr> generate_full_back_projection(const shared_ptr& input_sino_sptr, const shared_ptr>& template_image_sptr, - bool use_z_symmetries = false, bool use_other_symmetries = false); + bool use_z_symmetries = false, + bool use_other_symmetries = false); void test_forward_projection_for_one_subset(const shared_ptr>& input_image_sptr, const ProjDataInMemory& full_forward_projection, - ProjData& subset_forward_projection, bool use_z_symmetries = false, + ProjData& subset_forward_projection, + bool use_z_symmetries = false, bool use_other_symmetries = false); }; -TestProjDataInfoSubsets::TestProjDataInfoSubsets(const std::string& sinogram_filename) : _sinogram_filename(sinogram_filename) {} +TestProjDataInfoSubsets::TestProjDataInfoSubsets(const std::string& sinogram_filename) + : _sinogram_filename(sinogram_filename) +{} shared_ptr TestProjDataInfoSubsets::construct_test_proj_data(bool TOF) @@ -128,22 +142,24 @@ TestProjDataInfoSubsets::construct_test_proj_data(bool TOF) { cerr << "\tGenerating default ProjData from E953" << endl; shared_ptr scanner_ptr(new Scanner(Scanner::E953)); - proj_data_info_sptr = - 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); + proj_data_info_sptr = 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); } else { cerr << "\tGenerating default ProjData from D690" << endl; shared_ptr scanner_sptr(new Scanner(Scanner::Discovery690)); - proj_data_info_sptr = - ProjDataInfo::construct_proj_data_info(scanner_sptr, - /*span*/ 2, 5,/*views*/ scanner_sptr->get_num_detectors_per_ring()/4, - /*tang_pos*/22, /*arc_corrected*/ false, /* Tof_mashing */ 11); - + proj_data_info_sptr = ProjDataInfo::construct_proj_data_info(scanner_sptr, + /*span*/ 2, + 5, + /*views*/ scanner_sptr->get_num_detectors_per_ring() / 4, + /*tang_pos*/ 22, + /*arc_corrected*/ false, + /* Tof_mashing */ 11); } auto exam_info_sptr = std::make_shared(); @@ -175,7 +191,8 @@ TestProjDataInfoSubsets::construct_test_image_data(const ProjData& template_proj shared_ptr TestProjDataInfoSubsets::construct_projector_pair(const shared_ptr& template_projdatainfo_sptr, const shared_ptr>& template_image_sptr, - bool use_z_symmetries, bool use_other_symmetries) + bool use_z_symmetries, + bool use_other_symmetries) { cerr << "\tSetting up default projector pair, ProjectorByBinPairUsingProjMatrixByBin" << endl; auto proj_matrix_sptr = std::make_shared(); @@ -203,16 +220,19 @@ TestProjDataInfoSubsets::fill_proj_data_with_forward_projection( } void -TestProjDataInfoSubsets::run_tests( - const std::shared_ptr& input_sino_sptr, const std::shared_ptr>& test_image_sptr) +TestProjDataInfoSubsets::run_tests(const std::shared_ptr& input_sino_sptr, + const std::shared_ptr>& test_image_sptr) { try { // check get_original_view_nums() on the original data { auto views = input_sino_sptr->get_original_view_nums(); - check_if_equal(views[0], input_sino_sptr->get_min_view_num(), "check get_original_view_nums on non-subset data: first view"); - check_if_equal(views[views.size()-1], input_sino_sptr->get_max_view_num(), "check get_original_view_nums on non-subset data: last view"); + check_if_equal( + views[0], input_sino_sptr->get_min_view_num(), "check get_original_view_nums on non-subset data: first view"); + check_if_equal(views[views.size() - 1], + input_sino_sptr->get_max_view_num(), + "check get_original_view_nums on non-subset data: last view"); } test_split(*input_sino_sptr); @@ -221,13 +241,20 @@ TestProjDataInfoSubsets::run_tests( test_forward_projection_is_consistent(test_image_sptr, input_sino_sptr); cerr << "repeat with an 'unusual' number of subsets, 13" << endl; - test_forward_projection_is_consistent(test_image_sptr, input_sino_sptr, /*use_z_symmetries=*/false, - /*use_z_symmetries=*/false, /*num_subsets=*/13); + test_forward_projection_is_consistent(test_image_sptr, + input_sino_sptr, + /*use_z_symmetries=*/false, + /*use_z_symmetries=*/false, + /*num_subsets=*/13); cerr << "repeat with z shift symmetries" << endl; - test_forward_projection_is_consistent(test_image_sptr, input_sino_sptr, /*use_z_symmetries=*/true, + test_forward_projection_is_consistent(test_image_sptr, + input_sino_sptr, + /*use_z_symmetries=*/true, /*use_z_symmetries=*/false); cerr << "repeat with all symmetries" << endl; - test_forward_projection_is_consistent(test_image_sptr, input_sino_sptr, /*use_z_symmetries=*/true, + test_forward_projection_is_consistent(test_image_sptr, + input_sino_sptr, + /*use_z_symmetries=*/true, /*use_z_symmetries=*/true); test_forward_projection_is_consistent_with_unbalanced_subset(test_image_sptr, input_sino_sptr); @@ -260,17 +287,19 @@ TestProjDataInfoSubsets::check_viewgrams(const ProjData& proj_data, // the corresponding view in the original data is at subset_views[i] // loop over all segments to check viewgram for all segments - for (int timing_pos_num = proj_data.get_min_tof_pos_num(); timing_pos_num <= proj_data.get_max_tof_pos_num(); ++timing_pos_num) + for (int timing_pos_num = proj_data.get_min_tof_pos_num(); timing_pos_num <= proj_data.get_max_tof_pos_num(); + ++timing_pos_num) for (int segment_num = proj_data.get_min_segment_num(); segment_num < proj_data.get_max_segment_num(); ++segment_num) - { - if (!check_if_equal(proj_data.get_viewgram(subset_views[i], segment_num, false, timing_pos_num), - subset_proj_data.get_viewgram(i, segment_num, false, timing_pos_num), "Are viewgrams equal?")) - { - cerr << "test_split failed: viewgrams weren't equal" << endl; - break; - } - // TODO also compare viewgram metadata - } + { + if (!check_if_equal(proj_data.get_viewgram(subset_views[i], segment_num, false, timing_pos_num), + subset_proj_data.get_viewgram(i, segment_num, false, timing_pos_num), + "Are viewgrams equal?")) + { + cerr << "test_split failed: viewgrams weren't equal" << endl; + break; + } + // TODO also compare viewgram metadata + } } } @@ -290,15 +319,21 @@ TestProjDataInfoSubsets::test_split(const ProjData& proj_data) // check basic sizes { check_if_equal(proj_data.get_num_views() / num_subsets, subset_proj_data.get_num_views(), "check on get_num_views()"); - check_if_equal(proj_data.get_min_tangential_pos_num(), subset_proj_data.get_min_tangential_pos_num(), "check on get_min_tangential_pos_num()"); - check_if_equal(proj_data.get_max_tangential_pos_num(), subset_proj_data.get_max_tangential_pos_num(), "check on get_max_tangential_pos_num()"); + check_if_equal(proj_data.get_min_tangential_pos_num(), + subset_proj_data.get_min_tangential_pos_num(), + "check on get_min_tangential_pos_num()"); + check_if_equal(proj_data.get_max_tangential_pos_num(), + subset_proj_data.get_max_tangential_pos_num(), + "check on get_max_tangential_pos_num()"); check_if_equal(proj_data.get_min_segment_num(), subset_proj_data.get_min_segment_num(), "check on get_min_segment_num()"); check_if_equal(proj_data.get_max_segment_num(), subset_proj_data.get_max_segment_num(), "check on get_max_segment_num()"); - for (int segment_num = proj_data.get_min_segment_num(); segment_num <= proj_data.get_max_segment_num(); ++ segment_num) + for (int segment_num = proj_data.get_min_segment_num(); segment_num <= proj_data.get_max_segment_num(); ++segment_num) { - check_if_equal(proj_data.get_min_axial_pos_num(segment_num), subset_proj_data.get_min_axial_pos_num(segment_num), + check_if_equal(proj_data.get_min_axial_pos_num(segment_num), + subset_proj_data.get_min_axial_pos_num(segment_num), "check on get_min_axial_pos_num() for seg " + std::to_string(segment_num)); - check_if_equal(proj_data.get_max_axial_pos_num(segment_num), subset_proj_data.get_max_axial_pos_num(segment_num), + check_if_equal(proj_data.get_max_axial_pos_num(segment_num), + subset_proj_data.get_max_axial_pos_num(segment_num), "check on get_max_axial_pos_num() for seg " + std::to_string(segment_num)); } } @@ -366,8 +401,11 @@ TestProjDataInfoSubsets::test_split(const ProjData& proj_data) void TestProjDataInfoSubsets::test_forward_projection_is_consistent( - const shared_ptr>& input_image_sptr, const shared_ptr& template_sino_sptr, - bool use_z_symmetries, bool use_other_symmetries, int num_subsets) + const shared_ptr>& input_image_sptr, + const shared_ptr& template_sino_sptr, + bool use_z_symmetries, + bool use_other_symmetries, + int num_subsets) { cerr << "\tTesting Subset forward projection is consistent" << endl; @@ -381,15 +419,18 @@ TestProjDataInfoSubsets::test_forward_projection_is_consistent( = _calc_regularly_sampled_views_for_subset(subset_n, num_subsets, full_forward_projection.get_num_views()); auto subset_forward_projection_uptr = full_forward_projection.get_subset(subset_views); - test_forward_projection_for_one_subset(input_image_sptr, full_forward_projection, *subset_forward_projection_uptr, - use_z_symmetries, use_other_symmetries); + test_forward_projection_for_one_subset( + input_image_sptr, full_forward_projection, *subset_forward_projection_uptr, use_z_symmetries, use_other_symmetries); } } void TestProjDataInfoSubsets::test_forward_projection_is_consistent_with_unbalanced_subset( - const shared_ptr>& input_image_sptr, const shared_ptr& template_sino_sptr, - bool use_z_symmetries, bool use_other_symmetries, int num_subsets) + const shared_ptr>& input_image_sptr, + const shared_ptr& template_sino_sptr, + bool use_z_symmetries, + bool use_other_symmetries, + int num_subsets) { cerr << "\tTesting Subset forward projection is consistent with unbalanced subset" << endl; @@ -423,15 +464,18 @@ TestProjDataInfoSubsets::test_forward_projection_is_consistent_with_unbalanced_s auto subset_forward_projection_uptr = full_forward_projection.get_subset(subset_views); cerr << "\tTesting unbalanced subset " << subset_n << ": views " << subset_views << endl; - test_forward_projection_for_one_subset(input_image_sptr, full_forward_projection, *subset_forward_projection_uptr, - use_z_symmetries, use_other_symmetries); + test_forward_projection_for_one_subset( + input_image_sptr, full_forward_projection, *subset_forward_projection_uptr, use_z_symmetries, use_other_symmetries); } } void TestProjDataInfoSubsets::test_forward_projection_is_consistent_with_reduced_segment_range( - const shared_ptr>& input_image_sptr, const shared_ptr& template_sino_sptr, - bool use_z_symmetries, bool use_other_symmetries, int num_subsets) + const shared_ptr>& input_image_sptr, + const shared_ptr& template_sino_sptr, + bool use_z_symmetries, + bool use_other_symmetries, + int num_subsets) { cerr << "\tTesting Subset forward projection is consistent with reduced segment range" << endl; @@ -445,9 +489,11 @@ TestProjDataInfoSubsets::test_forward_projection_is_consistent_with_reduced_segm // First we make a full forward projection with a reduced segment range shared_ptr reduced_seg_range_pdi_sptr(template_sino_sptr->get_proj_data_info_sptr()->clone()); reduced_seg_range_pdi_sptr->reduce_segment_range(-1, 1); - auto full_forward_projection - = generate_full_forward_projection(input_image_sptr, reduced_seg_range_pdi_sptr, template_sino_sptr->get_exam_info_sptr(), - use_z_symmetries, use_other_symmetries); + auto full_forward_projection = generate_full_forward_projection(input_image_sptr, + reduced_seg_range_pdi_sptr, + template_sino_sptr->get_exam_info_sptr(), + use_z_symmetries, + use_other_symmetries); for (int subset_n = 0; subset_n < num_subsets; ++subset_n) { @@ -464,25 +510,30 @@ TestProjDataInfoSubsets::test_forward_projection_is_consistent_with_reduced_segm subset_reduced_seg_range_pdi_sptr); cerr << "\tTesting reduced segment range on subset " << subset_n << endl; - test_forward_projection_for_one_subset(input_image_sptr, full_forward_projection, subset_forward_projection, - use_z_symmetries, use_other_symmetries); + test_forward_projection_for_one_subset( + input_image_sptr, full_forward_projection, subset_forward_projection, use_z_symmetries, use_other_symmetries); } } ProjDataInMemory TestProjDataInfoSubsets::generate_full_forward_projection(const shared_ptr>& input_image_sptr, const shared_ptr& template_projdata_sptr, - bool use_z_symmetries, bool use_other_symmetries) + bool use_z_symmetries, + bool use_other_symmetries) { - return generate_full_forward_projection(input_image_sptr, template_projdata_sptr->get_proj_data_info_sptr(), - template_projdata_sptr->get_exam_info_sptr(), use_z_symmetries, use_other_symmetries); + return generate_full_forward_projection(input_image_sptr, + template_projdata_sptr->get_proj_data_info_sptr(), + template_projdata_sptr->get_exam_info_sptr(), + use_z_symmetries, + use_other_symmetries); } ProjDataInMemory TestProjDataInfoSubsets::generate_full_forward_projection(const shared_ptr>& input_image_sptr, const shared_ptr& template_projdata_info_sptr, const shared_ptr& template_examinfo_sptr, - bool use_z_symmetries, bool use_other_symmetries) + bool use_z_symmetries, + bool use_other_symmetries) { check(input_image_sptr->find_max() > 0, "forward projection test run with empty image"); @@ -502,11 +553,13 @@ TestProjDataInfoSubsets::generate_full_forward_projection(const shared_ptr> TestProjDataInfoSubsets::generate_full_back_projection(const shared_ptr& input_sino_sptr, const shared_ptr>& template_image_sptr, - bool use_z_symmetries, bool use_other_symmetries) + bool use_z_symmetries, + bool use_other_symmetries) { - auto back_projector_sptr = construct_projector_pair(input_sino_sptr->get_proj_data_info_sptr(), template_image_sptr, - use_z_symmetries, use_other_symmetries) - ->get_back_projector_sptr(); + auto back_projector_sptr + = construct_projector_pair( + input_sino_sptr->get_proj_data_info_sptr(), template_image_sptr, use_z_symmetries, use_other_symmetries) + ->get_back_projector_sptr(); shared_ptr> full_back_projection_sptr(template_image_sptr->get_empty_copy()); back_projector_sptr->back_project(*full_back_projection_sptr, *input_sino_sptr); @@ -518,15 +571,18 @@ TestProjDataInfoSubsets::generate_full_back_projection(const shared_ptr>& input_image_sptr, const ProjDataInMemory& full_forward_projection, - ProjData& subset_forward_projection, bool use_z_symmetries, bool use_other_symmetries) + const shared_ptr>& input_image_sptr, + const ProjDataInMemory& full_forward_projection, + ProjData& subset_forward_projection, + bool use_z_symmetries, + bool use_other_symmetries) { cerr << "\tTesting Subset forward projection is consistent" << endl; auto subset_proj_data_info_sptr = std::dynamic_pointer_cast(subset_forward_projection.get_proj_data_info_sptr()); - auto subset_proj_pair_sptr = construct_projector_pair(subset_forward_projection.get_proj_data_info_sptr(), input_image_sptr, - use_z_symmetries, use_other_symmetries); + auto subset_proj_pair_sptr = construct_projector_pair( + subset_forward_projection.get_proj_data_info_sptr(), input_image_sptr, use_z_symmetries, use_other_symmetries); subset_proj_pair_sptr->get_forward_projector_sptr()->forward_project(subset_forward_projection); @@ -539,12 +595,16 @@ TestProjDataInfoSubsets::test_forward_projection_for_one_subset( // the corresponding view in the original data is at subset_views[i] // loop over all segments to check viewgram for all segments - for (int timing_pos_num = full_forward_projection.get_min_tof_pos_num(); timing_pos_num <= full_forward_projection.get_max_tof_pos_num(); ++timing_pos_num) + for (int timing_pos_num = full_forward_projection.get_min_tof_pos_num(); + timing_pos_num <= full_forward_projection.get_max_tof_pos_num(); + ++timing_pos_num) for (int segment_num = full_forward_projection.get_min_segment_num(); - segment_num < full_forward_projection.get_max_segment_num(); ++segment_num) + segment_num < full_forward_projection.get_max_segment_num(); + ++segment_num) { if (!check_if_equal(full_forward_projection.get_viewgram(subset_views[i], segment_num, false, timing_pos_num), - subset_forward_projection.get_viewgram(i, segment_num, false, timing_pos_num), "Are viewgrams equal?")) + subset_forward_projection.get_viewgram(i, segment_num, false, timing_pos_num), + "Are viewgrams equal?")) { cerr << "testing forward projection failed: viewgrams weren't equal in subset " << i << endl; break; @@ -556,7 +616,8 @@ TestProjDataInfoSubsets::test_forward_projection_for_one_subset( void TestProjDataInfoSubsets::test_back_projection_is_consistent( - const shared_ptr& input_sino_sptr, const shared_ptr>& template_image_sptr, + const shared_ptr& input_sino_sptr, + const shared_ptr>& template_image_sptr, int num_subsets) { auto full_back_projection_sptr = generate_full_back_projection(input_sino_sptr, template_image_sptr); @@ -608,7 +669,6 @@ TestProjDataInfoSubsets::run_tests() auto test_image_sptr = construct_test_image_data(*input_sino_sptr); run_tests(input_sino_sptr, test_image_sptr); } - } END_NAMESPACE_STIR diff --git a/src/test/test_proj_data_maths.cxx b/src/test/test_proj_data_maths.cxx index adcf2d713..cb55aca69 100644 --- a/src/test/test_proj_data_maths.cxx +++ b/src/test/test_proj_data_maths.cxx @@ -31,91 +31,88 @@ #include "stir/error.h" START_NAMESPACE_STIR - /*! \ingroup test \brief Test class for ProjDataInMemory */ -class ProjDataInMemoryTests: public RunTests +class ProjDataInMemoryTests : public RunTests { public: void run_tests() override; + private: void run_tests(shared_ptr exam_info_sptr, shared_ptr proj_data_info_sptr); }; -static -void check_proj_data_are_equal_and_non_zero(const ProjData& x, const ProjData& y) +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"); + 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(shared_ptr exam_info_sptr, shared_ptr proj_data_info_sptr) +ProjDataInMemoryTests::run_tests(shared_ptr exam_info_sptr, shared_ptr proj_data_info_sptr) { - 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); + 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); } void -ProjDataInMemoryTests:: -run_tests() +ProjDataInMemoryTests::run_tests() { std::cerr << "tests on proj_data maths\n"; @@ -123,12 +120,12 @@ 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) - ); + 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); @@ -142,10 +139,14 @@ run_tests() // Create scanner and proj data info shared_ptr scanner_sptr(new Scanner(Scanner::Discovery690)); - shared_ptr proj_data_info_sptr - (ProjDataInfo::construct_proj_data_info(scanner_sptr, - /*span*/ 2, 5,/*views*/ scanner_sptr->get_num_detectors_per_ring()/4, /*tang_pos*/22, /*arc_corrected*/ false, /* Tof_mashing */ 11) - ); + shared_ptr proj_data_info_sptr( + ProjDataInfo::construct_proj_data_info(scanner_sptr, + /*span*/ 2, + 5, + /*views*/ scanner_sptr->get_num_detectors_per_ring() / 4, + /*tang_pos*/ 22, + /*arc_corrected*/ false, + /* Tof_mashing */ 11)); // Create pd1 and pd2 shared_ptr exam_info_sptr(new ExamInfo); @@ -153,16 +154,14 @@ run_tests() run_tests(exam_info_sptr, proj_data_info_sptr); } - - } END_NAMESPACE_STIR - USING_NAMESPACE_STIR -int main() +int +main() { ProjDataInMemoryTests tests; tests.run_tests(); diff --git a/src/test/test_radionuclide.cxx b/src/test/test_radionuclide.cxx index 9accf27ee..96171d7be 100644 --- a/src/test/test_radionuclide.cxx +++ b/src/test/test_radionuclide.cxx @@ -10,7 +10,7 @@ */ /*! - \file + \file \ingroup test \ingroup ancillary \brief A simple program to test stir::RadionuclideDB and stir::Radionuclide @@ -23,7 +23,6 @@ #include - START_NAMESPACE_STIR /*! @@ -37,7 +36,6 @@ class RadionuclideTest : public RunTests void run_tests() override; }; - void RadionuclideTest::run_tests() { @@ -55,14 +53,14 @@ RadionuclideTest::run_tests() check_if_equal(F18_rnuclide.get_energy(), 511.F, "check on F18 energy"); check_if_equal(F18_rnuclide.get_branching_ratio(), 0.9686F, "check on F-18 branching ratio"); check(F18_rnuclide.get_modality() == pt_mod, "check on F-18 modality"); - + const auto Tc99m_rnuclide = db.get_radionuclide(nm_mod, "^99m^Technetium"); std::cerr << "Tc-99m radionuclide: " << Tc99m_rnuclide.parameter_info(); check_if_equal(Tc99m_rnuclide.get_half_life(), 21624.12, "check on Tc-99m half-life"); check_if_equal(Tc99m_rnuclide.get_energy(), 140.511F, "check on Tc-99m energy"); check_if_equal(Tc99m_rnuclide.get_branching_ratio(), 0.885F, "check on Tc-99m branching ratio"); check(Tc99m_rnuclide.get_modality() == nm_mod, "check on Tc-99m modality"); - + std::cerr << "Testing defaults\n"; { // PET @@ -99,32 +97,25 @@ RadionuclideTest::run_tests() check_if_equal(Y90_rnuclide_PET.get_energy(), 511.F, "check on Y90 (PET) energy"); check_if_equal(Y90_rnuclide_PET.get_branching_ratio(), 0.0000319F, "check on Y90 (PET) branching ratio"); check(Y90_rnuclide_PET.get_modality() == pt_mod, "check on Y90 (PET) modality"); - } - + std::cerr << "Testing lookup-table and database\n"; { check(F18_rnuclide == db.get_radionuclide(pt_mod, "F-18"), "alias F-18"); check(F18_rnuclide == db.get_radionuclide(pt_mod, "18F"), "alias 18F"); check(Tc99m_rnuclide == db.get_radionuclide(nm_mod, "Tc-99m"), "alias Tc-99m"); check(Tc99m_rnuclide == db.get_radionuclide(nm_mod, "99mTc"), "alias 99mTc"); - check_if_equal(db.get_radionuclide(pt_mod, "^11^Carbon").get_half_life(), 1221.66F, - "C11 half-life"); + check_if_equal(db.get_radionuclide(pt_mod, "^11^Carbon").get_half_life(), 1221.66F, "C11 half-life"); } -#endif - +#endif } - END_NAMESPACE_STIR - - USING_NAMESPACE_STIR - - -int main() +int +main() { RadionuclideTest tests; tests.run_tests(); diff --git a/src/test/test_stir_math.cxx b/src/test/test_stir_math.cxx index abbcd3f02..b28d32dd4 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$$*. @@ -55,142 +55,138 @@ class stir_mathTests : public RunTests { public: stir_mathTests(const string& stir_math_executable) - : stir_math_executable(stir_math_executable) + : stir_math_executable(stir_math_executable) {} - + void run_tests() override; + 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"); - calc_data = data1; - calc_data += data2 + data3; - - check_if_equal( calc_data, *out_data_ptr,"test on adding"); - } + { + 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"); + } // mult 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"); - } + { + 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"); + } // 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); + 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"); - } + { + 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"); - 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"); - } - // 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"); - } + { + 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"); + } + // 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"); + } // 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")) - { - 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.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"); + } if (this->is_everything_ok()) { @@ -211,16 +207,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); @@ -232,99 +227,102 @@ 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")) - { - 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"); - } + { + 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"); + } // mult 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"); - } + { + 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"); + } // 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); + 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"); - } + { + 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")) - { - 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"); - } - // 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; - 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"); - } + { + 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"); + } + // 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; + 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"); + } // 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")) - { - calc_data.fill(0); - calc_data += data2; - calc_data *= calc_data * 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"); - } + { + calc_data.fill(0); + calc_data += data2; + calc_data *= calc_data * 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"); + } if (this->is_everything_ok()) { @@ -338,18 +336,16 @@ stir_mathTests::run_tests() remove("STIRtmpout.s"); } } - } END_NAMESPACE_STIR - USING_NAMESPACE_STIR - -int main(int argc, char** argv) +int +main(int argc, char** argv) { - stir_mathTests tests(argc==2?argv[1] : "stir_math"); + 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 index ca908ffd1..66357f7e9 100644 --- a/src/test/test_time_of_flight.cxx +++ b/src/test/test_time_of_flight.cxx @@ -37,7 +37,7 @@ #include "stir/Scanner.h" #include "boost/lexical_cast.hpp" #ifdef HAVE_CERN_ROOT -#include "stir/listmode/CListRecordROOT.h" +# include "stir/listmode/CListRecordROOT.h" #endif #include "stir/info.h" #include "stir/warning.h" @@ -45,13 +45,17 @@ START_NAMESPACE_STIR - // Helper class. -class FloatFloat{ +class FloatFloat +{ public: - FloatFloat() { float1 = 0.f; float2 = 0.f;} - float float1; - float float2; + FloatFloat() + { + float1 = 0.f; + float2 = 0.f; + } + float float1; + float float2; }; /*! @@ -74,142 +78,142 @@ class FloatFloat{ class TOF_Tests : public RunTests { public: - void run_tests() override; + void run_tests() override; private: - - void test_tof_proj_data_info_kernel(); - void test_tof_proj_data_info_det_pos(); - void test_tof_proj_data_info(); + void test_tof_proj_data_info_kernel(); + void test_tof_proj_data_info_det_pos(); + void test_tof_proj_data_info(); #ifdef HAVE_CERN_ROOT void test_CListEventROOT(); #endif - //! 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_proj_data_info_sptr; - - shared_ptr > test_discretised_density_sptr; - shared_ptr test_proj_matrix_sptr; - shared_ptr test_nonTOF_proj_matrix_sptr; + //! 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_proj_data_info_sptr; + + shared_ptr> test_discretised_density_sptr; + shared_ptr test_proj_matrix_sptr; + shared_ptr test_nonTOF_proj_matrix_sptr; }; void TOF_Tests::run_tests() { - // New Scanner - test_scanner_sptr.reset(new Scanner(Scanner::PETMR_Signa)); - - // 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_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_nonTOF_proj_data_info_sptr->set_tof_mash_factor(0); - - test_tof_proj_data_info(); - // test_tof_geometry_1(); + // New Scanner + test_scanner_sptr.reset(new Scanner(Scanner::PETMR_Signa)); + + // 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_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_nonTOF_proj_data_info_sptr->set_tof_mash_factor(0); + + test_tof_proj_data_info(); + // test_tof_geometry_1(); #ifdef HAVE_CERN_ROOT - test_CListEventROOT(); + test_CListEventROOT(); #endif - // 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); + // 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_kernel() { - const int correct_tof_mashing_factor = 39; - const int num_timing_positions = test_scanner_sptr->get_max_num_timing_poss() / correct_tof_mashing_factor; - const 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; - std::vector correct_timing_locations(num_timing_positions); - for (int i=0; iget_max_num_timing_poss() / correct_tof_mashing_factor; + const 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; + std::vector correct_timing_locations(num_timing_positions); + for (int i = 0; i < num_timing_positions; ++i) + { + correct_timing_locations[i] = (i - (num_timing_positions - 1) / 2.F) * correct_width_of_tof_bin; + } - check_if_equal(correct_tof_mashing_factor, - test_proj_data_info_sptr->get_tof_mash_factor(), "Different TOF mashing factor."); + 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."); + check_if_equal(num_timing_positions, test_proj_data_info_sptr->get_num_tof_poss(), "Different number of timing positions."); - for (int timing_pos_num = test_proj_data_info_sptr->get_min_tof_pos_num(), counter = 0; - timing_pos_num <= test_proj_data_info_sptr->get_max_tof_pos_num(); ++ timing_pos_num, counter++) + for (int timing_pos_num = test_proj_data_info_sptr->get_min_tof_pos_num(), counter = 0; + timing_pos_num <= test_proj_data_info_sptr->get_max_tof_pos_num(); + ++timing_pos_num, counter++) { - Bin bin(0, 0, 0, 0, timing_pos_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()"); + Bin bin(0, 0, 0, 0, timing_pos_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_scanner_ptr()->get_coincidence_window_width_in_mm()), - "Coincidence widths don't match."); - + 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_scanner_ptr()->get_coincidence_window_width_in_mm()), + "Coincidence widths don't match."); } - void TOF_Tests::test_tof_proj_data_info_det_pos() { - auto pdi_ptr = - dynamic_cast (test_proj_data_info_sptr.get()); + auto pdi_ptr = dynamic_cast(test_proj_data_info_sptr.get()); - Bin b1(1,2,3,4,5); + Bin b1(1, 2, 3, 4, 5); Bin b2 = b1; b2.timing_pos_num() = -b1.timing_pos_num(); @@ -218,11 +222,11 @@ TOF_Tests::test_tof_proj_data_info_det_pos() pdi_ptr->get_det_pos_pair_for_bin(dp2, b2); check((dp1.timing_pos() == dp2.timing_pos() && dp1.pos1() == dp2.pos2() && dp1.pos2() == dp2.pos1()) - || (static_cast(dp1.timing_pos()) == -static_cast(dp2.timing_pos()) && dp1.pos1() == dp2.pos1() && dp1.pos2() == dp2.pos2()), + || (static_cast(dp1.timing_pos()) == -static_cast(dp2.timing_pos()) && dp1.pos1() == dp2.pos1() + && dp1.pos2() == dp2.pos2()), "get_det_pos_for_bin with bins of opposite timing_pos"); } - void TOF_Tests::test_tof_proj_data_info() { @@ -231,7 +235,8 @@ TOF_Tests::test_tof_proj_data_info() } #ifdef HAVE_CERN_ROOT -void TOF_Tests::test_CListEventROOT() +void +TOF_Tests::test_CListEventROOT() { std::cerr << "CListEventROOT tests\n"; const auto old_tol = this->get_tolerance(); @@ -272,17 +277,28 @@ void TOF_Tests::test_CListEventROOT() event.get_detection_position(det_pos_swapped); if (det_pos_swapped.timing_pos() == det_pos.timing_pos()) { - check_if_equal(det_pos_swapped.pos1(), det_pos.pos1(), "CListEventROOT: get_detection_position with swapped detectors: equal timing_pos, but different pos1"); - check_if_equal(det_pos_swapped.pos2(), det_pos.pos2(), "CListEventROOT: get_detection_position with swapped detectors: equal timing_pos, but different pos2"); + check_if_equal(det_pos_swapped.pos1(), + det_pos.pos1(), + "CListEventROOT: get_detection_position with swapped detectors: equal timing_pos, but different pos1"); + check_if_equal(det_pos_swapped.pos2(), + det_pos.pos2(), + "CListEventROOT: get_detection_position with swapped detectors: equal timing_pos, but different pos2"); } else if (det_pos_swapped.timing_pos() == -det_pos.timing_pos()) { - check_if_equal(det_pos_swapped.pos2(), det_pos.pos1(), "CListEventROOT: get_detection_position with swapped detectors: opposite timing_pos, but different pos1/2"); - check_if_equal(det_pos_swapped.pos1(), det_pos.pos2(), "CListEventROOT: get_detection_position with swapped detectors: opposite timing_pos, but different pos1/2"); + check_if_equal( + det_pos_swapped.pos2(), + det_pos.pos1(), + "CListEventROOT: get_detection_position with swapped detectors: opposite timing_pos, but different pos1/2"); + check_if_equal( + det_pos_swapped.pos1(), + det_pos.pos2(), + "CListEventROOT: get_detection_position with swapped detectors: opposite timing_pos, but different pos1/2"); } else { - check_if_equal(std::abs(det_pos_swapped.timing_pos()), std::abs(det_pos.timing_pos()), + check_if_equal(std::abs(det_pos_swapped.timing_pos()), + std::abs(det_pos.timing_pos()), "CListEventROOT: get_detection_position with swapped detectors: wrong timing_pos"); } } @@ -291,8 +307,10 @@ void TOF_Tests::test_CListEventROOT() LORInAxialAndNoArcCorrSinogramCoordinates lor_sc_swapped; test_proj_data_info_sptr->get_LOR(lor_sc_swapped, bin_swapped); LORAs2Points test_lor_swapped(lor_sc); - check_if_equal(lor_2pts_swapped.p1(), test_lor_swapped.p1(), "CListEventROOT::get_LOR and ProjDataInfo::get_LOR consistency check 3"); - check_if_equal(lor_2pts_swapped.p2(), test_lor_swapped.p2(), "CListEventROOT::get_LOR and ProjDataInfo::get_LOR consistency check 4"); + check_if_equal( + lor_2pts_swapped.p1(), test_lor_swapped.p1(), "CListEventROOT::get_LOR and ProjDataInfo::get_LOR consistency check 3"); + check_if_equal( + lor_2pts_swapped.p2(), test_lor_swapped.p2(), "CListEventROOT::get_LOR and ProjDataInfo::get_LOR consistency check 4"); // now check if equal check_if_equal(bin, bin_swapped, "CListEventROOT:get_bin for reordered detectors"); @@ -307,271 +325,259 @@ void TOF_Tests::test_CListEventROOT() 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; + 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; + float nonTOF_val = 0.0; + float TOF_val = 0.0; - ProjMatrixElemsForOneBin proj_matrix_row; - ProjMatrixElemsForOneBin sum_tof_proj_matrix_row; + ProjMatrixElemsForOneBin proj_matrix_row; + ProjMatrixElemsForOneBin sum_tof_proj_matrix_row; - HighResWallClockTimer t; - std::vector times_of_tofing; + HighResWallClockTimer t; + std::vector times_of_tofing; - ProjDataInfoCylindrical* proj_data_ptr = - dynamic_cast (test_proj_data_info_sptr.get()); + 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()); + // ProjDataInfoCylindrical* proj_data_nonTOF_ptr = + // dynamic_cast (test_nonTOF_proj_data_info_sptr.get()); - LORInAxialAndNoArcCorrSinogramCoordinates lor; + LORInAxialAndNoArcCorrSinogramCoordinates lor; - Bin this_bin(seg_num, view_num, axial_num, tang_num, 1.f); + 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(); + 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: "<get_LOR(lor, this_bin); - LORAs2Points lor2(lor); + 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); + if (print_to_file) + export_lor(proj_matrix_row, lor2.p1(), lor2.p2(), 500000000); - for (int timing_pos_num = test_proj_data_info_sptr->get_min_tof_pos_num(); - timing_pos_num <= test_proj_data_info_sptr->get_max_tof_pos_num(); ++ timing_pos_num) + for (int timing_pos_num = test_proj_data_info_sptr->get_min_tof_pos_num(); + timing_pos_num <= test_proj_data_info_sptr->get_max_tof_pos_num(); + ++timing_pos_num) { - ProjMatrixElemsForOneBin new_proj_matrix_row; - Bin bin(seg_num, view_num, axial_num, tang_num, timing_pos_num, 1.f); + ProjMatrixElemsForOneBin new_proj_matrix_row; + Bin bin(seg_num, view_num, axial_num, tang_num, timing_pos_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()); + 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_pos_num, - proj_matrix_row); + if (print_to_file) + export_lor(new_proj_matrix_row, lor2.p1(), lor2.p2(), timing_pos_num, proj_matrix_row); - - if (sum_tof_proj_matrix_row.size() > 0) + 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 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()) + 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()) + 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; + 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; + ++sum_element_ptr; } - if (!found) + if (!found) { - sum_tof_proj_matrix_row.push_back(ProjMatrixElemsForOneBin::value_type(element_ptr->get_coords(), - element_ptr->get_value())); - break; + sum_tof_proj_matrix_row.push_back( + ProjMatrixElemsForOneBin::value_type(element_ptr->get_coords(), element_ptr->get_value())); + break; } - ++element_ptr; + ++element_ptr; } - } - else + else { - ProjMatrixElemsForOneBin::iterator element_ptr = new_proj_matrix_row.begin(); - while (element_ptr != new_proj_matrix_row.end()) + 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; + 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 nonTOF LOR, for central voxels only - // Get value of TOF 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; + } + } - { - 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; - } - } + // 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."); + 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); + { + 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()); + 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); + 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: "<& point1, - const CartesianCoordinate3D& point2, - int current_id) +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()); + std::ofstream myfile; + std::string file_name = "glor_" + boost::lexical_cast(current_id) + ".txt"; + myfile.open(file_name.c_str()); - CartesianCoordinate3D voxel_center; + CartesianCoordinate3D voxel_center; - std::vector lor_to_export; - lor_to_export.reserve(probabilities.size()); + std::vector lor_to_export; + lor_to_export.reserve(probabilities.size()); - const CartesianCoordinate3D middle = (point1 + point2)*0.5f; - const CartesianCoordinate3D diff = point2 - middle; + 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())); + 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()) + 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()); + 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 ); + // if(voxel_center.z() == 0.f) + { + project_point_on_a_line(point1, point2, voxel_center); - const CartesianCoordinate3D x = voxel_center - middle; + const CartesianCoordinate3D x = voxel_center - middle; - const float d2 = -inner_product(x, diff) * lor_length; + const float d2 = -inner_product(x, diff) * lor_length; - FloatFloat tmp; - tmp.float1 = d2; + 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() <get_value(); - lor_to_export.push_back(tmp); - } - ++element_ptr; + tmp.float2 = element_ptr->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; + 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(); + myfile << std::endl; + myfile.close(); } void -TOF_Tests:: -export_lor(ProjMatrixElemsForOneBin& probabilities, - const CartesianCoordinate3D& point1, - const CartesianCoordinate3D& point2, int current_id, - ProjMatrixElemsForOneBin& template_probabilities) +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()); + 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 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())); + const float lor_length = 1.f / (std::sqrt(diff.x() * diff.x() + diff.y() * diff.y() + diff.z() * diff.z())); - CartesianCoordinate3D voxel_center; + CartesianCoordinate3D voxel_center; - std::vector lor_to_export; - lor_to_export.reserve(template_probabilities.size()); + 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()) + 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 ); + 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 CartesianCoordinate3D x = voxel_center - middle; - const float d2 = -inner_product(x, diff) * lor_length; + const float d2 = -inner_product(x, diff) * lor_length; - FloatFloat tmp; - tmp.float1 = d2; + FloatFloat tmp; + tmp.float1 = d2; - ProjMatrixElemsForOneBin::iterator element_ptr = probabilities.begin(); + 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; + 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; + 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(); + myfile << std::endl; + myfile.close(); } END_NAMESPACE_STIR -int main() +int +main() { - USING_NAMESPACE_STIR - TOF_Tests tests; - tests.run_tests(); - return tests.main_return_value(); + 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 d27b95e27..80923bfd3 100644 --- a/src/test/test_warp_image.cxx +++ b/src/test/test_warp_image.cxx @@ -3,16 +3,16 @@ /* Copyright (C) 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 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 */ @@ -47,123 +47,140 @@ 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) + 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; + 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(); diff --git a/src/test/test_zoom_image.cxx b/src/test/test_zoom_image.cxx index ccb5d294a..a50f9b74b 100644 --- a/src/test/test_zoom_image.cxx +++ b/src/test/test_zoom_image.cxx @@ -1,21 +1,21 @@ // // /* - Copyright (C) 2006- 2007, Hammersmith Imanet Ltd - This file is part of STIR. - - SPDX-License-Identifier: Apache-2.0 - + Copyright (C) 2006- 2007, Hammersmith Imanet Ltd + This file is part of STIR. + + SPDX-License-Identifier: Apache-2.0 + 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" @@ -43,33 +43,29 @@ class zoom_imageTests : public RunTests void run_tests() override; }; - 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 @@ -80,93 +76,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(); diff --git a/src/utilities/GE/print_GE_singles_values.cxx b/src/utilities/GE/print_GE_singles_values.cxx index 5c2ab360c..89a9c8373 100644 --- a/src/utilities/GE/print_GE_singles_values.cxx +++ b/src/utilities/GE/print_GE_singles_values.cxx @@ -13,7 +13,6 @@ \author Kris Thielemans */ - #include "stir/data/SinglesRatesFromGEHDF5.h" #include "stir/stream.h" #include "stir/IndexRange3D.h" @@ -22,32 +21,29 @@ USING_NAMESPACE_STIR - - - -int -main (int argc, char **argv) +int +main(int argc, char** argv) { - // Check arguments. - // Singles filename - if (argc != 2) { - std::cerr << "Program to print out values from a singles file.\n\n"; - std::cerr << "Usage: " << argv[0] << " rdf_filename \n\n"; - exit(EXIT_FAILURE); - } + // Check arguments. + // Singles filename + if (argc != 2) + { + std::cerr << "Program to print out values from a singles file.\n\n"; + std::cerr << "Usage: " << argv[0] << " rdf_filename \n\n"; + exit(EXIT_FAILURE); + } const std::string rdf_filename = argv[1]; // Singles file object. GE::RDF_HDF5::SinglesRatesFromGEHDF5 singles(rdf_filename); // Get total number of frames - //int num_frames = singles.get_num_frames(); - + // int num_frames = singles.get_num_frames(); + // Get scanner details and, from these, the number of singles units. const Scanner& scanner = *singles.get_scanner_ptr(); - const TimeFrameDefinitions time_def = - singles.get_time_frame_definitions(); + const TimeFrameDefinitions time_def = singles.get_time_frame_definitions(); // print time-frame info { @@ -59,38 +55,34 @@ main (int argc, char **argv) const int units = units_secs ? 1 : 1000; const std::string units_string = units_secs ? " secs" : " millisecs"; - for (unsigned frame_num = 1; frame_num<=time_def.get_num_time_frames(); ++frame_num) + for (unsigned frame_num = 1; frame_num <= time_def.get_num_time_frames(); ++frame_num) { 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 frame_duration = end_frame - start_frame; - std::cout << "(" << frame_duration*units << ", " << start_frame*units << ')'; + std::cout << "(" << frame_duration * units << ", " << start_frame * units << ')'; } std::cout << std::endl; } - Array<3,float> singles_arr(IndexRange3D(time_def.get_num_time_frames(), - scanner.get_num_axial_singles_units(), - scanner.get_num_transaxial_singles_units())); + Array<3, float> singles_arr(IndexRange3D( + time_def.get_num_time_frames(), scanner.get_num_axial_singles_units(), scanner.get_num_transaxial_singles_units())); - for (int time_frame_num=1; time_frame_num<=time_def.get_num_time_frames(); ++time_frame_num) + for (int time_frame_num = 1; time_frame_num <= time_def.get_num_time_frames(); ++time_frame_num) { - for (int ax=0; ax energy_window_name; + private: - //shared_ptr proj_data_info_sptr; + // shared_ptr proj_data_info_sptr; std::string dicom_filename; float start_angle = 0.0f; float angular_step = 0.0f; - int actual_frame_duration = 0; //frame duration in msec + int actual_frame_duration = 0; // frame duration in msec int num_of_rotations = 0; std::string direction_of_rotation, isotope_name; int extent_of_rotation; float calibration_factor; - std::string rotation_radius ; + std::string rotation_radius; std::vector lower_en_window_thres; std::vector upper_en_window_thres; @@ -74,161 +89,181 @@ class SPECTDICOMData std::vector pixel_sizes; }; -stir::Succeeded GetDICOMTagInfo(const gdcm::File &file, const gdcm::Tag tag, std::string &dst, const int sequence_idx){ +stir::Succeeded +GetDICOMTagInfo(const gdcm::File& file, const gdcm::Tag tag, std::string& dst, const int sequence_idx) +{ - //Extracts information for a given DICOM tag from a gdcm dataset. - //Tag contents are returned as a string in dst variable. + // Extracts information for a given DICOM tag from a gdcm dataset. + // Tag contents are returned as a string in dst variable. - //Tries to read the element associated with the tag. If the read fails, the - //DataElement should have a ByteValue of NULL. + // Tries to read the element associated with the tag. If the read fails, the + // DataElement should have a ByteValue of NULL. - try { - const gdcm::DataSet &ds = file.GetDataSet(); + try + { + const gdcm::DataSet& ds = file.GetDataSet(); - gdcm::StringFilter sf; - sf.SetFile(file); + gdcm::StringFilter sf; + sf.SetFile(file); - std::stringstream inStream; - inStream.exceptions(std::ios::badbit); + std::stringstream inStream; + inStream.exceptions(std::ios::badbit); - // First try and see if this is a standard tag. - gdcm::DataElement element = ds.GetDataElement(tag); + // First try and see if this is a standard tag. + gdcm::DataElement element = ds.GetDataElement(tag); - if (element.GetByteValue() != NULL) { - dst = sf.ToString(tag); - return stir::Succeeded::yes; - } + if (element.GetByteValue() != NULL) + { + dst = sf.ToString(tag); + return stir::Succeeded::yes; + } - // Try: RotationInformationSequence (0054,0052) - // DetectorInformationSequence (0054,0022) - // EnergyWindowInformationSequence (0054,0012) - std::vector seqs = { gdcm::Tag(0x0054,0x0052), gdcm::Tag(0x0054,0x0022), gdcm::Tag(0x0054,0x0012)}; + // Try: RotationInformationSequence (0054,0052) + // DetectorInformationSequence (0054,0022) + // EnergyWindowInformationSequence (0054,0012) + std::vector seqs = { gdcm::Tag(0x0054, 0x0052), gdcm::Tag(0x0054, 0x0022), gdcm::Tag(0x0054, 0x0012) }; - for (const auto& t : seqs) { - try + for (const auto& t : seqs) { - const gdcm::DataElement &de = file.GetDataSet().GetDataElement(t); - const gdcm::SequenceOfItems *sqi = de.GetValueAsSQ(); - const gdcm::Item &item = sqi->GetItem(sequence_idx); + try + { + const gdcm::DataElement& de = file.GetDataSet().GetDataElement(t); + const gdcm::SequenceOfItems* sqi = de.GetValueAsSQ(); + const gdcm::Item& item = sqi->GetItem(sequence_idx); - element = item.GetDataElement(tag); + element = item.GetDataElement(tag); - if (element.GetByteValue() != NULL) { - dst = sf.ToString(element); - return stir::Succeeded::yes; - } - } - catch (...) - { - // ignore error and try next sequence + if (element.GetByteValue() != NULL) + { + dst = sf.ToString(element); + return stir::Succeeded::yes; + } + } + catch (...) + { + // ignore error and try next sequence + } } } - - } catch (...){ - stir::error(boost::format("GetDICOMTagInfo: cannot read tag %1% sequence index %2%") % tag % sequence_idx); - return stir::Succeeded::no; - } + catch (...) + { + stir::error(boost::format("GetDICOMTagInfo: cannot read tag %1% sequence index %2%") % tag % sequence_idx); + return stir::Succeeded::no; + } return stir::Succeeded::no; } -stir::Succeeded GetEnergyWindowInfo(const gdcm::File &file, const EnergyWindowInfo request, std::string &dst, const int sequence_idx){ +stir::Succeeded +GetEnergyWindowInfo(const gdcm::File& file, const EnergyWindowInfo request, std::string& dst, const int sequence_idx) +{ - if (request == EnergyWindowInfo::WindowName){ - return GetDICOMTagInfo(file, gdcm::Tag(0x0054,0x0018), dst, sequence_idx); - } + if (request == EnergyWindowInfo::WindowName) + { + return GetDICOMTagInfo(file, gdcm::Tag(0x0054, 0x0018), dst, sequence_idx); + } - try { - const gdcm::Tag energy_window_info_seq = gdcm::Tag(0x0054,0x0012); - const gdcm::Tag energy_window_range_seq = gdcm::Tag(0x0054,0x0013); + try + { + const gdcm::Tag energy_window_info_seq = gdcm::Tag(0x0054, 0x0012); + const gdcm::Tag energy_window_range_seq = gdcm::Tag(0x0054, 0x0013); - const gdcm::Tag lower_energy_window_tag = gdcm::Tag(0x0054,0x0014); - const gdcm::Tag upper_energy_window_tag = gdcm::Tag(0x0054,0x0015); + const gdcm::Tag lower_energy_window_tag = gdcm::Tag(0x0054, 0x0014); + const gdcm::Tag upper_energy_window_tag = gdcm::Tag(0x0054, 0x0015); - //Get Energy Window Info Sequence - const gdcm::DataElement &de = file.GetDataSet().GetDataElement(energy_window_info_seq); - const gdcm::SequenceOfItems *sqi = de.GetValueAsSQ(); - const gdcm::Item &item = sqi->GetItem(sequence_idx); + // Get Energy Window Info Sequence + const gdcm::DataElement& de = file.GetDataSet().GetDataElement(energy_window_info_seq); + const gdcm::SequenceOfItems* sqi = de.GetValueAsSQ(); + const gdcm::Item& item = sqi->GetItem(sequence_idx); - //Get Energy Window Range Sequence - const gdcm::DataElement &element = item.GetDataElement(energy_window_range_seq); - const gdcm::SequenceOfItems *sqi2 = element.GetValueAsSQ(); - if (sqi2->GetNumberOfItems() > 1) - stir::warning("Energy window sequence contains more than 1 window. Ignoring all later ones"); - const gdcm::Item &item2 = sqi2->GetItem(1); + // Get Energy Window Range Sequence + const gdcm::DataElement& element = item.GetDataElement(energy_window_range_seq); + const gdcm::SequenceOfItems* sqi2 = element.GetValueAsSQ(); + if (sqi2->GetNumberOfItems() > 1) + stir::warning("Energy window sequence contains more than 1 window. Ignoring all later ones"); + const gdcm::Item& item2 = sqi2->GetItem(1); - //std::cout << item2 << std::endl; + // std::cout << item2 << std::endl; - gdcm::DataElement window_element; + gdcm::DataElement window_element; - if (request == EnergyWindowInfo::LowerThreshold) - window_element = item2.GetDataElement(lower_energy_window_tag); - else - window_element = item2.GetDataElement(upper_energy_window_tag); + if (request == EnergyWindowInfo::LowerThreshold) + window_element = item2.GetDataElement(lower_energy_window_tag); + else + window_element = item2.GetDataElement(upper_energy_window_tag); - if (window_element.GetByteValue() != NULL) { - gdcm::StringFilter sf; - sf.SetFile(file); - dst = sf.ToString(window_element); - return stir::Succeeded::yes; + if (window_element.GetByteValue() != NULL) + { + gdcm::StringFilter sf; + sf.SetFile(file); + dst = sf.ToString(window_element); + return stir::Succeeded::yes; + } + } + catch (...) + { + stir::warning("GetEnergyWindowInfo: cannot read energy info"); + return stir::Succeeded::no; } - - } catch (...){ - stir::warning("GetEnergyWindowInfo: cannot read energy info"); - return stir::Succeeded::no; - } return stir::Succeeded::no; } -stir::Succeeded GetRadionuclideInfo(const gdcm::File &file, const RadionuclideInfo request, std::string &dst, const int sequence_idx){ +stir::Succeeded +GetRadionuclideInfo(const gdcm::File& file, const RadionuclideInfo request, std::string& dst, const int sequence_idx) +{ -// if (request == RadionuclideInfo::CodeMeaning){ -// return GetDICOMTagInfo(file, gdcm::Tag(0x0008,0x0018), dst); -// } + // if (request == RadionuclideInfo::CodeMeaning){ + // return GetDICOMTagInfo(file, gdcm::Tag(0x0008,0x0018), dst); + // } - try { - const gdcm::Tag radiopharm_info_seq_tag = gdcm::Tag(0x0054,0x0016); - const gdcm::Tag radionuclide_code_seq_tag = gdcm::Tag(0x0054,0x0300); + try + { + const gdcm::Tag radiopharm_info_seq_tag = gdcm::Tag(0x0054, 0x0016); + const gdcm::Tag radionuclide_code_seq_tag = gdcm::Tag(0x0054, 0x0300); - const gdcm::Tag radionuclide_codemeaning_tag = gdcm::Tag(0x0008,0x0104); -// const gdcm::Tag upper_radionuclide_tag = gdcm::Tag(0x0054,0x0015); + const gdcm::Tag radionuclide_codemeaning_tag = gdcm::Tag(0x0008, 0x0104); + // const gdcm::Tag upper_radionuclide_tag = gdcm::Tag(0x0054,0x0015); - //Get Radiopharmaceutical Info Sequence - const gdcm::DataElement &de = file.GetDataSet().GetDataElement(radiopharm_info_seq_tag); - const gdcm::SequenceOfItems *sqi = de.GetValueAsSQ(); - const gdcm::Item &item = sqi->GetItem(sequence_idx); + // Get Radiopharmaceutical Info Sequence + const gdcm::DataElement& de = file.GetDataSet().GetDataElement(radiopharm_info_seq_tag); + const gdcm::SequenceOfItems* sqi = de.GetValueAsSQ(); + const gdcm::Item& item = sqi->GetItem(sequence_idx); + // Get Radiopnuclide Code Sequence + gdcm::DataElement nuclide_element; + const gdcm::DataElement& element = item.GetDataElement(radionuclide_code_seq_tag); + if (element.GetVL() > 0) + { + const gdcm::SequenceOfItems* sqi2 = element.GetValueAsSQ(); + const gdcm::Item& item2 = sqi2->GetItem(sequence_idx); + // std::cout<< "num items"<< sqi2->GetNumberOfItems(); + // std::cout << item2 << std::endl; - //Get Radiopnuclide Code Sequence - gdcm::DataElement nuclide_element; - const gdcm::DataElement &element = item.GetDataElement(radionuclide_code_seq_tag); - if(element.GetVL()>0){ - const gdcm::SequenceOfItems *sqi2 = element.GetValueAsSQ(); - const gdcm::Item &item2 = sqi2->GetItem(sequence_idx); - //std::cout<< "num items"<< sqi2->GetNumberOfItems(); - //std::cout << item2 << std::endl; + // gdcm::DataElement nuclide_element; + nuclide_element = item2.GetDataElement(radionuclide_codemeaning_tag); + } -// gdcm::DataElement nuclide_element; - nuclide_element = item2.GetDataElement(radionuclide_codemeaning_tag); + if (nuclide_element.GetByteValue() != NULL) + { + gdcm::StringFilter sf; + sf.SetFile(file); + dst = sf.ToString(nuclide_element); + return stir::Succeeded::yes; + } } - - if (nuclide_element.GetByteValue() != NULL) { - gdcm::StringFilter sf; - sf.SetFile(file); - dst = sf.ToString(nuclide_element); - return stir::Succeeded::yes; + catch (...) + { + stir::warning("GetRadionuclideInfo: cannot read radiopharmaceutical info"); + dst = ""; + return stir::Succeeded::no; } - } catch (...){ - stir::warning("GetRadionuclideInfo: cannot read radiopharmaceutical info"); - dst = ""; - return stir::Succeeded::no; - } return stir::Succeeded::no; } -stir::Succeeded SPECTDICOMData::open_dicom_file(bool is_planar) +stir::Succeeded +SPECTDICOMData::open_dicom_file(bool is_planar) { stir::info(boost::format("SPECTDICOMData: opening file %1%") % dicom_filename); @@ -236,24 +271,29 @@ stir::Succeeded SPECTDICOMData::open_dicom_file(bool is_planar) std::unique_ptr DICOM_reader(new gdcm::Reader); DICOM_reader->SetFileName(dicom_filename.c_str()); - try { - if (!DICOM_reader->Read()) { - stir::error(boost::format("SPECTDICOMData: cannot read file %1%") % dicom_filename); - //return stir::Succeeded::no; + try + { + if (!DICOM_reader->Read()) + { + stir::error(boost::format("SPECTDICOMData: cannot read file %1%") % dicom_filename); + // return stir::Succeeded::no; + } + } + catch (const std::string& e) + { + std::cerr << e << std::endl; + return stir::Succeeded::no; } - } catch (const std::string &e){ - std::cerr << e << std::endl; - return stir::Succeeded::no; - } - const gdcm::File &file = DICOM_reader->GetFile(); + const gdcm::File& file = DICOM_reader->GetFile(); std::cout << std::endl; std::string patient_name; - if (GetDICOMTagInfo(file, gdcm::Tag(0x0010,0x0010), patient_name) == stir::Succeeded::yes){ - std::cout << "Patient name: " << patient_name << std::endl; - } + if (GetDICOMTagInfo(file, gdcm::Tag(0x0010, 0x0010), patient_name) == stir::Succeeded::yes) + { + std::cout << "Patient name: " << patient_name << std::endl; + } std::string no_of_proj_as_str; std::string start_angle_as_string; std::string angular_step_as_string; @@ -267,77 +307,87 @@ stir::Succeeded SPECTDICOMData::open_dicom_file(bool is_planar) std::string lower_window_as_string; std::string upper_window_as_string; - { std::string str; - if (GetDICOMTagInfo(file, gdcm::Tag(0x0028,0x0008), str) == stir::Succeeded::yes){ - num_frames = std::stoi(str); - std::cout << "Number of frames: " << num_frames << std::endl; - } + if (GetDICOMTagInfo(file, gdcm::Tag(0x0028, 0x0008), str) == stir::Succeeded::yes) + { + num_frames = std::stoi(str); + std::cout << "Number of frames: " << num_frames << std::endl; + } } - this->num_of_projections=1; - if(!is_planar){ - if (GetDICOMTagInfo(file, gdcm::Tag(0x0054,0x0053), no_of_proj_as_str) == stir::Succeeded::yes){ - num_of_projections = std::stoi(no_of_proj_as_str); - std::cout << "Number of projections: " << num_of_projections << std::endl; - } + this->num_of_projections = 1; + if (!is_planar) + { + if (GetDICOMTagInfo(file, gdcm::Tag(0x0054, 0x0053), no_of_proj_as_str) == stir::Succeeded::yes) + { + num_of_projections = std::stoi(no_of_proj_as_str); + std::cout << "Number of projections: " << num_of_projections << std::endl; + } - if (GetDICOMTagInfo(file, gdcm::Tag(0x0018,0x1140), direction_of_rotation) == stir::Succeeded::yes){ + if (GetDICOMTagInfo(file, gdcm::Tag(0x0018, 0x1140), direction_of_rotation) == stir::Succeeded::yes) + { - if (direction_of_rotation=="CC") - direction_of_rotation="CCW"; + if (direction_of_rotation == "CC") + direction_of_rotation = "CCW"; - std::cout << "Direction of rotation: " << direction_of_rotation << std::endl; - } + std::cout << "Direction of rotation: " << direction_of_rotation << std::endl; + } - if (GetDICOMTagInfo(file, gdcm::Tag(0x0054,0x0200), start_angle_as_string) == stir::Succeeded::yes){ - start_angle = std::stof(start_angle_as_string); - std::cout << "Starting angle: " << std::fixed << std::setprecision(6) << start_angle << std::endl; - } + if (GetDICOMTagInfo(file, gdcm::Tag(0x0054, 0x0200), start_angle_as_string) == stir::Succeeded::yes) + { + start_angle = std::stof(start_angle_as_string); + std::cout << "Starting angle: " << std::fixed << std::setprecision(6) << start_angle << std::endl; + } - if (GetDICOMTagInfo(file, gdcm::Tag(0x0054,0x1322), calib_factor_as_string) == stir::Succeeded::yes){ - calibration_factor = std::stof(calib_factor_as_string); - std::cout << "calibration factor: " << std::fixed << std::setprecision(6) << calibration_factor << std::endl; - } + if (GetDICOMTagInfo(file, gdcm::Tag(0x0054, 0x1322), calib_factor_as_string) == stir::Succeeded::yes) + { + calibration_factor = std::stof(calib_factor_as_string); + std::cout << "calibration factor: " << std::fixed << std::setprecision(6) << calibration_factor << std::endl; + } else - calibration_factor=-1; + calibration_factor = -1; - if (GetRadionuclideInfo(file, RadionuclideInfo::CodeMeaning , isotope_name) == stir::Succeeded::yes){ - std::cout << "Isotope name: " << isotope_name << std::endl; - } + if (GetRadionuclideInfo(file, RadionuclideInfo::CodeMeaning, isotope_name) == stir::Succeeded::yes) + { + std::cout << "Isotope name: " << isotope_name << std::endl; + } - if (GetDICOMTagInfo(file, gdcm::Tag(0x0018,0x1144), angular_step_as_string) == stir::Succeeded::yes){ - angular_step = std::stof(angular_step_as_string); - std::cout << "Angular step: " << std::fixed << std::setprecision(6) << angular_step << std::endl; - } + if (GetDICOMTagInfo(file, gdcm::Tag(0x0018, 0x1144), angular_step_as_string) == stir::Succeeded::yes) + { + angular_step = std::stof(angular_step_as_string); + std::cout << "Angular step: " << std::fixed << std::setprecision(6) << angular_step << std::endl; + } - if (GetDICOMTagInfo(file, gdcm::Tag(0x0018,0x1143), extent_of_rotation_as_string) == stir::Succeeded::yes){ - extent_of_rotation = std::stoi(extent_of_rotation_as_string); - std::cout << "Rotation extent: " << extent_of_rotation << std::endl; - } + if (GetDICOMTagInfo(file, gdcm::Tag(0x0018, 0x1143), extent_of_rotation_as_string) == stir::Succeeded::yes) + { + extent_of_rotation = std::stoi(extent_of_rotation_as_string); + std::cout << "Rotation extent: " << extent_of_rotation << std::endl; + } - if (GetDICOMTagInfo(file, gdcm::Tag(0x0018,0x1142), radius_as_string) == stir::Succeeded::yes){ - rotation_radius =(radius_as_string); - char slash='\\'; - char comma=','; - std::cout << "Radius: " << radius_as_string <<" " <rotation_radius <<"}"<< std::endl; - std::cout << "orbit := non-circular" << std::endl; - }else{ + if (is_planar) + { ss << "orbit := circular" << std::endl; - ss << "radius := " << this->rotation_radius <<""<< std::endl; - } - } + ss << "radius := " << 0 << std::endl; + } + else + { + if (this->rotation_radius.find(",") != std::string::npos) + { + ss << "orbit := non-circular" << std::endl; + ss << "radii := {" << this->rotation_radius << "}" << std::endl; + std::cout << "orbit := non-circular" << std::endl; + } + else + { + ss << "orbit := circular" << std::endl; + ss << "radius := " << this->rotation_radius << "" << std::endl; + } + } ss << std::endl; ss << "!END OF INTERFILE :="; @@ -468,25 +533,31 @@ stir::Succeeded SPECTDICOMData::get_interfile_header(std::string &output_header, return stir::Succeeded::yes; } -stir::Succeeded SPECTDICOMData::get_proj_data(const std::string &output_file) const{ +stir::Succeeded +SPECTDICOMData::get_proj_data(const std::string& output_file) const +{ std::unique_ptr DICOM_reader(new gdcm::Reader); DICOM_reader->SetFileName(dicom_filename.c_str()); - try { - if (!DICOM_reader->Read()) { - stir::error(boost::format("SPECTDICOMData: cannot read file %1%") % dicom_filename); - //return stir::Succeeded::no; + try + { + if (!DICOM_reader->Read()) + { + stir::error(boost::format("SPECTDICOMData: cannot read file %1%") % dicom_filename); + // return stir::Succeeded::no; + } + } + catch (const std::string& e) + { + std::cerr << e << std::endl; + return stir::Succeeded::no; } - } catch (const std::string &e){ - std::cerr << e << std::endl; - return stir::Succeeded::no; - } - const gdcm::File &file = DICOM_reader->GetFile(); + const gdcm::File& file = DICOM_reader->GetFile(); - const gdcm::DataElement &de = file.GetDataSet().GetDataElement(gdcm::Tag(0x7fe0,0x0010)); - const gdcm::ByteValue *bv = de.GetByteValue(); + const gdcm::DataElement& de = file.GetDataSet().GetDataElement(gdcm::Tag(0x7fe0, 0x0010)); + const gdcm::ByteValue* bv = de.GetByteValue(); /* std::string tmpFile = "tmp.s"; @@ -499,20 +570,21 @@ stir::Succeeded SPECTDICOMData::get_proj_data(const std::string &output_file) co bv->WriteBuffer(outfile); outfile.close();*/ - uint64_t len0 = (uint64_t)bv->GetLength()/2; + uint64_t len0 = (uint64_t)bv->GetLength() / 2; std::cout << "Number of data points = " << len0 << std::endl; std::vector pixel_data_as_float; - uint16_t *ptr = (uint16_t*)bv->GetPointer(); + uint16_t* ptr = (uint16_t*)bv->GetPointer(); uint64_t ct = 0; - while (ct < len0){ - uint16_t val = *ptr; - pixel_data_as_float.push_back((float)val); - ptr++; - ct++; - } + while (ct < len0) + { + uint16_t val = *ptr; + pixel_data_as_float.push_back((float)val); + ptr++; + ct++; + } std::ofstream final_out(output_file.c_str(), std::ios::out | std::ofstream::binary); final_out.write(reinterpret_cast(&pixel_data_as_float[0]), pixel_data_as_float.size() * sizeof(float)); @@ -540,9 +612,10 @@ convert_to_filename(const std::string& s) int main(int argc, char* argv[]) - { +{ - if ( argc!=4) { + if (argc != 4) + { std::cerr << "Usage: " << argv[0] << " sinogram(dcm)> is_planar?\n"; exit(EXIT_FAILURE); } @@ -550,17 +623,21 @@ main(int argc, char* argv[]) SPECTDICOMData spect(argv[2]); const std::string output_prefix(argv[1]); - spect.is_planar=atoi(argv[3]); + spect.is_planar = atoi(argv[3]); - try{ - if (spect.open_dicom_file(spect.is_planar) == stir::Succeeded::no){ - std::cerr << "Failed to read!" << std::endl; + try + { + if (spect.open_dicom_file(spect.is_planar) == stir::Succeeded::no) + { + std::cerr << "Failed to read!" << std::endl; + return EXIT_FAILURE; + } + } + catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; return EXIT_FAILURE; } - } catch(const std::exception& e){ - std::cerr << e.what() << std::endl; - return EXIT_FAILURE; - } std::cout << "Read successfully!" << std::endl; @@ -571,7 +648,7 @@ main(int argc, char* argv[]) const std::string data_filename(output_prefix + ".s"); stir::Succeeded s = spect.get_proj_data(data_filename); - for (int w=0; w1 && strcmp(argv[1], "-t")==0) - { - num_tangential_poss_to_trim = atoi(argv[2]); - argc -= 2; argv += 2; - } + if (argc > 1 && strcmp(argv[1], "-t") == 0) + { + num_tangential_poss_to_trim = atoi(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, @@ -119,35 +121,38 @@ void classic_SSRB(int argc, char **argv) num_views_to_combine, num_tangential_poss_to_trim, do_norm, - max_segment_num_to_process - ); + 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) +int +main(int argc, char** argv) { - if (argc > 7 || argc < 3 ) - { - print_usage_and_exit(argv[0]); - } - - if (strcmp(argv[1], "--template")==0) - { - template_based_SSRB(argc, argv); - } else { - classic_SSRB(argc, argv); - } + if (argc > 7 || argc < 3) + { + print_usage_and_exit(argv[0]); + } + + if (strcmp(argv[1], "--template") == 0) + { + template_based_SSRB(argc, argv); + } + else + { + classic_SSRB(argc, argv); + } return EXIT_SUCCESS; } diff --git a/src/utilities/UPENN/conv_UPENN_projdata_to_STIR.cxx b/src/utilities/UPENN/conv_UPENN_projdata_to_STIR.cxx old mode 100755 new mode 100644 index 11b923a58..eb7e10b13 --- a/src/utilities/UPENN/conv_UPENN_projdata_to_STIR.cxx +++ b/src/utilities/UPENN/conv_UPENN_projdata_to_STIR.cxx @@ -41,275 +41,277 @@ #include "stir/ViewSegmentNumbers.h" #include "stir/LORCoordinates.h" - #include "liblor.h" #include "libimagio++.h" static void -print_usage_and_exit(const char * const prog_name) +print_usage_and_exit(const char* const prog_name) { - std::cerr << "\nUsage:\n" << prog_name << "\\\n" - << "\t--output \\\n" - << "\t--template \\\n" - << "\t--input \\\n" - << "\t--add-gaps\\\n" - << "\t--template_with_gaps\\\n" - << "\t--inv\\\n" - << "\t--up_thresshold \\\n" - << "END:=\n"; - - exit(EXIT_FAILURE); + std::cerr << "\nUsage:\n" + << prog_name << "\\\n" + << "\t--output \\\n" + << "\t--template \\\n" + << "\t--input \\\n" + << "\t--add-gaps\\\n" + << "\t--template_with_gaps\\\n" + << "\t--inv\\\n" + << "\t--up_thresshold \\\n" + << "END:=\n"; + + exit(EXIT_FAILURE); } USING_NAMESPACE_STIR //! Regurn true if the ring is a gap (between 0 and 16) -bool is_gap(int r) +bool +is_gap(int r) { - int d = r % 56; - if (d >= 0 && d < 16 ) - return true; - return false; + int d = r % 56; + if (d >= 0 && d < 16) + return true; + return false; } -int main(int argc, const char *argv[]) +int +main(int argc, const char* argv[]) { - const char * const prog_name = argv[0]; - - std::string output_filename; - std::string input_filename; - std::string template_filename; - std::string gtemplate_filename; - bool addgaps = false; - bool invert = false; - bool max = false; - bool up_thresshold = false; - float up_thresshold_value = 13.f; - - // option processing - while (argc>1 && argv[1][1] == '-') + const char* const prog_name = argv[0]; + + std::string output_filename; + std::string input_filename; + std::string template_filename; + std::string gtemplate_filename; + bool addgaps = false; + bool invert = false; + bool max = false; + bool up_thresshold = false; + float up_thresshold_value = 13.f; + + // option processing + while (argc > 1 && argv[1][1] == '-') { - if (strcmp(argv[1], "--output")==0) + if (strcmp(argv[1], "--output") == 0) { - output_filename = (argv[2]); - argc-=2; argv +=2; + output_filename = (argv[2]); + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--template")==0) + else if (strcmp(argv[1], "--template") == 0) { - template_filename = argv[2]; - argc-=2; argv +=2; + template_filename = argv[2]; + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--input") ==0) + else if (strcmp(argv[1], "--input") == 0) { - input_filename = argv[2]; - argc-=2; argv +=2; + input_filename = argv[2]; + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--template_with_gaps") ==0) + else if (strcmp(argv[1], "--template_with_gaps") == 0) { - gtemplate_filename = argv[2]; - argc-=2; argv +=2; + gtemplate_filename = argv[2]; + argc -= 2; + argv += 2; } - else if (strcmp(argv[1], "--add-gaps") ==0) + else if (strcmp(argv[1], "--add-gaps") == 0) { - addgaps = true; - argc-=1; argv +=1; + addgaps = true; + argc -= 1; + argv += 1; } - else if (strcmp(argv[1], "--inv") ==0) + else if (strcmp(argv[1], "--inv") == 0) { - invert = true; - argc-=1; argv +=1; + invert = true; + argc -= 1; + argv += 1; } - else if (strcmp(argv[1], "--max") ==0) + else if (strcmp(argv[1], "--max") == 0) { - max = true; - argc-=1; argv +=1; + max = true; + argc -= 1; + argv += 1; } - else if (strcmp(argv[1], "--up_thresshold") ==0) + else if (strcmp(argv[1], "--up_thresshold") == 0) { - up_thresshold = true; - up_thresshold_value = atof(argv[2]); - argc-=2; argv +=2; + up_thresshold = true; + up_thresshold_value = atof(argv[2]); + argc -= 2; + argv += 2; } - else + else { - std::cerr << "\nUnknown option: " << argv[1]; - print_usage_and_exit(prog_name); + std::cerr << "\nUnknown option: " << argv[1]; + print_usage_and_exit(prog_name); } } - if (argc > 1) + if (argc > 1) { - std::cerr << "Command line should contain only options\n"; - print_usage_and_exit(prog_name); + std::cerr << "Command line should contain only options\n"; + print_usage_and_exit(prog_name); } - const stir::shared_ptr template_projdata_sptr = - ProjData::read_from_file(template_filename); - - stir::shared_ptr gtemplate_projdata_sptr; + const stir::shared_ptr template_projdata_sptr = ProjData::read_from_file(template_filename); - if(addgaps) - gtemplate_projdata_sptr = ProjData::read_from_file(gtemplate_filename); + stir::shared_ptr gtemplate_projdata_sptr; - shared_ptr output_projdata_sptr; + if (addgaps) + gtemplate_projdata_sptr = ProjData::read_from_file(gtemplate_filename); - if(addgaps) - output_projdata_sptr.reset(new ProjDataInterfile (gtemplate_projdata_sptr->get_exam_info_sptr(), - gtemplate_projdata_sptr->get_proj_data_info_sptr(), output_filename)); - else - output_projdata_sptr.reset(new ProjDataInterfile (template_projdata_sptr->get_exam_info_sptr(), - template_projdata_sptr->get_proj_data_info_sptr(), output_filename)); + shared_ptr output_projdata_sptr; + if (addgaps) + output_projdata_sptr.reset(new ProjDataInterfile( + gtemplate_projdata_sptr->get_exam_info_sptr(), gtemplate_projdata_sptr->get_proj_data_info_sptr(), output_filename)); + else + output_projdata_sptr.reset(new ProjDataInterfile( + template_projdata_sptr->get_exam_info_sptr(), template_projdata_sptr->get_proj_data_info_sptr(), output_filename)); - const shared_ptr out_projdata_info_sptr = - dynamic_pointer_cast(output_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone()); + const shared_ptr out_projdata_info_sptr + = dynamic_pointer_cast( + output_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone()); - long int fillvalue = 0; - if (max) - fillvalue = 1000000000; + long int fillvalue = 0; + if (max) + fillvalue = 1000000000; #ifdef STIR_OPENMP -#pragma omp parallel for schedule(dynamic) +# pragma omp parallel for schedule(dynamic) #endif - for (int iseg = out_projdata_info_sptr->get_min_segment_num(); - iseg <= out_projdata_info_sptr->get_max_segment_num(); ++iseg) + for (int iseg = out_projdata_info_sptr->get_min_segment_num(); iseg <= out_projdata_info_sptr->get_max_segment_num(); ++iseg) { - SegmentByView d = out_projdata_info_sptr->get_empty_segment_by_view(iseg); - d.fill(fillvalue); - output_projdata_sptr->set_segment(d); + SegmentByView d = out_projdata_info_sptr->get_empty_segment_by_view(iseg); + d.fill(fillvalue); + output_projdata_sptr->set_segment(d); } - InputImagioFile inputSinoFile; - if(!inputSinoFile.open(input_filename)) + InputImagioFile inputSinoFile; + if (!inputSinoFile.open(input_filename)) { - std::cerr<<"Cannot read input file: "<< input_filename <<" Abort."< tmp_slice(sliceSize); + sinoMap.getCrystalZsForSinoSlice(iSlice, &_dr1, &_dr2); + std::vector tmp_slice(sliceSize); #ifdef STIR_OPENMP -#pragma omp critical(LISTMODEIO) +# pragma omp critical(LISTMODEIO) #endif + { + if (!inputSinoFile.readSlice(1, 1, iSlice, &tmp_slice[0])) + ; { - if(!inputSinoFile.readSlice(1, 1, iSlice, &tmp_slice[0])); - { - // std::cerr <<"Cannot read input data. Abort."<get_segment_axial_pos_num_for_ring_pair(cur_seg, cur_axial, - dr1, dr2); - std::cout << cur_seg << std::endl; + int cur_seg, cur_axial; + out_projdata_info_sptr->get_segment_axial_pos_num_for_ring_pair(cur_seg, cur_axial, dr1, dr2); + std::cout << cur_seg << std::endl; - Sinogram cur_sino(output_projdata_sptr->get_empty_sinogram(cur_axial, cur_seg)); - cur_sino.fill(fillvalue); + Sinogram cur_sino(output_projdata_sptr->get_empty_sinogram(cur_axial, cur_seg)); + cur_sino.fill(fillvalue); - for(int i_phi = 0; i_phi <= template_projdata_sptr->get_max_view_num(); ++i_phi) + for (int i_phi = 0; i_phi <= template_projdata_sptr->get_max_view_num(); ++i_phi) { - for(int i_tang = 0; - i_tang < template_projdata_sptr->get_num_tangential_poss(); - ++i_tang) + for (int i_tang = 0; i_tang < template_projdata_sptr->get_num_tangential_poss(); ++i_tang) { - int d1, d2; - int _d1, _d2; + int d1, d2; + int _d1, _d2; - sinoMap.getCrystalXsForSinoPhiRadMash(i_phi, i_tang, 0, &_d1, &_d2); + sinoMap.getCrystalXsForSinoPhiRadMash(i_phi, i_tang, 0, &_d1, &_d2); - if(addgaps) + if (addgaps) { - d1 = _d1 + static_cast(_d1 * 0.03125f) + 1; // add gap - d2 = _d2 + static_cast(_d2 * 0.03125f) + 1; // add gap + d1 = _d1 + static_cast(_d1 * 0.03125f) + 1; // add gap + d2 = _d2 + static_cast(_d2 * 0.03125f) + 1; // add gap } - else + else { - d1 = _d1; - d2 = _d2; + d1 = _d1; + d2 = _d2; } - Bin tmp_bin; - const DetectionPositionPair<> det_pos_pair(DetectionPosition<>(d1, dr1), DetectionPosition<>(d2, dr2)); - out_projdata_info_sptr->get_bin_for_det_pos_pair(tmp_bin, det_pos_pair); + Bin tmp_bin; + const DetectionPositionPair<> det_pos_pair(DetectionPosition<>(d1, dr1), DetectionPosition<>(d2, dr2)); + out_projdata_info_sptr->get_bin_for_det_pos_pair(tmp_bin, det_pos_pair); - const int index = i_phi * mh_isino.numray + i_tang; - float val = tmp_slice[index]; + const int index = i_phi * mh_isino.numray + i_tang; + float val = tmp_slice[index]; - if(up_thresshold) + if (up_thresshold) { - if (val > up_thresshold_value) - val = up_thresshold_value; + if (val > up_thresshold_value) + val = up_thresshold_value; } - - if(invert) //for attenuation correction + if (invert) // for attenuation correction { - if (val != 0) + if (val != 0) { - cur_sino[tmp_bin.view_num()][tmp_bin.tangential_pos_num()] = 1.f/val; + cur_sino[tmp_bin.view_num()][tmp_bin.tangential_pos_num()] = 1.f / val; } - else - cur_sino[tmp_bin.view_num()][tmp_bin.tangential_pos_num()] = 0.f; + else + cur_sino[tmp_bin.view_num()][tmp_bin.tangential_pos_num()] = 0.f; } - else + else { - if (val != 0) + if (val != 0) { - cur_sino[tmp_bin.view_num()][tmp_bin.tangential_pos_num()] = val; + cur_sino[tmp_bin.view_num()][tmp_bin.tangential_pos_num()] = val; } - else - cur_sino[tmp_bin.view_num()][tmp_bin.tangential_pos_num()] = fillvalue; + else + cur_sino[tmp_bin.view_num()][tmp_bin.tangential_pos_num()] = fillvalue; } - } } - output_projdata_sptr->set_sinogram(cur_sino); + output_projdata_sptr->set_sinogram(cur_sino); } - return EXIT_SUCCESS; + return EXIT_SUCCESS; } diff --git a/src/utilities/abs_image.cxx b/src/utilities/abs_image.cxx index 2280e23f6..7020bfafe 100644 --- a/src/utilities/abs_image.cxx +++ b/src/utilities/abs_image.cxx @@ -11,7 +11,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 @@ -20,7 +20,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. */ @@ -33,111 +33,108 @@ #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) + 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; - } + { + 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) + if (output_filename == 0 || input_filename == 0) { std::cerr << usage; return EXIT_FAILURE; } - if(do_parametric)// A better way will be to template it... + if (do_parametric) // A better way will be to template it... { - shared_ptr - input_image_sptr(ParametricVoxelsOnCartesianGrid::read_from_file(input_filename)); + 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... + 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 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; + 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> 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 939aed3dc..b43a12e07 100644 --- a/src/utilities/apply_normfactors.cxx +++ b/src/utilities/apply_normfactors.cxx @@ -33,49 +33,44 @@ #include #include - USING_NAMESPACE_STIR -int main(int argc, char **argv) +int +main(int argc, char** argv) { - if (argc<7 || argc>10) + if (argc < 7 || argc > 10) { - std::cerr << "Usage: " << argv[0] - << " out_filename in_norm_filename_prefix measured_data multiply_or_divide iter_num eff_iter_num [do_eff [ do_geo [ do_block]]]\n" - << "multiply_or_divide is 1 (multiply) or 0 (divide)\n" - << "do_eff, do_geo, do_block are 1 or 0 and all default to 1\n"; + std::cerr << "Usage: " << argv[0] + << " out_filename in_norm_filename_prefix measured_data multiply_or_divide iter_num eff_iter_num [do_eff [ " + "do_geo [ do_block]]]\n" + << "multiply_or_divide 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 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 multiply_or_divide = atoi(argv[4])!=0; + const bool multiply_or_divide = 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; @@ -86,69 +81,63 @@ 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_%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 + { + 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 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 + { + { + 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; - } - } + { + { + 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, multiply_or_divide); - if (do_geo) - apply_geo_norm(det_pair_data, norm_geo_data, multiply_or_divide); - if (do_block) - apply_block_norm(det_pair_data, norm_block_data, multiply_or_divide); - set_det_pair_data(*out_proj_data_ptr, - det_pair_data, - segment_num, - ax_pos_num); + make_det_pair_data(det_pair_data, *measured_data, segment_num, ax_pos_num); + if (do_eff) + apply_efficiencies(det_pair_data, efficiencies, multiply_or_divide); + if (do_geo) + apply_geo_norm(det_pair_data, norm_geo_data, multiply_or_divide); + if (do_block) + apply_block_norm(det_pair_data, norm_block_data, multiply_or_divide); + set_det_pair_data(*out_proj_data_ptr, det_pair_data, segment_num, ax_pos_num); } } diff --git a/src/utilities/apply_normfactors3D.cxx b/src/utilities/apply_normfactors3D.cxx index cd08b692e..a235aea2b 100644 --- a/src/utilities/apply_normfactors3D.cxx +++ b/src/utilities/apply_normfactors3D.cxx @@ -60,8 +60,8 @@ main(int argc, char** argv) const std::string in_filename_prefix = argv[2]; const std::string output_file_name = argv[1]; // const std::string program_name = argv[0]; - ProjDataInterfile out_proj_data(measured_data->get_exam_info_sptr(), measured_data->get_proj_data_info_sptr(), - output_file_name); + ProjDataInterfile out_proj_data( + measured_data->get_exam_info_sptr(), measured_data->get_proj_data_info_sptr(), output_file_name); BinNormalisationPETFromComponents norm; norm.allocate(measured_data->get_proj_data_info_sptr(), do_eff, do_geo, do_block, do_symmetry_per_block); diff --git a/src/utilities/attenuation_coefficients_to_projections.cxx b/src/utilities/attenuation_coefficients_to_projections.cxx index 2ad0bcab2..2b4115853 100644 --- a/src/utilities/attenuation_coefficients_to_projections.cxx +++ b/src/utilities/attenuation_coefficients_to_projections.cxx @@ -18,7 +18,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) @@ -28,7 +28,6 @@ \author Kris Thielemans */ - #include "stir/ProjData.h" #include "stir/ProjDataInterfile.h" #include "stir/Viewgram.h" @@ -39,75 +38,72 @@ USING_NAMESPACE_STIR -static void print_usage_and_exit() +static void +print_usage_and_exit() { - std::cerr<<"\nUsage:\nattenuation_coefficients_to_projections\n\t" - << " --AF|--ACF \n"; + 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)); + 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(); + 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; - } - } - - + 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 44b7d3499..23b48eeb4 100644 --- a/src/utilities/back_project.cxx +++ b/src/utilities/back_project.cxx @@ -45,55 +45,53 @@ #include #include -static void print_usage_and_exit() +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"; + 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) + 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.add_stop_key("END"); parser.parse(argv[4]); } else { - shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); - back_projector_sptr.reset(new BackProjectorByBinUsingProjMatrixByBin(PM)); + shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); + back_projector_sptr.reset(new BackProjectorByBinUsingProjMatrixByBin(PM)); } if (!back_projector_sptr) { @@ -102,8 +100,7 @@ main (int argc, char * argv[]) } 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); @@ -112,9 +109,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 e0fd030da..bc5c9fce5 100644 --- a/src/utilities/calculate_attenuation_coefficients.cxx +++ b/src/utilities/calculate_attenuation_coefficients.cxx @@ -18,12 +18,11 @@ \par Usage \verbatim calculate_attenuation_coefficients - [--PMRT --NOPMRT] --AF|--ACF [forwardprojector-parfile] - \endverbatim - --ACF calculates the attenuation correction factors, --AF calculates + [--PMRT --NOPMRT] --AF|--ACF + [forwardprojector-parfile] \endverbatim --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 option --NOPMRT forces forward projection using the (old) Ray Tracing @@ -75,112 +74,111 @@ using std::endl; using std::cerr; - START_NAMESPACE_STIR - -static void print_usage_and_exit() +static void +print_usage_and_exit() { - std::cerr<<"\nUsage: calculate_attenuation_coefficients [--PMRT --NOPMRT] --AF|--ACF [forwardprojector-parfile]\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) (ignored if parfile provided)\n" - <<"\t--NOPMRT uses the (old) Ray Tracing forward projector (ignored if parfile provided)\n" - <<"The input image has to give the attenuation (or mu) values at 511 keV, and be in units of cm^-1.\n\n" - <<"Example forward projector 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); + std::cerr << "\nUsage: calculate_attenuation_coefficients [--PMRT --NOPMRT] --AF|--ACF [forwardprojector-parfile]\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) (ignored if parfile provided)\n" + << "\t--NOPMRT uses the (old) Ray Tracing forward projector (ignored if parfile provided)\n" + << "The input image has to give the attenuation (or mu) values at 511 keV, and be in units of cm^-1.\n\n" + << "Example forward projector 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); } 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; + bool use_PMRT = true; - if (argc>1 && strcmp(argv[1],"--PMRT")==0) + if (argc > 1 && strcmp(argv[1], "--PMRT") == 0) { - use_PMRT=true; - --argc; ++argv; + use_PMRT = true; + --argc; + ++argv; } - if (!(argc==5 || argc==6)) + if (!(argc == 5 || argc == 6)) 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_sptr; - if (argc>=5) - { + 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 if (use_PMRT) - { - shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); + { + shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); forw_projector_sptr.reset(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); - } + } else - { - forw_projector_sptr.reset(new ForwardProjectorByBinUsingRayTracing()); - } + { + forw_projector_sptr.reset(new ForwardProjectorByBinUsingRayTracing()); + } cerr << "\n\nForward projector used:\n" << forw_projector_sptr->parameter_info(); if (template_proj_data_ptr->get_proj_data_info_sptr()->is_tof_data()) - { - info("The scanner template provided contains TOF information. The calculation of the attenuation coefficients will be non-TOF anyway."); - } + { + info("The scanner template provided contains TOF information. The calculation of the attenuation coefficients will be " + "non-TOF anyway."); + } 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_non_tof_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_sptr)); - - 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()) + shared_ptr normalisation_ptr( + new BinNormalisationFromAttenuationImage(atten_image_filename, forw_projector_sptr)); + + 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"); @@ -198,8 +196,7 @@ main (int argc, char * argv[]) else { normalisation_ptr->undo(*out_proj_data_ptr, symmetries_sptr); - } + } return EXIT_SUCCESS; } - diff --git a/src/utilities/compare_image.cxx b/src/utilities/compare_image.cxx index da522b693..11feca2d8 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. @@ -28,7 +28,7 @@ if the files are identical or not. See STIR/LICENSE.txt for details */ /* Modification History: - + KT 12/09/2001 added rim_truncation option */ @@ -45,115 +45,119 @@ using std::cerr; using std::cout; using std::endl; - - //********************** main - - USING_NAMESPACE_STIR - -int main(int argc, char *argv[]) +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); - } + 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]=='-') + 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; - } + 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); } + { + cerr << "Could not read first file\n"; + exit(EXIT_FAILURE); + } - shared_ptr< DiscretisedDensity<3,float> > - second_operand(read_from_file >(argv[1])); + 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); } + { + 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)) + 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; + warning("input images do not have the same characteristics.\n%s", explanation.c_str()); + return EXIT_FAILURE; } } - if (rim_truncation_image>=0) - { - truncate_rim(*first_operand, rim_truncation_image); - truncate_rim(*second_operand, rim_truncation_image); - } + 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) +void +update_comparison(SegmentByView& 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 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); + const float local_amplitude = fabs(reference_max) > fabs(reference_min) ? fabs(reference_max) : fabs(reference_min); - amplitude=local_amplitude>amplitude?local_amplitude:amplitude; + 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(); + 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_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]=='-') + 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; - } + 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); + 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"; - exit(EXIT_FAILURE); - } - - + 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) + if (argc == 4) { - first_sptr->reduce_segment_range(-max_segment, max_segment); - second_sptr->reduce_segment_range(-max_segment, max_segment); + 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; } + 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 timing_pos_num=first_operand->get_min_tof_pos_num(); - timing_pos_num<=first_operand->get_max_tof_pos_num(); + float max_pos_error = 0.F, max_neg_error = 0.F, amplitude = 0.F; + for (int timing_pos_num = first_operand->get_min_tof_pos_num(); timing_pos_num <= first_operand->get_max_tof_pos_num(); ++timing_pos_num) - for (int segment_num = -max_segment; segment_num <= max_segment ; segment_num++) + for (int segment_num = -max_segment; segment_num <= max_segment; segment_num++) { SegmentIndices s_idx(segment_num, timing_pos_num); - auto input1=first_operand->get_segment_by_view(s_idx); - const auto input2=second_operand->get_segment_by_view(s_idx); + auto input1 = first_operand->get_segment_by_view(s_idx); + const auto input2 = second_operand->get_segment_by_view(s_idx); - 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() +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; + 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[]) +main(int argc, char* argv[]) { - if (argc!=2) + 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 90f6cff74..b2843c657 --- a/src/utilities/construct_randoms_from_GEsingles.cxx +++ b/src/utilities/construct_randoms_from_GEsingles.cxx @@ -39,17 +39,17 @@ using std::string; USING_NAMESPACE_STIR -int main(int argc, char **argv) +int +main(int argc, char** argv) { - if (argc!=4 && argc!=3) + if (argc != 4 && argc != 3) { - cerr << "Usage: " << argv[0] - << " out_filename GE_RDF_filename [template_projdata]\n" + 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 string input_filename = argv[2]; const string output_file_name = argv[1]; const string program_name = argv[0]; @@ -58,7 +58,7 @@ int main(int argc, char **argv) GE::RDF_HDF5::GEHDF5Wrapper input_file(input_filename); std::string template_filename; - if (argc==4) + if (argc == 4) { template_filename = argv[3]; shared_ptr template_projdata_sptr = ProjData::read_from_file(template_filename); @@ -72,16 +72,13 @@ int main(int argc, char **argv) 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 +'\"'); + 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 + '\"'); - 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); - GE::RDF_HDF5::SinglesRatesFromGEHDF5 singles(input_filename); + GE::RDF_HDF5::SinglesRatesFromGEHDF5 singles(input_filename); randoms_from_singles(proj_data, singles); return EXIT_SUCCESS; diff --git a/src/utilities/construct_randoms_from_singles.cxx b/src/utilities/construct_randoms_from_singles.cxx index 9db43f308..86c234429 100644 --- a/src/utilities/construct_randoms_from_singles.cxx +++ b/src/utilities/construct_randoms_from_singles.cxx @@ -36,48 +36,45 @@ using std::string; USING_NAMESPACE_STIR -int main(int argc, char **argv) +int +main(int argc, char** argv) { - if (argc!=5) + if (argc != 5) { - cerr << "Usage: " << argv[0] - << " out_filename in_norm_filename_prefix template_projdata eff_iter_num\n"; + cerr << "Usage: " << argv[0] << " out_filename in_norm_filename_prefix template_projdata eff_iter_num\n"; return EXIT_FAILURE; } 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(); DetectorEfficiencies efficiencies(IndexRange2D(num_rings, num_detectors_per_ring)); { // efficiencies - { - 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) - { - error("Error reading %s, using all 1s instead\n", in_filename); - } - delete[] in_filename; - } + { + 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) + { + error("Error reading %s, using all 1s instead\n", in_filename); + } + delete[] in_filename; + } } multiply_crystal_factors(proj_data, efficiencies, 1.F); 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 1038bd06b..2cf2e65e9 100644 --- a/src/utilities/conv_GATE_raw_ECAT_projdata_to_interfile.cxx +++ b/src/utilities/conv_GATE_raw_ECAT_projdata_to_interfile.cxx @@ -3,19 +3,19 @@ Copyright (C) 2010- 2013, King's College London Copyright (C) 2013, University College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + 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" @@ -31,94 +31,90 @@ #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){ - 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); - 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") ; - } - const float STIR_scanner_length = - scanner_sptr->get_num_rings() * scanner_sptr->get_ring_spacing(); + else + { + 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"); + } + 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) + 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 <= 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) - { + 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; - } + 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 de89e6d72..69fffa61c 100644 --- a/src/utilities/conv_gipl_to_interfile.cxx +++ b/src/utilities/conv_gipl_to_interfile.cxx @@ -2,15 +2,15 @@ Copyright (C) 2009 - 2013, King's College London Copyright (C) 2013, University College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 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 */ @@ -35,126 +35,137 @@ using std::fstream; using std::cerr; using std::endl; - USING_NAMESPACE_STIR // ------------------------------------------------------------------------- // Main function // ------------------------------------------------------------------------- -int main(int argc, char* argv[]) +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; + 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->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; diff --git a/src/utilities/conv_interfile_to_gipl.cxx b/src/utilities/conv_interfile_to_gipl.cxx index 50b6694c6..c06943cba 100644 --- a/src/utilities/conv_interfile_to_gipl.cxx +++ b/src/utilities/conv_interfile_to_gipl.cxx @@ -1,16 +1,16 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 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 */ @@ -35,109 +35,116 @@ using std::fstream; using std::cerr; using std::endl; - 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"; - exit(EXIT_FAILURE); - } +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*>(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 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 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; diff --git a/src/utilities/convert_to_binary_image.cxx b/src/utilities/convert_to_binary_image.cxx index 2415ef579..f1ea25673 100644 --- a/src/utilities/convert_to_binary_image.cxx +++ b/src/utilities/convert_to_binary_image.cxx @@ -9,10 +9,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 @@ -25,40 +25,36 @@ USING_NAMESPACE_STIR -int main(int argc, char **argv) +int +main(int argc, char** argv) { - if(argc!=4) { - std::cerr<<"Usage: " << argv[0] << " threshold\n"; - exit(EXIT_FAILURE); - } - + 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 3c01ba002..687f32886 100644 --- a/src/utilities/correct_projdata.cxx +++ b/src/utilities/correct_projdata.cxx @@ -20,7 +20,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 @@ -33,24 +33,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 @@ -66,7 +66,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 @@ -79,7 +79,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 @@ -87,11 +87,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:
        @@ -99,21 +100,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.
      • @@ -140,14 +141,14 @@ This parameter will be removed. #include "stir/warning.h" #include "stir/error.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 @@ -161,8 +162,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 @@ -173,35 +172,34 @@ START_NAMESPACE_STIR 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: void set_defaults() override; void initialise_keymap() override; bool post_processing() override; @@ -209,18 +207,15 @@ 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; @@ -228,61 +223,53 @@ run() const 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 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<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_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,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 + 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_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, 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(); @@ -308,73 +295,64 @@ run() const 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); - } - else - { - normalisation_ptr->undo(viewgrams); - } - } - 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 (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; - } - } - } - - } +#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); + } + else + { + normalisation_ptr->undo(viewgrams); + } + } + 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 (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 = ""; @@ -388,25 +366,24 @@ 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); @@ -418,76 +395,66 @@ initialise_keymap() parser.add_stop_key("END"); } - bool -CorrectProjDataApplication:: -post_processing() +CorrectProjDataApplication::post_processing() { if (is_null_ptr(normalisation_ptr)) - { - warning("Invalid normalisation object\n"); - return true; - } + { + 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 + else { // make a single frame starting from 0 to 1. - std::vector > frame_times(1, std::pair(0,1)); + std::vector> frame_times(1, std::pair(0, 1)); frame_defs = TimeFrameDefinitions(frame_times); } - if (frame_num<=0) + if (frame_num <= 0) { warning("frame_num should be >= 1 \n"); return true; } - if (static_cast(frame_num)> frame_defs.get_num_frames()) + 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()); + 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() +CorrectProjDataApplication::set_up() { - const int max_segment_num_available = - input_projdata_ptr->get_max_segment_num(); + 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 = 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 = 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); + output_proj_data_info_sptr->reduce_segment_range(-max_segment_num_to_process, max_segment_num_to_process); // construct output_projdata { @@ -508,7 +475,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) { @@ -517,76 +484,66 @@ 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)); - } + 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 - forward_projector_ptr.reset(); - } + { + // get rid of this object for now + // this is currently checked to find the symmetries: bad + // TODO + forward_projector_ptr.reset(); + } // set up normalisation object - if ( - normalisation_ptr->set_up(input_projdata_ptr->get_exam_info_sptr(),input_proj_data_info_sptr) - != Succeeded::yes) + 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[]) +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) + + if (argc != 2) { - cerr << "Corresponding .par file input \n" - << correct_proj_data_application.parameter_info() << endl; + 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; } - CPUTimer timer; timer.start(); @@ -594,11 +551,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 c5bab4dc6..c01cf3a8d 100644 --- a/src/utilities/create_multi_header.cxx +++ b/src/utilities/create_multi_header.cxx @@ -25,44 +25,50 @@ \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) +int +main(int argc, char** argv) { - if(argc<3) + if (argc < 3) { - std::cerr<< "Usage: " << argv[0] << "\n\t" - << "output_filename_with_extension in_data1 [in_data2 [in_data3...]]\n\n"; + 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 904052ac2..01642144f 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. SPDX-License-Identifier: Apache-2.0 @@ -33,31 +33,31 @@ using std::cerr; - USING_NAMESPACE_STIR -int main(int argc, char *argv[]) -{ - - if(argc!=2) - { - cerr<<"Usage: " << argv[0] << " output_filename\n"; - return EXIT_FAILURE; - } +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()); - + 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; // 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)); + // 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 6166c2a3d..ce92027c6 100644 --- a/src/utilities/ctac_to_mu_values.cxx +++ b/src/utilities/ctac_to_mu_values.cxx @@ -17,10 +17,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 @@ -28,7 +26,6 @@ */ - #include "stir/info.h" #include "stir/Succeeded.h" #include "stir/HUToMuImageProcessor.h" @@ -42,90 +39,90 @@ 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) + 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; - } + { + 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 ) + 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. - kVp_str = "120"; - stir::info(boost::format("No value for kVp given, assuming %s") % kVp_str); - } + 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; + 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 + // 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 )); + 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< FloatImageType > output_image_sptr(input_image_sptr->clone()); - //Apply scaling. + // 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 output file. write_to_file(output_filename, *output_image_sptr); } catch (std::string& error_string) @@ -144,5 +141,4 @@ int main(int argc, char * argv[]) return EXIT_FAILURE; } return EXIT_SUCCESS; - } diff --git a/src/utilities/display_projdata.cxx b/src/utilities/display_projdata.cxx index 37b4cad5d..bbe8da9a5 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 @@ -27,46 +27,44 @@ #include "stir/display.h" #include "stir/utilities.h" - using std::cout; USING_NAMESPACE_STIR - -int main(int argc, char *argv[]) +int +main(int argc, char* argv[]) { - if(argc<2) { - cout<<"Usage: display_projdata
        (*.hs)\n"; - exit(EXIT_FAILURE); + 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); + 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, 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)); + 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)); - return EXIT_SUCCESS; + return EXIT_SUCCESS; } diff --git a/src/utilities/do_linear_regression.cxx b/src/utilities/do_linear_regression.cxx index 2c5ac1600..9e5821d60 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:
        @@ -45,34 +45,31 @@ using std::ifstream; USING_NAMESPACE_STIR - -int main(int argc, char **argv) +int +main(int argc, char** argv) { 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; - return EXIT_FAILURE; - } - - + { + 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; + return EXIT_FAILURE; + } ifstream in(argv[1]); if (!in) - { - cerr << argv[0] - << ": Error opening input file " << argv[1] << "\nExiting." - << endl; - return EXIT_FAILURE; - } + { + cerr << argv[0] << ": Error opening input file " << argv[1] << "\nExiting." << endl; + return EXIT_FAILURE; + } int size; in >> size; @@ -80,50 +77,44 @@ 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); + 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); + 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); + 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 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 3dfb2a1c1..b969a3863 100644 --- a/src/utilities/ecat/conv_to_ecat6.cxx +++ b/src/utilities/ecat/conv_to_ecat6.cxx @@ -9,16 +9,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
         
        @@ -26,27 +26,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" @@ -72,8 +71,8 @@ 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; @@ -81,231 +80,218 @@ int main(int argc, char *argv[]) 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); - } - } - 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); + 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]); - 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) + 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); + } + } + else { - ask_filename_with_extension(cur_name,"Name of the input file? ",its_an_image?".hv":".hs"); - filenames.push_back(cur_name); + 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); + + 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"); + 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); + 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; + 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) - { + { - 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])); - - ECAT6_Main_header mhead; - make_ECAT6_Main_header(mhead, *scanner_ptr, filenames[0], *density_ptr); - mhead.num_frames = filenames.size(); + // read first image + cerr << "Reading " << filenames[0] << endl; + shared_ptr> density_ptr(read_from_file>(filenames[0])); - 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; + ECAT6_Main_header mhead; + make_ECAT6_Main_header(mhead, *scanner_ptr, filenames[0], *density_ptr); + mhead.num_frames = filenames.size(); - while (1) - { - if (DiscretisedDensity_to_ECAT6(fptr, - *density_ptr, - mhead, - frame_num) - == Succeeded::no) - { - fclose(fptr); - return EXIT_FAILURE; - } - 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]); + 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) + { + fclose(fptr); + return EXIT_FAILURE; + } + 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]); + } } - } - else - { - - // read first data set - cerr << "Reading " << filenames[0] << endl; - shared_ptr proj_data_ptr = - ProjData::read_from_file(filenames[0]); - - ECAT6_Main_header mhead; - FILE *fptr; + else + { - 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; + // read first data set + cerr << "Reading " << filenames[0] << endl; + shared_ptr proj_data_ptr = ProjData::read_from_file(filenames[0]); - 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); - } + ECAT6_Main_header mhead; + 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 - { - 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()) - { - fclose(fptr); - return EXIT_SUCCESS; - } - cerr << "Reading " << filenames[frame_num-1] << endl; - proj_data_ptr = - ProjData::read_from_file(filenames[frame_num-1]); - } - } -} + { + 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) + { + 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) + { + fclose(fptr); + return EXIT_FAILURE; + } + 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]); + } + } +} diff --git a/src/utilities/ecat/conv_to_ecat7.cxx b/src/utilities/ecat/conv_to_ecat7.cxx index 783e272a4..5e09b3860 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. */ /* @@ -59,242 +59,228 @@ USING_NAMESPACE_STIR USING_NAMESPACE_ECAT USING_NAMESPACE_ECAT7 +void +usage() +{ - - -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"; + 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] == '-' ) { - - int i = 1; - char 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++; - } - + while (arg_index < argc && argv[arg_index][0] == '-') + { - + int i = 1; + char c; - /* Check number of remaining arguments */ - 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 ) { - 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 ) { - - 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++) { - filenames.push_back(argv[arg_index]); - } - } + while ((c = argv[arg_index][i]) != '\0') + { - } else { - - usage(); - - cerr << "I will now ask you the same info interactively...\n\n"; - - its_an_image = ask("Converting images?",true); - - if (!its_an_image) { - write_as_attenuation = ask("Write as attenuation data?",false); - } else { - if ( ask("Fix scale factor to 1.0?", false) ) { - scale_factor = 1.0F; - } - } + switch (c) + { - 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"); - filenames.push_back(cur_name); - } - - ask_filename_with_extension(cti_name,"Name of the ECAT7 file? ", - its_an_image ? ".img" : ".scn"); - - } - + case 's': + its_an_image = false; + break; + case 'a': + its_an_image = false; + write_as_attenuation = true; + break; - if (its_an_image) - { - - 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])); - - 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; - - 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; + case 'n': + scale_factor = 1.0F; + break; + + default: + cerr << "Error: Unknown option " << c << " \n\n"; + usage(); + exit(0); + break; + } + + i++; + } + + arg_index++; } - unsigned int frame_num = 1; - while (1) + /* Check number of remaining arguments */ + if ((its_an_image == false && argc - arg_index >= 1) || argc - arg_index >= 2) { - if (DiscretisedDensity_to_ECAT7(mptr, - *density_ptr, - frame_num) - == Succeeded::no) - { - matrix_close(mptr); - return EXIT_FAILURE; - } - 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]); + + // Warn about scaling option on it's own. + 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) + { + + 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++) + { + filenames.push_back(argv[arg_index]); + } + } } - } - else - { - - // read first data set - cerr << "Reading " << filenames[0] << endl; - 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); - // 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) + else { - warning(boost::format("conv_to_ecat7: error opening output file %s. Remove first if it exists already") % cti_name); - return EXIT_FAILURE; + + usage(); + + cerr << "I will now ask you the same info interactively...\n\n"; + + its_an_image = ask("Converting images?", true); + + if (!its_an_image) + { + write_as_attenuation = ask("Write as attenuation data?", false); + } + else + { + if (ask("Fix scale factor to 1.0?", false)) + { + scale_factor = 1.0F; + } + } + + 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"); + filenames.push_back(cur_name); + } + + ask_filename_with_extension(cti_name, "Name of the ECAT7 file? ", its_an_image ? ".img" : ".scn"); } - unsigned int frame_num = 1; + if (its_an_image) + { - while (1) + 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])); + + 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; + + 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) + { + matrix_close(mptr); + return EXIT_FAILURE; + } + 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]); + } + } + else { - 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()) - { - matrix_close(mptr); - return EXIT_SUCCESS; - } - cerr << "Reading " << filenames[frame_num-1] << endl; - proj_data_ptr = - ProjData::read_from_file(filenames[frame_num-1]); + + // read first data set + cerr << "Reading " << filenames[0] << endl; + 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); + // 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) + { + 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) + { + matrix_close(mptr); + return EXIT_FAILURE; + } + 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]); + } } - } } - diff --git a/src/utilities/ecat/convecat6_if.cxx b/src/utilities/ecat/convecat6_if.cxx index 60b4e0ece..4f5eec7be 100644 --- a/src/utilities/ecat/convecat6_if.cxx +++ b/src/utilities/ecat/convecat6_if.cxx @@ -11,7 +11,7 @@ See STIR/LICENSE.txt for details */ -/*! +/*! \file \ingroup ECAT_utilities \brief Conversion from ECAT 6 cti to interfile (image and sinogram data) @@ -20,22 +20,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 @@ -51,7 +51,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" @@ -72,160 +71,141 @@ using std::endl; using std::min; using std::max; - - 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) - { + char* scanner_name_ptr = 0; + FILE* cti_fptr; + + if (argc == 3 || argc == 4) + { cti_name = argv[2]; out_name = argv[1]; - if (argc>3) + if (argc > 3) scanner_name_ptr = argv[3]; } - else + 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"); - + 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) - { - // force scanner - shared_ptr scanner_ptr( - Scanner::get_scanner_from_name(scanner_name_ptr)); - mhead.system_type = find_ECAT_system_type(*scanner_ptr); - } + { + // force scanner + 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); + 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; + 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); + 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; + + 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; + 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"); + 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 29d807658..33d09414e 100644 --- a/src/utilities/ecat/copy_ecat7_header.cxx +++ b/src/utilities/ecat/copy_ecat7_header.cxx @@ -10,7 +10,7 @@ See STIR/LICENSE.txt for details */ -/*! +/*! \file \ingroup utilities \ingroup ECAT @@ -32,7 +32,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" @@ -53,41 +52,44 @@ 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) + 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 + 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 (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); @@ -107,10 +109,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); @@ -137,32 +139,32 @@ 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) { @@ -220,24 +222,25 @@ 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); @@ -254,26 +257,27 @@ 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); @@ -286,14 +290,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) +void +copy_subheader(MatrixData* data_out, const MatrixData* data_in) { - MatrixFile *mptr = data_out->matfile; + MatrixFile* mptr = data_out->matfile; switch (mptr->mhptr->file_type) { #if 0 @@ -310,40 +314,33 @@ void copy_subheader(MatrixData * data_out, #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: - 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 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)); + 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)); + case Float3dSinogram: + copy_subheader(*reinterpret_cast(data_out->shptr), *reinterpret_cast(data_in->shptr)); break; default: case ByteProjection: @@ -352,263 +349,249 @@ void copy_subheader(MatrixData * data_out, } } -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 { 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() +ECAT_dataset_spec::set_defaults() { - frame_num=1; - gate_num=1; - data_num=0; - bed_pos_num=0; - plane_num=0; + 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() +ECAT_dataset_spec::ECAT_dataset_spec() { set_defaults(); } -ECAT_dataset_spec:: -ECAT_dataset_spec(const char * const spec) +ECAT_dataset_spec::ECAT_dataset_spec(const char* const spec) { decode_spec(spec); } -ECAT_dataset_spec:: -ECAT_dataset_spec(const string& spec) +ECAT_dataset_spec::ECAT_dataset_spec(const string& spec) { decode_spec(spec.c_str()); } -int -ECAT_dataset_spec:: -matnum() const +int +ECAT_dataset_spec::matnum() const { - return mat_numcod (frame_num, 1, gate_num, data_num, bed_pos_num); + return mat_numcod(frame_num, 1, gate_num, data_num, bed_pos_num); } -ostream& operator<<(ostream& s, const ECAT_dataset_spec& spec) +ostream& +operator<<(ostream& s, const ECAT_dataset_spec& spec) { - s << spec.frame_num << ',' - << spec.gate_num << ',' - << spec.data_num << ',' - << spec.bed_pos_num; + 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) + if (data == NULL) { matrix_errno = MAT_READ_FROM_NILFPTR; return Succeeded::no; } - MatrixFile *mptr = data->matfile; + MatrixFile* mptr = data->matfile; if (mptr == NULL) - { - matrix_errno = MAT_READ_FROM_NILFPTR ; + { + 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) + 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) return Succeeded::no; - - const int strtblk = matdir.strtblk; - int return_value=0; + 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; + 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; + 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; + 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; + 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; + fprintf(stderr, "Not implemented yet\n"); + matrix_errno = MAT_WRITE_ERROR; } - if (return_value) + if (return_value) { matrix_perror("error in writing subheader"); - return Succeeded::no; + return Succeeded::no; } - else - return Succeeded::yes; - + else + return Succeeded::yes; } - - - -int main(int argc, char *argv[]) +int +main(int argc, char* argv[]) { - bool update=true; // switch between update and straight copy - if (argc>1 && strcmp(argv[1], "--copy")==0) + bool update = true; // switch between update and straight copy + if (argc > 1 && strcmp(argv[1], "--copy") == 0) { - update=false; - --argc; ++ argv; + 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)); - } + 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 (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()); - } + { + 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()); - } + { + 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); - 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); - if (!mout_ptr) { - matrix_perror(output_name.c_str()); - exit(EXIT_FAILURE); - } + 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); + 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; + return EXIT_FAILURE; else - return EXIT_SUCCESS; + return EXIT_SUCCESS; } #endif @@ -616,26 +599,23 @@ int main(int argc, char *argv[]) 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); + 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); + { + 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) - { - matrix_perror("Error reading output subheader"); - return EXIT_FAILURE; - } + { + 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 92e1e526d..82be7db3a 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. @@ -110,143 +110,141 @@ using std::swap; USING_NAMESPACE_STIR -static void dets_to_ve( int da, int db, int *v, int *e, int ndets) +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) +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]); - - + + 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]); + 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) + for (int segment_num = 1; segment_num <= org_proj_data_ptr->get_max_segment_num(); ++segment_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_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 73aba2f9d..a925baa82 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 @@ -38,8 +38,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" @@ -62,60 +60,56 @@ using std::fstream; using std::cerr; using std::endl; - USING_NAMESPACE_STIR USING_NAMESPACE_ECAT USING_NAMESPACE_ECAT7 -int -main( int argc, char **argv) +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); - if (!mptr) { - matrix_perror(argv[1]); - exit(EXIT_FAILURE); - } - - const int num_frames = std::max(static_cast( mptr->mhptr->num_frames),1); + 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); + if (!mptr) + { + matrix_perror(argv[1]); + exit(EXIT_FAILURE); + } + + 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] == '-') + while (argc > 1 && argv[1][0] == '-') { if (strcmp(argv[1], "--image") == 0) - { - option = opt_image; --argc; ++argv; break; - } + { + option = opt_image; + --argc; + ++argv; + break; + } if (strcmp(argv[1], "--emission") == 0) - { - option = opt_emission; --argc; ++argv; break; - } + { + option = opt_emission; + --argc; + ++argv; + break; + } if (strcmp(argv[1], "--ACF") == 0) - { - option = opt_ACF; --argc; ++argv; break; - } + { + option = opt_ACF; + --argc; + ++argv; + break; + } else - print_usage_and_exit(prog_name); + print_usage_and_exit(prog_name); } - if (argc!=2) + 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; + 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) diff --git a/src/utilities/ecat/print_ecat_singles_values.cxx b/src/utilities/ecat/print_ecat_singles_values.cxx index 082252e44..e9a7fc0c1 100644 --- a/src/utilities/ecat/print_ecat_singles_values.cxx +++ b/src/utilities/ecat/print_ecat_singles_values.cxx @@ -15,16 +15,13 @@ \author Tim Borgeaud */ - #include "stir/data/SinglesRatesFromECAT7.h" - #include #include #include #include - using std::cout; using std::cerr; using std::endl; @@ -34,86 +31,81 @@ 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"; - cerr << "Usage: " << argv[0] << " sgl_filename [bin_index ...]\n\n"; - cerr << "If no bin index values are supplied, all bins are output.\n\n"; - exit(EXIT_FAILURE); - } + if (argc < 2) + { + cerr << "Program to print out values from a singles file.\n\n"; + cerr << "Usage: " << argv[0] << " sgl_filename [bin_index ...]\n\n"; + cerr << "If no bin index values are supplied, all bins are output.\n\n"; + exit(EXIT_FAILURE); + } const string ecat7_filename = argv[1]; - for (int arg = 2 ; arg < argc ; ++arg) { - columns.push_back(atoi(argv[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) { - cout << setw(9) << *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) { - - // 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) << " "; - - for (vector::iterator col = columns.begin() ; col < columns.end() ; ++col) { - - if ( *col >= 0 && *col < total_singles_units ) { - float val = singles_from_ecat7.get_singles(*col, frame); - - cout << setw(9) << val << " "; - } - } - - // Output the end of line. - cout << endl; - - } + 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) << " "; + + for (vector::iterator col = columns.begin(); col < columns.end(); ++col) + { + + if (*col >= 0 && *col < total_singles_units) + { + float val = singles_from_ecat7.get_singles(*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 3c1ecbf8f..c43ff9d4b 100644 --- a/src/utilities/estimate_triple_energy_window_scatter_sinogram.cxx +++ b/src/utilities/estimate_triple_energy_window_scatter_sinogram.cxx @@ -16,7 +16,6 @@ \author Daniel Deidda */ - #include "stir/SegmentByView.h" #include "stir/IO/OutputFileFormat.h" #include "stir/IO/read_from_file.h" @@ -34,9 +33,8 @@ #include "stir/IndexRange3D.h" #include "stir/ArrayFilter3DUsingConvolution.h" - -#include -#include +#include +#include #include #include #include @@ -50,42 +48,37 @@ using std::min; using std::string; using std::vector; - USING_NAMESPACE_STIR 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() @@ -93,122 +86,116 @@ estimate_TEW_scatter::estimate_TEW_scatter() initialise_keymap(); } -int -main(int argc, char **argv) +int +main(int argc, char** argv) { - if(argc<2) + 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"; + 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) + 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.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); + // 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()); + 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)); + 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); -// } + // 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(); + // 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); - } + ++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(); + 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 + // The following apply the the TEW method C_{scatter}=(C_{lower}/W_{lower}+C_{upper}/W_{upper})*W_{peak}/2 - 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 ); + 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); - 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); + 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)) + 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); + 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); + char const* const filename = argv[1]; - const bool extract_by_view = - ask_num("Extract as SegmentByView (0) or BySinogram (1)?", 0,1,0)==0; + shared_ptr s3d = ProjData::read_from_file(filename); - const bool is_tof = s3d->get_min_tof_pos_num() != s3d->get_max_tof_pos_num(); + 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) - for (int tof_pos_num = s3d->get_min_tof_pos_num(); - tof_pos_num <= s3d->get_max_tof_pos_num(); - ++tof_pos_num) - { - std::string output_filename=filename; + const bool is_tof = s3d->get_min_tof_pos_num() != s3d->get_max_tof_pos_num(); + + for (int segment_num = s3d->get_min_segment_num(); segment_num <= s3d->get_max_segment_num(); ++segment_num) + for (int tof_pos_num = s3d->get_min_tof_pos_num(); tof_pos_num <= s3d->get_max_tof_pos_num(); ++tof_pos_num) + { + std::string output_filename = filename; replace_extension(output_filename, ""); - output_filename+="seg"; - output_filename+=boost::str(boost::format("%d") % segment_num); + output_filename += "seg"; + output_filename += boost::str(boost::format("%d") % segment_num); if (is_tof) output_filename += "_tof" + std::to_string(tof_pos_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); + 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) - { - const auto segment= s3d->get_segment_by_view(segment_num, tof_pos_num); - write_basic_interfile(output_filename + "_by_view.hv", - segment, - CartesianCoordinate3D(1.F, m_spacing, s_spacing), - CartesianCoordinate3D(0.F, m, s)); - } - else { - const auto segment = s3d->get_segment_by_sinogram(segment_num, tof_pos_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; + { + const auto segment = s3d->get_segment_by_view(segment_num, tof_pos_num); + write_basic_interfile(output_filename + "_by_view.hv", + segment, + CartesianCoordinate3D(1.F, m_spacing, s_spacing), + CartesianCoordinate3D(0.F, m, s)); + } + else + { + const auto segment = s3d->get_segment_by_sinogram(segment_num, tof_pos_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; } diff --git a/src/utilities/extract_single_images_from_dynamic_image.cxx b/src/utilities/extract_single_images_from_dynamic_image.cxx index c54ae4f4d..a7b15f303 100644 --- a/src/utilities/extract_single_images_from_dynamic_image.cxx +++ b/src/utilities/extract_single_images_from_dynamic_image.cxx @@ -16,7 +16,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, @@ -44,68 +44,80 @@ #include "stir/Succeeded.h" #include "stir/error.h" -int main(int argc, char *argv[]) +int +main(int argc, char* argv[]) { - USING_NAMESPACE_STIR + 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; + 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) { + // 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); + 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; + 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."); + // 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; + // 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 eee2394f4..b0c7e3cab 100644 --- a/src/utilities/find_ML_normfactors.cxx +++ b/src/utilities/find_ML_normfactors.cxx @@ -35,7 +35,6 @@ START_NAMESPACE_STIR - #if 0 // this is a test routine for the code // should really be in a test class @@ -97,58 +96,61 @@ void check_geo_data() #endif - - END_NAMESPACE_STIR -static void print_usage_and_exit(const std::string& program_name) +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"; + 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) +int +main(int argc, char** argv) { - const char * const program_name = argv[0]; + 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) + 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; - } + 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); + 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) + ++argc; + --argv; + + if (argc != 6) { print_usage_and_exit(program_name); } @@ -157,17 +159,13 @@ int main(int argc, char **argv) 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(); @@ -175,11 +173,11 @@ 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)); @@ -192,156 +190,151 @@ int main(int argc, char **argv) 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_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(model_det_pair_data, *model_data, segment_num, ax_pos_num); - //display(model_det_pair_data, "model"); + // display(model_det_pair_data, "model"); - 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); + 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; + 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; - 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); + 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; a #include -static void print_usage_and_exit(const std::string& program_name) +static void +print_usage_and_exit(const std::string& program_name) { - std::cerr<<"Usage: " << program_name << " [--display | --print-KL | --include-block-timing-model | --for-symmetry-per-block] \\\n" - << " out_filename_prefix measured_data model num_iterations num_eff_iterations\n" - << " set num_iterations to 0 to do only efficiencies\n"; + std::cerr << "Usage: " << program_name + << " [--display | --print-KL | --include-block-timing-model | --for-symmetry-per-block] \\\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) +int +main(int argc, char** argv) { - const char * const program_name = argv[0]; - // skip program name - --argc; - ++argv; + const char* const program_name = argv[0]; + // skip program name + --argc; + ++argv; bool do_display = false; bool do_KL = false; @@ -50,41 +52,47 @@ int main(int argc, char **argv) bool do_symmetry_per_block = false; // first process command line options - while (argc>0 && argv[0][0]=='-' && argc>=1) + 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 if (strcmp(argv[0], "--for-symmetry-per-block")==0) - { - do_symmetry_per_block = true; - --argc; ++argv; - } + 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 if (strcmp(argv[0], "--for-symmetry-per-block") == 0) + { + do_symmetry_per_block = true; + --argc; + ++argv; + } else - print_usage_and_exit(program_name); + 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) + ++argc; + --argv; + + // check_geo_data(); + if (argc != 6) { print_usage_and_exit(program_name); } @@ -97,9 +105,16 @@ int main(int argc, char **argv) CPUTimer timer; timer.start(); - ML_estimate_component_based_normalisation(out_filename_prefix, *measured_data, *model_data, - num_eff_iterations, num_iterations, - do_geo, do_block, do_symmetry_per_block, do_KL, do_display); + ML_estimate_component_based_normalisation(out_filename_prefix, + *measured_data, + *model_data, + num_eff_iterations, + num_iterations, + do_geo, + do_block, + do_symmetry_per_block, + do_KL, + do_display); timer.stop(); info(boost::format("CPU time %1% secs") % timer.value()); diff --git a/src/utilities/find_ML_singles_from_delayed.cxx b/src/utilities/find_ML_singles_from_delayed.cxx index 7c7ecc906..8e9202406 100644 --- a/src/utilities/find_ML_singles_from_delayed.cxx +++ b/src/utilities/find_ML_singles_from_delayed.cxx @@ -30,30 +30,30 @@ 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))) +int +main(int argc, char** argv) +{ + if (!(argc == 4 || (argc == 7 && strcmp(argv[1], "-f") == 0))) { - std::cerr << "Usage: \n" + 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" @@ -62,29 +62,25 @@ int main(int argc, char **argv) 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); + 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) + 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()); + 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; @@ -97,21 +93,20 @@ int main(int argc, char **argv) { std::string fan_sum_name = "fansums_for_"; fan_sum_name += get_filename(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); - } + 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 @@ -120,101 +115,100 @@ int main(int argc, char **argv) fan_size = atoi(argv[6]); std::ifstream in(argv[3]); if (!in) - { - warning("Error opening input file %s\n", argv[3]); - exit(EXIT_FAILURE); - } + { + 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); + 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_rings0 && 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); - } - out << efficiencies; - 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)) + for (int eff_iter_num = 1; eff_iter_num <= num_eff_iterations; ++eff_iter_num) { - 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) - { - display(efficiencies, "efficiencies"); + 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); + std::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); + } + + 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); + } + std::cout << std::endl; + 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 500b7275c..18890b258 100644 --- a/src/utilities/find_fwhm_in_image.cxx +++ b/src/utilities/find_fwhm_in_image.cxx @@ -10,7 +10,7 @@ \file \ingroup utilities \brief List of FWHM and location of maximum in the image - + \author Charalampos Tsoumpas \author Kris Thielemans \author Sanida Mustafovic @@ -20,23 +20,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" @@ -47,91 +47,80 @@ #include #include #include -#include +#include #include using std::setw; -/***********************************************************/ -int main(int argc, char *argv[]) -{ +/***********************************************************/ +int +main(int argc, char* argv[]) +{ USING_NAMESPACE_STIR - if (argc< 2 || argc>6) + 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" + << "\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< 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) + 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 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' ; + 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) + output_string += '_' + slices_string + "_slices_FWHM"; + + std::ofstream out(output_string.c_str()); // output file // + if (!out) { - std::cerr << "Cannot open text file.\n" ; + 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) + 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::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 2c14c69a3..b75babcee 100644 --- a/src/utilities/find_maxima_in_image.cxx +++ b/src/utilities/find_maxima_in_image.cxx @@ -41,107 +41,98 @@ #include #include - using std::endl; using std::cout; using std::cerr; using std::setw; USING_NAMESPACE_STIR - -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; - - 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; - - 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) + +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" << endl; + return (EXIT_FAILURE); + } + + 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"; + + 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); + + 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; + 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/find_normfactors_from_cylinder_data.cxx b/src/utilities/find_normfactors_from_cylinder_data.cxx index 2164546ac..69483110e 100644 --- a/src/utilities/find_normfactors_from_cylinder_data.cxx +++ b/src/utilities/find_normfactors_from_cylinder_data.cxx @@ -5,7 +5,7 @@ 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, @@ -40,30 +40,29 @@ limitations under the License. USING_NAMESPACE_STIR -int main(int argc, char **argv) +int +main(int argc, char** argv) { - if (argc!=4) - { - std::cerr << "Usage: "<< argv[0] - <<" output_file_name_prefix cylider_measured_data cylinder_radius(mm)\n" - <<"only cylinder data are supported. The radius should be the radius of the measured cylinder data.\n" - <<"warning: mind the input order\n"; - return EXIT_FAILURE; - } + if (argc != 4) + { + std::cerr << "Usage: " << argv[0] << " output_file_name_prefix cylider_measured_data cylinder_radius(mm)\n" + << "only cylinder data are supported. The radius should be the radius of the measured cylinder data.\n" + << "warning: mind the input order\n"; + return EXIT_FAILURE; + } shared_ptr cylinder_projdata_ptr = ProjData::read_from_file(argv[2]); const std::string output_file_name = argv[1]; const float R = atof(argv[3]); // cylinder radius (mm) - if (R==0) - { - std::cerr << " Radius must be a float value\n" - <<"Usage: "<< argv[0] - <<" output_file_name_prefix cylider_measured_data cylinder_radius\n" - <<"warning: mind the input order\n"; - return EXIT_FAILURE; - } - - //output file + if (R == 0) + { + std::cerr << " Radius must be a float value\n" + << "Usage: " << argv[0] << " output_file_name_prefix cylider_measured_data cylinder_radius\n" + << "warning: mind the input order\n"; + return EXIT_FAILURE; + } + + // output file shared_ptr cylinder_pdi_ptr(cylinder_projdata_ptr->get_proj_data_info_sptr()->clone()); ProjDataInterfile output_projdata(cylinder_projdata_ptr->get_exam_info_sptr(), cylinder_pdi_ptr, output_file_name); @@ -73,86 +72,93 @@ int main(int argc, char **argv) LORInAxialAndNoArcCorrSinogramCoordinates lor; // first find the average number of counts per LOR - float total_count=0; - float min_count=std::numeric_limits::max(); // minimum number of counts per LOR - float average_count=0; //average number of counts per LOR in the active region - int num_active_LORs=0; //number of LORs which pass through the cylinder - for (int seg =cylinder_projdata_ptr->get_min_segment_num(); seg <=cylinder_projdata_ptr->get_max_segment_num(); ++seg) - for (int view =cylinder_projdata_ptr->get_min_view_num(); view <=cylinder_projdata_ptr->get_max_view_num(); ++view) - { - Viewgram cylinder_viewgram = cylinder_projdata_ptr->get_viewgram(view, seg); - for (int ax =cylinder_projdata_ptr->get_min_axial_pos_num(seg); ax <=cylinder_projdata_ptr->get_max_axial_pos_num(seg); ++ax) - for (int tang =cylinder_projdata_ptr->get_min_tangential_pos_num(); tang <=cylinder_projdata_ptr->get_max_tangential_pos_num(); ++tang) - { - Bin bin(seg, view, ax, tang); - cylinder_projdata_ptr->get_proj_data_info_sptr()->get_LOR(lor, bin); - LORAs2Points lor_as2points(lor); - LORAs2Points intersection_coords; - if (find_LOR_intersections_with_cylinder(intersection_coords, lor_as2points, R) ==Succeeded::yes) - { //this only succeeds if LOR is intersecting with the cylinder - float N_lor = cylinder_viewgram[ax][tang]; //counts seen by this lor - c1 = intersection_coords.p1(); - c2 = intersection_coords.p2(); - float c12 = sqrt( pow(c1.z()-c2.z(), 2) // length of intersection of lor with the cylinder - + pow(c1.y()-c2.y(), 2) - + pow(c1.x()-c2.x(), 2) ); - if (c12>0.5) // if LOR intersection is lager than 0.5 mm, check the count per LOR - { - float N_lor_corrected=N_lor/c12; // corrected for the length - total_count+=N_lor_corrected; - num_active_LORs+=1; - if (N_lor_corrected::max(); // minimum number of counts per LOR + float average_count = 0; // average number of counts per LOR in the active region + int num_active_LORs = 0; // number of LORs which pass through the cylinder + for (int seg = cylinder_projdata_ptr->get_min_segment_num(); seg <= cylinder_projdata_ptr->get_max_segment_num(); ++seg) + for (int view = cylinder_projdata_ptr->get_min_view_num(); view <= cylinder_projdata_ptr->get_max_view_num(); ++view) + { + Viewgram cylinder_viewgram = cylinder_projdata_ptr->get_viewgram(view, seg); + for (int ax = cylinder_projdata_ptr->get_min_axial_pos_num(seg); ax <= cylinder_projdata_ptr->get_max_axial_pos_num(seg); + ++ax) + for (int tang = cylinder_projdata_ptr->get_min_tangential_pos_num(); + tang <= cylinder_projdata_ptr->get_max_tangential_pos_num(); + ++tang) + { + Bin bin(seg, view, ax, tang); + cylinder_projdata_ptr->get_proj_data_info_sptr()->get_LOR(lor, bin); + LORAs2Points lor_as2points(lor); + LORAs2Points intersection_coords; + if (find_LOR_intersections_with_cylinder(intersection_coords, lor_as2points, R) == Succeeded::yes) + { // this only succeeds if LOR is intersecting with the cylinder + float N_lor = cylinder_viewgram[ax][tang]; // counts seen by this lor + c1 = intersection_coords.p1(); + c2 = intersection_coords.p2(); + float c12 = sqrt(pow(c1.z() - c2.z(), 2) // length of intersection of lor with the cylinder + + pow(c1.y() - c2.y(), 2) + pow(c1.x() - c2.x(), 2)); + if (c12 > 0.5) // if LOR intersection is lager than 0.5 mm, check the count per LOR + { + float N_lor_corrected = N_lor / c12; // corrected for the length + total_count += N_lor_corrected; + num_active_LORs += 1; + if (N_lor_corrected < min_count && N_lor_corrected != 0) + min_count = N_lor_corrected; + } + } + } } - } - } - average_count=total_count/num_active_LORs; - std::cout<<"num_lor, tot_count_per_length_unit, average_count_per_length_unit, non_zero_min_per_length_unit = "<get_min_segment_num(); seg <=cylinder_projdata_ptr->get_max_segment_num(); ++seg) - for (int view =cylinder_projdata_ptr->get_min_view_num(); view <=cylinder_projdata_ptr->get_max_view_num(); ++view) - { - Viewgram cylinder_viewgram = cylinder_projdata_ptr->get_viewgram(view, seg); - Viewgram out_viewgram = cylinder_projdata_ptr->get_empty_viewgram(view, seg); - for (int ax =cylinder_projdata_ptr->get_min_axial_pos_num(seg); ax <=cylinder_projdata_ptr->get_max_axial_pos_num(seg); ++ax) - for (int tang =cylinder_projdata_ptr->get_min_tangential_pos_num(); tang <=cylinder_projdata_ptr->get_max_tangential_pos_num(); ++tang) - { - Bin bin(seg, view, ax, tang); - cylinder_projdata_ptr->get_proj_data_info_sptr()->get_LOR(lor, bin); - LORAs2Points lor_as2points(lor); - LORAs2Points intersection_coords; - float NF_lor; - if (find_LOR_intersections_with_cylinder(intersection_coords, lor_as2points, R) ==Succeeded::yes) - { //this only succeeds if LOR is intersecting with the cylinder - - /* - for each lor - find_LOR_intersections_with_cylinder => c1 & c2 - c12 = |c1-c2| = sqrt(dx^2+dy^2+dz^2) - N_lor/c12 should be the same for all therefore: - NF_lor= / (N_lor/c12) - */ - - float N_lor = cylinder_viewgram[ax][tang]; //counts seen by this lor - c1 = intersection_coords.p1(); - c2 = intersection_coords.p2(); - float c12 = sqrt( pow(c1.z()-c2.z(), 2) // length of intersection of lor with the cylinder - + pow(c1.y()-c2.y(), 2) - + pow(c1.x()-c2.x(), 2) ); - if (N_lor<1) //if inside the cylinder but the value is too small - { - NF_lor = average_count*c12/min_count; - } - else - NF_lor = average_count*c12/N_lor; - } - else //if out of the cylinder set it to a small value instead of zero, otherwise normalisation gives strange recon image. + for (int seg = cylinder_projdata_ptr->get_min_segment_num(); seg <= cylinder_projdata_ptr->get_max_segment_num(); ++seg) + for (int view = cylinder_projdata_ptr->get_min_view_num(); view <= cylinder_projdata_ptr->get_max_view_num(); ++view) { - NF_lor=0.0001; + Viewgram cylinder_viewgram = cylinder_projdata_ptr->get_viewgram(view, seg); + Viewgram out_viewgram = cylinder_projdata_ptr->get_empty_viewgram(view, seg); + for (int ax = cylinder_projdata_ptr->get_min_axial_pos_num(seg); ax <= cylinder_projdata_ptr->get_max_axial_pos_num(seg); + ++ax) + for (int tang = cylinder_projdata_ptr->get_min_tangential_pos_num(); + tang <= cylinder_projdata_ptr->get_max_tangential_pos_num(); + ++tang) + { + Bin bin(seg, view, ax, tang); + cylinder_projdata_ptr->get_proj_data_info_sptr()->get_LOR(lor, bin); + LORAs2Points lor_as2points(lor); + LORAs2Points intersection_coords; + float NF_lor; + if (find_LOR_intersections_with_cylinder(intersection_coords, lor_as2points, R) == Succeeded::yes) + { // this only succeeds if LOR is intersecting with the cylinder + + /* + for each lor + find_LOR_intersections_with_cylinder => c1 & c2 + c12 = |c1-c2| = sqrt(dx^2+dy^2+dz^2) + N_lor/c12 should be the same for all therefore: + NF_lor= / (N_lor/c12) + */ + + float N_lor = cylinder_viewgram[ax][tang]; // counts seen by this lor + c1 = intersection_coords.p1(); + c2 = intersection_coords.p2(); + float c12 = sqrt(pow(c1.z() - c2.z(), 2) // length of intersection of lor with the cylinder + + pow(c1.y() - c2.y(), 2) + pow(c1.x() - c2.x(), 2)); + if (N_lor < 1) // if inside the cylinder but the value is too small + { + NF_lor = average_count * c12 / min_count; + } + else + NF_lor = average_count * c12 / N_lor; + } + else // if out of the cylinder set it to a small value instead of zero, otherwise normalisation gives strange recon + // image. + { + NF_lor = 0.0001; + } + out_viewgram[ax][tang] = NF_lor; + } + output_projdata.set_viewgram(out_viewgram); } - out_viewgram[ax][tang] = NF_lor; - } - output_projdata.set_viewgram(out_viewgram); - } } diff --git a/src/utilities/find_recovery_coefficients_in_image_quality_phantom_nema_nu4.cxx b/src/utilities/find_recovery_coefficients_in_image_quality_phantom_nema_nu4.cxx index c665a055d..2dbb49d35 100644 --- a/src/utilities/find_recovery_coefficients_in_image_quality_phantom_nema_nu4.cxx +++ b/src/utilities/find_recovery_coefficients_in_image_quality_phantom_nema_nu4.cxx @@ -5,7 +5,7 @@ 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, @@ -49,22 +49,20 @@ using std::vector; USING_NAMESPACE_STIR - class FindRecoveryCoefficient : public ParsingObject { public: - - FindRecoveryCoefficient(const char * const par_filename); + FindRecoveryCoefficient(const char* const par_filename); Succeeded compute(); private: typedef ParsingObject base_type; - int min_index_for_average_plane; //min plane number - int max_index_for_average_plane; //max plane number + int min_index_for_average_plane; // min plane number + int max_index_for_average_plane; // max plane number float mean_uniform_region; float STD_uniform_region; - int start_z_of_rods; //axial position of start point of the rods - int stop_z_of_rods; //axial position of end point of the rods + int start_z_of_rods; // axial position of start point of the rods + int stop_z_of_rods; // axial position of end point of the rods std::vector ROIs_x; // order is from the smallest ROI to the largest std::vector ROIs_y; // order is from the smallest ROI to the largest std::string input_filename; @@ -74,12 +72,12 @@ class FindRecoveryCoefficient : public ParsingObject void set_defaults() override; }; -void FindRecoveryCoefficient:: -initialise_keymap() +void +FindRecoveryCoefficient::initialise_keymap() { this->parser.add_start_key("FindRecoveryCoefficient Parameters"); - this->parser.add_key("input filename",&input_filename); - this->parser.add_key("output filename",&output_filename); + this->parser.add_key("input filename", &input_filename); + this->parser.add_key("output filename", &output_filename); this->parser.add_key("minimun index to calculate the average plane", &min_index_for_average_plane); this->parser.add_key("maximum index to calculate the average plane", &max_index_for_average_plane); this->parser.add_key("mean value of uniform region", &mean_uniform_region); @@ -91,40 +89,39 @@ initialise_keymap() this->parser.add_stop_key("END FindRecoveryCoefficient Parameters"); } -void FindRecoveryCoefficient:: -set_defaults() +void +FindRecoveryCoefficient::set_defaults() { // specify defaults for the parameters in case they are not set. - min_index_for_average_plane= 88; - max_index_for_average_plane= 98; + min_index_for_average_plane = 88; + max_index_for_average_plane = 98; mean_uniform_region = 0.00569557; STD_uniform_region = 0.00107216; start_z_of_rods = 86; stop_z_of_rods = 102; - ROIs_x = {2.16312,-5.66312,-5.66312,2.16312,7.}; - ROIs_y = {6.6574,4.1145,-4.1145,-6.6574,0.}; + ROIs_x = { 2.16312, -5.66312, -5.66312, 2.16312, 7. }; + ROIs_y = { 6.6574, 4.1145, -4.1145, -6.6574, 0. }; input_filename.resize(0); output_filename.resize(0); } -FindRecoveryCoefficient:: -FindRecoveryCoefficient(const char * const par_filename) +FindRecoveryCoefficient::FindRecoveryCoefficient(const char* const par_filename) { set_defaults(); - if (par_filename!=0) + if (par_filename != 0) { if (parse(par_filename) == false) - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } else ask_parameters(); } - void compute_average_plane_in_given_range(VoxelsOnCartesianGrid& average_plane, - const VoxelsOnCartesianGrid& image, - const int& min_index, const int& max_index) + const VoxelsOnCartesianGrid& image, + const int& min_index, + const int& max_index) { int min_z = image.get_min_z(); int max_z = image.get_max_z(); @@ -132,52 +129,51 @@ compute_average_plane_in_given_range(VoxelsOnCartesianGrid& average_plane int min_x = image.get_min_x(); int max_y = image.get_max_y(); int max_x = image.get_max_x(); - if (min_indexmax_z) - { - error("min_index & max_index are not in the range of provided image!"); - } - + if (min_index < min_z || max_index > max_z) + { + error("min_index & max_index are not in the range of provided image!"); + } - shared_ptr > sum_planes_ptr(image.get_empty_voxels_on_cartesian_grid()); + shared_ptr> sum_planes_ptr(image.get_empty_voxels_on_cartesian_grid()); VoxelsOnCartesianGrid sum_planes = *sum_planes_ptr; int num_planes = max_index - min_index + 1; - for (int z=min_index; z<=max_index; z++) - for(int y=min_y; y<=max_y; y++) - for(int x=min_x; x<=max_x; x++) - { - sum_planes[0][y][x] += image[z][y][x]; - } - for(int y=min_y; y<=max_y; y++) - for(int x=min_x; x<=max_x; x++) - { - average_plane[0][y][x] = sum_planes[0][y][x] / num_planes; - } + for (int z = min_index; z <= max_index; z++) + for (int y = min_y; y <= max_y; y++) + for (int x = min_x; x <= max_x; x++) + { + sum_planes[0][y][x] += image[z][y][x]; + } + for (int y = min_y; y <= max_y; y++) + for (int x = min_x; x <= max_x; x++) + { + average_plane[0][y][x] = sum_planes[0][y][x] / num_planes; + } } void -build_ROIs(vector & ROIs, float length_z, std::vector ROIs_x, std::vector ROIs_y) +build_ROIs(vector& ROIs, float length_z, std::vector ROIs_x, std::vector ROIs_y) { - //note: the y coordinate is (-1*y) of coordinates in your images. STIR assumes y axis downward. - vector> ROI_centers{CartesianCoordinate2D(ROIs_y[0],ROIs_x[0]), //(y,x) - CartesianCoordinate2D(ROIs_y[1],ROIs_x[1]), - CartesianCoordinate2D(ROIs_y[2],ROIs_x[2]), - CartesianCoordinate2D(ROIs_y[3],ROIs_x[3]), - CartesianCoordinate2D(ROIs_y[4],ROIs_x[4])}; - for (int i = 0; i<5; i++) - { - float d = 2*(i+1); //ROI diameter in mm - float radius_y =d/2.; - float radius_x = d/2.; - CartesianCoordinate3D centre(0, ROI_centers[i].y(), ROI_centers[i].x()); - EllipsoidalCylinder current_ROI(length_z, radius_y, radius_x, centre); - ROIs.push_back(current_ROI); - } + // note: the y coordinate is (-1*y) of coordinates in your images. STIR assumes y axis downward. + vector> ROI_centers{ CartesianCoordinate2D(ROIs_y[0], ROIs_x[0]), //(y,x) + CartesianCoordinate2D(ROIs_y[1], ROIs_x[1]), + CartesianCoordinate2D(ROIs_y[2], ROIs_x[2]), + CartesianCoordinate2D(ROIs_y[3], ROIs_x[3]), + CartesianCoordinate2D(ROIs_y[4], ROIs_x[4]) }; + for (int i = 0; i < 5; i++) + { + float d = 2 * (i + 1); // ROI diameter in mm + float radius_y = d / 2.; + float radius_x = d / 2.; + CartesianCoordinate3D centre(0, ROI_centers[i].y(), ROI_centers[i].x()); + EllipsoidalCylinder current_ROI(length_z, radius_y, radius_x, centre); + ROIs.push_back(current_ROI); + } } - void -find_max_in_ROI(float &max, CartesianCoordinate3D& max_coord, +find_max_in_ROI(float& max, + CartesianCoordinate3D& max_coord, const VoxelsOnCartesianGrid& image, const EllipsoidalCylinder& ROI) { @@ -187,32 +183,31 @@ find_max_in_ROI(float &max, CartesianCoordinate3D& max_coord, const int max_y = image.get_max_y(); const int max_x = image.get_max_x(); - shared_ptr > - discretised_shape_ptr(image.get_empty_voxels_on_cartesian_grid()); - ROI.construct_volume(*discretised_shape_ptr, Coordinate3D(1,1,1)); // TODO number_samples=1, make it general + shared_ptr> discretised_shape_ptr(image.get_empty_voxels_on_cartesian_grid()); + ROI.construct_volume(*discretised_shape_ptr, Coordinate3D(1, 1, 1)); // TODO number_samples=1, make it general VoxelsOnCartesianGrid discretised_shape = *discretised_shape_ptr; max = std::numeric_limits::lowest(); - //iterate only over y , x. because the image is actualy the average plane in which only z=0 is valid - for(int y=min_y; y<=max_y; y++) - for(int x=min_x; x<=max_x; x++) - { - int z=0; - const float weight = discretised_shape[z][y][x]; - if (weight ==0) - continue; - - change = 1; - CartesianCoordinate3D current_index(z,y,x); - const float current_value = image[z][y][x]; - if (current_value>max) - { - max=current_value; - max_coord = current_index; - } - } - if (change ==0) + // iterate only over y , x. because the image is actualy the average plane in which only z=0 is valid + for (int y = min_y; y <= max_y; y++) + for (int x = min_x; x <= max_x; x++) + { + int z = 0; + const float weight = discretised_shape[z][y][x]; + if (weight == 0) + continue; + + change = 1; + CartesianCoordinate3D current_index(z, y, x); + const float current_value = image[z][y][x]; + if (current_value > max) + { + max = current_value; + max_coord = current_index; + } + } + if (change == 0) error("Max was not found in this range. All voxels are zero\n"); } @@ -222,167 +217,164 @@ find_max_in_all_ROIs(vector& maxs, const VoxelsOnCartesianGrid& image, const vector& ROIs) { - for (unsigned int i=0; i max_coord; - find_max_in_ROI(max, max_coord, image, ROIs[i]); - maxs.push_back(max); - max_coords.push_back(max_coord); - } + for (unsigned int i = 0; i < ROIs.size(); i++) + { + float max; + CartesianCoordinate3D max_coord; + find_max_in_ROI(max, max_coord, image, ROIs[i]); + maxs.push_back(max); + max_coords.push_back(max_coord); + } } void -find_mean_STD_along_lineprofile(float & mean, float & STD, - const VoxelsOnCartesianGrid& image, - char direction, int min_index, int max_index, - const CartesianCoordinate3D& pos) +find_mean_STD_along_lineprofile(float& mean, + float& STD, + const VoxelsOnCartesianGrid& image, + char direction, + int min_index, + int max_index, + const CartesianCoordinate3D& pos) { float sum = 0; float variance = 0; - switch(direction) - { - case 'z': - { - for (int z=min_index; z<=max_index; z++) - { - sum += image[z][pos.y()][pos.x()]; - } - - mean = sum/(max_index-min_index+1); - - for (int z=min_index; z<=max_index; z++) - { - variance += pow((image[z][pos.y()][pos.x()] - mean), 2); - } - - variance /= (max_index-min_index+1); - STD = sqrt(variance); - break; - } - case 'y': + switch (direction) { - for (int y=min_index; y<=max_index; y++) - { - sum += image[pos.z()][y][pos.x()]; + case 'z': { + for (int z = min_index; z <= max_index; z++) + { + sum += image[z][pos.y()][pos.x()]; + } + + mean = sum / (max_index - min_index + 1); + + for (int z = min_index; z <= max_index; z++) + { + variance += pow((image[z][pos.y()][pos.x()] - mean), 2); + } + + variance /= (max_index - min_index + 1); + STD = sqrt(variance); + break; } - - mean = sum/(max_index-min_index+1); - - for (int y=min_index; y<=max_index; y++) - { - variance += pow((image[pos.z()][y][pos.x()] - mean), 2); - } - - variance /= (max_index-min_index+1); - STD = sqrt(variance); - break; - } - case 'x': - { - for (int x=min_index; x<=max_index; x++) - { - sum += image[pos.z()][pos.y()][x]; + case 'y': { + for (int y = min_index; y <= max_index; y++) + { + sum += image[pos.z()][y][pos.x()]; + } + + mean = sum / (max_index - min_index + 1); + + for (int y = min_index; y <= max_index; y++) + { + variance += pow((image[pos.z()][y][pos.x()] - mean), 2); + } + + variance /= (max_index - min_index + 1); + STD = sqrt(variance); + break; } - mean = sum/(max_index-min_index+1); - - for (int x=min_index; x<=max_index; x++) - { - variance += pow((image[pos.z()][pos.y()][x] - mean), 2); + case 'x': { + for (int x = min_index; x <= max_index; x++) + { + sum += image[pos.z()][pos.y()][x]; + } + mean = sum / (max_index - min_index + 1); + + for (int x = min_index; x <= max_index; x++) + { + variance += pow((image[pos.z()][pos.y()][x] - mean), 2); + } + + variance /= (max_index - min_index + 1); + STD = sqrt(variance); + break; } - - variance /= (max_index-min_index+1); - STD = sqrt(variance); - break; } - } } -Succeeded FindRecoveryCoefficient:: -compute() +Succeeded +FindRecoveryCoefficient::compute() { - shared_ptr > - density(read_from_file >(input_filename)); + shared_ptr> density(read_from_file>(input_filename)); - const VoxelsOnCartesianGrid& image = - dynamic_cast&>(*density); + const VoxelsOnCartesianGrid& image = dynamic_cast&>(*density); - ofstream out (output_filename +".txt"); + ofstream out(output_filename + ".txt"); if (!out) - { - warning("Cannot open output file.\n"); - return Succeeded::no; - } + { + warning("Cannot open output file.\n"); + return Succeeded::no; + } vector ROI_maxs; vector> ROI_max_coords; // average over 10 middle slices and save the result in one slice - shared_ptr > average_plane_ptr(image.get_empty_voxels_on_cartesian_grid()); + shared_ptr> average_plane_ptr(image.get_empty_voxels_on_cartesian_grid()); VoxelsOnCartesianGrid average_plane = *average_plane_ptr; info("Computing average plane"); - compute_average_plane_in_given_range(average_plane, image, - min_index_for_average_plane, max_index_for_average_plane); + compute_average_plane_in_given_range(average_plane, image, min_index_for_average_plane, max_index_for_average_plane); info("Done computing average plane"); // draw circular ROIs around each rod with D=2 * rod_d then find max in each ROIs vector ROIs; - float length_z = image.get_voxel_size().z(); + float length_z = image.get_voxel_size().z(); info("Building ROIs"); build_ROIs(ROIs, length_z, ROIs_x, ROIs_y); info("Done building ROIs"); - //find maximum and its corresponding coordinate in ROIs + // find maximum and its corresponding coordinate in ROIs info("Finding max in ROIs"); find_max_in_all_ROIs(ROI_maxs, ROI_max_coords, average_plane, ROIs); info("Done find max in ROIs"); // draw line profiles along the rods on the pixel coordinates with max ROI - //find pixel values along line profiles - //determine mean and standard deviation of the valuse. - out<<"Results of recovery coeficient for "< in_proj_data_ptr = ProjData::read_from_file(argv[2]); - if (strcmp(argv[4], "viewgram")==0) + std::string output_filename = argv[1]; + shared_ptr in_proj_data_ptr = ProjData::read_from_file(argv[2]); + if (strcmp(argv[4], "viewgram") == 0) { const int segment_num = atoi(argv[3]); const int view_num = atoi(argv[5]); - shared_ptr pdi_ptr (in_proj_data_ptr->get_proj_data_info_sptr()->clone()); - std::cout<<"[min_tang_pos, max_tang_pos]=["<get_min_view_num()<<", "<get_max_view_num()<<"]\n"; - if (pdi_ptr->get_num_tangential_poss()/2.==0) - std::cout<<"num_tang_pos is even\n"; + shared_ptr pdi_ptr(in_proj_data_ptr->get_proj_data_info_sptr()->clone()); + std::cout << "[min_tang_pos, max_tang_pos]=[" << pdi_ptr->get_min_view_num() << ", " << pdi_ptr->get_max_view_num() + << "]\n"; + if (pdi_ptr->get_num_tangential_poss() / 2. == 0) + std::cout << "num_tang_pos is even\n"; - if (segment_num get_min_segment_num() || segment_num > in_proj_data_ptr->get_max_segment_num()) + if (segment_num < in_proj_data_ptr->get_min_segment_num() || segment_num > in_proj_data_ptr->get_max_segment_num()) error("segment_num is out of range!\n"); - if (view_num get_min_view_num() || view_num > in_proj_data_ptr->get_max_view_num()) + if (view_num < in_proj_data_ptr->get_min_view_num() || view_num > in_proj_data_ptr->get_max_view_num()) error("view_num is out of range!\n"); SegmentByView segment_by_view = in_proj_data_ptr->get_segment_by_view(segment_num); Viewgram view = segment_by_view.get_viewgram(view_num); std::vector squeezed_view; squeezed_view.reserve(view.get_num_tangential_poss()); - for (int tang = view.get_min_tangential_pos_num(); - tang <= view.get_max_tangential_pos_num(); - ++tang) - { - float sum_bins = 0; - for (int ax = view.get_min_axial_pos_num(); - ax <= view.get_max_axial_pos_num(); - ++ax) + for (int tang = view.get_min_tangential_pos_num(); tang <= view.get_max_tangential_pos_num(); ++tang) { - sum_bins+= view[ax][tang]; + float sum_bins = 0; + for (int ax = view.get_min_axial_pos_num(); ax <= view.get_max_axial_pos_num(); ++ax) + { + sum_bins += view[ax][tang]; + } + squeezed_view.push_back(sum_bins); } - squeezed_view.push_back(sum_bins); - } - std::ofstream out(output_filename+".txt"); - out<<"Values of the squeezed view for segment_num="< output_iterator(out, "\n"); std::copy(squeezed_view.begin(), squeezed_view.end(), output_iterator); return EXIT_SUCCESS; } - else if (strcmp(argv[4], "sinogram")==0) + else if (strcmp(argv[4], "sinogram") == 0) { const int segment_num = atoi(argv[3]); const int axial_pos_num = atoi(argv[5]); - shared_ptr pdi_ptr (in_proj_data_ptr->get_proj_data_info_sptr()->clone()); - std::cout<<"[min_axial_pos, max_axial_pos]=["<get_min_axial_pos_num(segment_num)<<", "<get_max_axial_pos_num(segment_num)<<"]\n"; + shared_ptr pdi_ptr(in_proj_data_ptr->get_proj_data_info_sptr()->clone()); + std::cout << "[min_axial_pos, max_axial_pos]=[" << pdi_ptr->get_min_axial_pos_num(segment_num) << ", " + << pdi_ptr->get_max_axial_pos_num(segment_num) << "]\n"; - if (segment_num get_min_segment_num() || segment_num > in_proj_data_ptr->get_max_segment_num()) + if (segment_num < in_proj_data_ptr->get_min_segment_num() || segment_num > in_proj_data_ptr->get_max_segment_num()) error("segment_num is out of range!\n"); - if (axial_pos_num get_min_axial_pos_num(segment_num) || axial_pos_num > in_proj_data_ptr->get_max_axial_pos_num(segment_num)) + if (axial_pos_num < in_proj_data_ptr->get_min_axial_pos_num(segment_num) + || axial_pos_num > in_proj_data_ptr->get_max_axial_pos_num(segment_num)) error("axial_pos_num is out of range!\n"); SegmentBySinogram segment_by_sino = in_proj_data_ptr->get_segment_by_sinogram(segment_num); Sinogram sino = segment_by_sino.get_sinogram(axial_pos_num); std::vector squeezed_sino; squeezed_sino.reserve(sino.get_num_tangential_poss()); - for (int tang = sino.get_min_tangential_pos_num(); - tang <= sino.get_max_tangential_pos_num(); - ++tang) - { - float sum_bins = 0; - for (int view = sino.get_min_view_num(); - view <= sino.get_max_view_num(); - ++view) + for (int tang = sino.get_min_tangential_pos_num(); tang <= sino.get_max_tangential_pos_num(); ++tang) { - sum_bins+= sino[view][tang]; + float sum_bins = 0; + for (int view = sino.get_min_view_num(); view <= sino.get_max_view_num(); ++view) + { + sum_bins += sino[view][tang]; + } + squeezed_sino.push_back(sum_bins); } - squeezed_sino.push_back(sum_bins); - } - std::ofstream out(output_filename+".txt"); - out<<"Values of the squeezed sino for segment_num="< output_iterator(out, "\n"); std::copy(squeezed_sino.begin(), squeezed_sino.end(), output_iterator); return EXIT_SUCCESS; } - else + else { - cerr<<"\tYou should determine either 'sinogram' or 'viewgram'\n"; - cerr<<"\tUsage: " << argv[0] << " output_filename input_filename segment_number viewgram/simogram view_number/axial_pos_number\n"; - cerr<<"\tviewgram: to calculate sum projection for a viewgram\n"; - cerr<<"\tsinogram: to calculate sum projection for a sinogram\n"; + cerr << "\tYou should determine either 'sinogram' or 'viewgram'\n"; + cerr << "\tUsage: " << argv[0] + << " output_filename input_filename segment_number viewgram/simogram view_number/axial_pos_number\n"; + cerr << "\tviewgram: to calculate sum projection for a viewgram\n"; + cerr << "\tsinogram: to calculate sum projection for a sinogram\n"; exit(EXIT_FAILURE); } } diff --git a/src/utilities/forward_project.cxx b/src/utilities/forward_project.cxx index 3d72be1ea..5f865c348 100644 --- a/src/utilities/forward_project.cxx +++ b/src/utilities/forward_project.cxx @@ -49,51 +49,49 @@ #include #include -static void print_usage_and_exit() +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"; + 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()) + 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) + 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()) @@ -105,18 +103,18 @@ main (int argc, char * argv[]) } shared_ptr forw_projector_sptr; - if (argc>=5) + 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.add_stop_key("END"); parser.parse(argv[4]); } else { - shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); - forw_projector_sptr.reset(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); + shared_ptr PM(new ProjMatrixByBinUsingRayTracing()); + forw_projector_sptr.reset(new ForwardProjectorByBinUsingProjMatrixByBin(PM)); } if (!forw_projector_sptr) { @@ -124,15 +122,12 @@ main (int argc, char * argv[]) return EXIT_FAILURE; } - forw_projector_sptr->set_up(template_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(), - image_density_sptr ); + 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); + 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 a7f7af62d..46343be60 100644 --- a/src/utilities/generate_image.cxx +++ b/src/utilities/generate_image.cxx @@ -23,16 +23,18 @@ /************************ main ************************/ USING_NAMESPACE_STIR -int main(int argc, char * argv[]) +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); + + if (argc != 2) + { + std::cerr << "Usage: " << argv[0] << " par_file\n"; + exit(EXIT_FAILURE); + } + GenerateImage application(argc == 2 ? argv[1] : 0); Succeeded success = application.compute(); application.save_image(); - 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 bda47095e..6bc1049f8 100644 --- a/src/utilities/get_time_frame_info.cxx +++ b/src/utilities/get_time_frame_info.cxx @@ -28,9 +28,11 @@ using std::cout; USING_NAMESPACE_STIR -void print_usage_and_exit(char const * const prog_name) +void +print_usage_and_exit(char const* const prog_name) { - cerr << "Usage:\n" << prog_name << " PARAMETERS\n" + 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" @@ -42,14 +44,14 @@ 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]; + const char* const prog_name = argv[0]; bool units_secs = true; bool only_duration = false; @@ -58,82 +60,85 @@ main(int argc, char* argv[]) bool only_mid_time = false; bool only_num_time_frames = false; - while (argc>=2 && argv[1][1]=='-') + while (argc >= 2 && argv[1][1] == '-') { - if (strcmp(argv[1], "--num-time-frames")==0) - { - only_num_time_frames = true; - --argc; ++argv; - } + 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); - } + { + 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); + 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; + 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) + 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); - } + 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; + 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 @@ -143,23 +148,20 @@ main(int argc, char* argv[]) const int units = units_secs ? 1 : 1000; const std::string units_string = units_secs ? " secs" : " millisecs"; if (only_duration) - cout << frame_duration*units << endl; + cout << frame_duration * units << endl; else if (only_start_time) - cout << start_frame*units << endl; + cout << start_frame * units << endl; else if (only_end_time) - cout << end_frame*units << endl; + cout << end_frame * units << endl; else if (only_end_time) - cout << end_frame*units << endl; + cout << end_frame * units << endl; else if (only_mid_time) - cout << mid_frame*units << endl; + 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; - - + 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 73d5d48f2..7997efb5c --- a/src/utilities/invert_axis.cxx +++ b/src/utilities/invert_axis.cxx @@ -20,34 +20,33 @@ USING_NAMESPACE_STIR -int main(int argc, char **argv) +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); - } + 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::unique_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::unique_ptr> image_aptr(DiscretisedDensity<3, float>::read_from_file(input_filename)); + const std::unique_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 a845837c2..35b5eaab4 100644 --- a/src/utilities/list_ROI_values.cxx +++ b/src/utilities/list_ROI_values.cxx @@ -59,9 +59,8 @@ using std::cerr; using std::endl; using std::ofstream; - START_NAMESPACE_STIR -//TODO repetition of postfilter.cxx to be able to use its .par file +// TODO repetition of postfilter.cxx to be able to use its .par file class ROIValuesParameters : public KeyParser { public: @@ -69,10 +68,11 @@ class ROIValuesParameters : public KeyParser virtual void set_defaults(); virtual void initialise_keymap(); bool post_processing() override; - 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; @@ -85,10 +85,10 @@ ROIValuesParameters::ROIValuesParameters() initialise_keymap(); } -void ROIValuesParameters:: -increment_current_shape_num() +void +ROIValuesParameters::increment_current_shape_num() { - if (!is_null_ptr( current_shape_sptr)) + if (!is_null_ptr(current_shape_sptr)) { shape_ptrs.push_back(current_shape_sptr); shape_names.push_back(current_shape_name); @@ -98,8 +98,7 @@ increment_current_shape_num() } void -ROIValuesParameters:: -set_defaults() +ROIValuesParameters::set_defaults() { shape_ptrs.resize(0); shape_names.resize(0); @@ -107,18 +106,16 @@ set_defaults() 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()); @@ -127,26 +124,25 @@ initialise_keymap() } bool -ROIValuesParameters:: -post_processing() +ROIValuesParameters::post_processing() { assert(shape_names.size() == shape_ptrs.size()); - if (!is_null_ptr( current_shape_sptr)) + if (!is_null_ptr(current_shape_sptr)) { increment_current_shape_num(); } - if (num_samples.z()<=0) + 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) + 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) + if (num_samples.x() <= 0) { warning("number of samples to take in x-direction should be strictly positive\n"); return true; @@ -159,153 +155,143 @@ END_NAMESPACE_STIR USING_NAMESPACE_STIR int -main(int argc, char *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; + 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]; + 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; + 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"; - 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";; - 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); + 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) + 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) { - 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) < 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) + { + ROIValues values; + values = compute_total_ROI_values(*image_ptr, **current_shape_iter, parameters.num_samples); + if (do_filename) + out << std::setw(15) << input_file; + out << std::setw(15) << *current_name_iter << std::setw(15) << values.get_mean() << std::setw(15) + << values.get_stddev(); + if (do_max) + out << std::setw(15) << values.get_max(); + if (do_min) + out << std::setw(15) << values.get_min(); + 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(); diff --git a/src/utilities/list_detector_and_bin_info.cxx b/src/utilities/list_detector_and_bin_info.cxx index 27ddaaeec..f637e5def 100644 --- a/src/utilities/list_detector_and_bin_info.cxx +++ b/src/utilities/list_detector_and_bin_info.cxx @@ -24,7 +24,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 @@ -36,20 +36,20 @@ #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) { @@ -57,17 +57,13 @@ int main(int argc, char *argv[]) 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_max_num_non_arccorrected_bins(), - false) - )); - - + 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_max_num_non_arccorrected_bins(), + false))); { using std::cout; @@ -83,33 +79,25 @@ int main(int argc, char *argv[]) const DetectionPositionPair<> det_pos_pair(DetectionPosition<>(det_num_a, ring_a), DetectionPosition<>(det_num_b, ring_b)); proj_data_info_sptr->get_bin_for_det_pos_pair(bin, det_pos_pair); - cout << "bin: (segment " << bin.segment_num() << ", axial pos " << bin.axial_pos_num() - << ", view = " << bin.view_num() + 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 6cd256e9f..0c0db8d84 100644 --- a/src/utilities/list_image_info.cxx +++ b/src/utilities/list_image_info.cxx @@ -11,9 +11,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. @@ -36,18 +36,20 @@ USING_NAMESPACE_STIR -static void print_usage_and_exit(const std::string& program_name) +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"; + 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[]) +int +main(int argc, char* argv[]) { - const char * const program_name = argv[0]; + const char* const program_name = argv[0]; // skip program name --argc; ++argv; @@ -62,46 +64,53 @@ 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) + 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; - } + 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); + print_usage_and_exit(program_name); } if (no_options) { @@ -111,10 +120,10 @@ int main(int argc, char *argv[]) print_sum = true; } - if(argc!=1) - { - print_usage_and_exit(program_name); - } + if (argc != 1) + { + print_usage_and_exit(program_name); + } // set filename to last remaining argument const std::string filename(argv[0]); @@ -136,24 +145,20 @@ int main(int argc, char *argv[]) if (print_geom) { - BasicCoordinate<3,int> min_indices, max_indices; - auto vox = dynamic_cast &>( image_aptr->get_density(1)); + 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; + 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 + 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 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} :" @@ -170,18 +175,18 @@ int main(int argc, char *argv[]) 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 << "\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 << "\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 3a8074065..c706ee3df 100644 --- a/src/utilities/list_image_values.cxx +++ b/src/utilities/list_image_values.cxx @@ -32,100 +32,94 @@ #include #include - - USING_NAMESPACE_STIR -const char * prog_name; +const char* prog_name; -void print_usage_and_exit() +void +print_usage_and_exit() { - std::cerr << "Usage:\n" << prog_name << " \\\n" + 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)) + 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) + 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; + ++argv; + --argc; } - - if (argc!= 9) + + 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]); - using std::setw; + std::ofstream profile_file(output_filename); - const char separator = print_csv ? ',' : ' ' ; + 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'; + 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'; + 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'; - } - + 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 81b9170db..6a9601821 100644 --- a/src/utilities/list_projdata_info.cxx +++ b/src/utilities/list_projdata_info.cxx @@ -34,23 +34,25 @@ #include "stir/SegmentByView.h" #include "stir/is_null_ptr.h" #include "stir/warning.h" -#include +#include #include #include USING_NAMESPACE_STIR -void print_usage_and_exit(const std::string& program_name) +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"; + 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; @@ -64,49 +66,55 @@ 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) + 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; - } + 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); + print_usage_and_exit(program_name); } if (no_options) print_geom = true; - if(argc!=1) - { - print_usage_and_exit(program_name); - } + if (argc != 1) + { + print_usage_and_exit(program_name); + } // set filename to last remaining argument const std::string filename(argv[0]); @@ -125,37 +133,40 @@ int main(int argc, char *argv[]) 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(); 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(); 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.; + 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 timing_num = min_timing_num; timing_num <= max_timing_num; ++timing_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) + { 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; - } + 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; - } - } - } + { + 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; if (print_max) @@ -163,6 +174,6 @@ int main(int argc, char *argv[]) if (print_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 1954e9c8b..daaef9821 100644 --- a/src/utilities/manip_image.cxx +++ b/src/utilities/manip_image.cxx @@ -10,9 +10,9 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup utilities - + \brief This program performs operations on image data \author Matthew Jacobson @@ -33,8 +33,7 @@ #include "stir/ArrayFunction.h" #include "stir/zoom.h" - -#include +#include #include #include #include @@ -52,353 +51,366 @@ 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++){ + 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; - } - } - } + 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[]) +int +main(int argc, char* argv[]) { - // file input - VoxelsOnCartesianGrid main_buffer; - if(argc>1) + // file input + VoxelsOnCartesianGrid main_buffer; + if (argc > 1) { - main_buffer= - * dynamic_cast *>( - DiscretisedDensity<3,float>::read_from_file(argv[1])); + main_buffer = *dynamic_cast*>(DiscretisedDensity<3, float>::read_from_file(argv[1])); } - else { - cerr< (*.hv)"< (*.hv)" << endl << endl; + main_buffer = ask_interfile_image("File to load in main buffer? "); } - int zs,ys,xs, ze,ye,xe,choice; + 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(); + zs = main_buffer.get_min_z(); + ys = main_buffer.get_min_y(); + xs = main_buffer.get_min_x(); - cerr<<"resx: "<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 1: // display + { + const float maxi = ask_num("Maximum in color scale", 0.F, main_buffer.find_max(), main_buffer.find_max()); - case 5: // min-max image - { - cerr << "Min and Max in image " << main_buffer.find_min() - << " " << main_buffer.find_max() << endl; + switch (ask_num("transaxial (0), coronal (1), sagital (2)", 0, 2, 0)) + { + case 0: + display(main_buffer, maxi); break; - } - - case 6: // trim - { - trim_edges(main_buffer); + case 1: + display(transpose_12(main_buffer), maxi); break; - } - - case 7: // get plane - { - get_plane(main_buffer); + case 2: + display(transpose_13(main_buffer), maxi); break; - } + } + break; + } + case 2: // data total + { + for (int z = zs; z <= ze; z++) + for (int y = ys; y <= ye; y++) + for (int x = xs; x <= xe; x++) + cerr << main_buffer[z][y][x] << " "; + break; + } + + case 3: // data plane-wise + { + plane = 1; + + while (plane > 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 << main_buffer[zs + plane - 1][y][x] << " "; // pause + } + break; + } - case 8: // get row - { - get_plane_row(main_buffer); - break; - } + case 4: // min-max, counts plane-wise + { + plane = 1; - case 9: // counts - { - cerr< 0 && plane <= ze - zs + 1) + { + plane = ask_num("Input plane # (0 to exit)", 0, ze - zs + 1, zs); - case 11: //reload buffer from main menu - { - main_buffer = ask_interfile_image("File to load in buffer? "); - break; - } - - case 12: // buffer to file - { - char outfile[max_filename_length]; - ask_filename_with_extension(outfile, "Output filename (without extension) ", ""); - write_to_file(outfile, main_buffer); - break; - } + if (plane == 0) + break; - case 13: // remove nan values - { - char outfile[max_filename_length]; - VoxelsOnCartesianGrid& 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; - } + 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 << endl << "The number of counts is: " << main_buffer.sum() << endl; + break; + } + + case 10: // math mode + { + math_mode(main_buffer, quit_from_math); + break; + } + + case 11: // reload buffer from main menu + { + main_buffer = ask_interfile_image("File to load in buffer? "); + break; + } + + case 12: // buffer to file + { + char outfile[max_filename_length]; + ask_filename_with_extension(outfile, "Output filename (without extension) ", ""); + write_to_file(outfile, main_buffer); + break; + } + + case 13: // remove nan values + { + char outfile[max_filename_length]; + VoxelsOnCartesianGrid& 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(); - case 14: show_menu(); - } // end switch main mode - } while(choice>0 && choice<=13 && (!quit_from_math)); - return EXIT_SUCCESS; + } while (choice > 0 && choice <= 13 && (!quit_from_math)); + return EXIT_SUCCESS; } -void trim_edges(VoxelsOnCartesianGrid& input_image) +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); + 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); + truncate_rim(input_image, rim_trunc); - if(ask("Zero end planes?",false)) truncate_end_planes(input_image); + if (ask("Zero end planes?", false)) + truncate_end_planes(input_image); } -void get_plane(VoxelsOnCartesianGrid& input_image) +void +get_plane(VoxelsOnCartesianGrid& input_image) { - int zs,ys,xs, ze,ye,xe; + 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(); - 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(); + ze = input_image.get_max_z(); + ye = input_image.get_max_y(); + xe = input_image.get_max_x(); - const int zm=(ze+zs)/2; + const int zm = (ze + zs) / 2; - int plane=ask_num("Which plane?",1,ze-zs+1,(int)zm-zs+1); + 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); + 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) +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(); - - 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< ask_interfile_image(const char *const input_query) +VoxelsOnCartesianGrid +ask_interfile_image(const char* const input_query) { - char filename[max_filename_length]; + char filename[max_filename_length]; - ask_filename_with_extension(filename, input_query, ".hv"); - - shared_ptr > - image_ptr(read_from_file >(filename)); - return - * dynamic_cast*>(image_ptr.get()); + ask_filename_with_extension(filename, input_query, ".hv"); + shared_ptr> image_ptr(read_from_file>(filename)); + return *dynamic_cast*>(image_ptr.get()); } - -void show_menu() +void +show_menu() { - cerr<<"\n\ + cerr << "\n\ MAIN MODE:\n\ 0. Quit\n\ 1. Display image\n\ @@ -414,11 +426,13 @@ 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) +void +math_mode(VoxelsOnCartesianGrid& 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; - } + VoxelsOnCartesianGrid math_buffer = main_buffer; // initialize math buffer + int operation; - 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; - } + show_math_menu(); - 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; - } + do + { + operation = ask_num("Choose Operation: ", 0, 16, 15); - case 15: //redisplay menu - { - show_math_menu(); - break; - } + switch (operation) + { // math mode + case 0: // quit + { + quit_from_math = 1; + break; + } - case 16: //go back to main mode - { - show_menu(); - } + 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; + + break; + } + + case 3: // image addition + { + VoxelsOnCartesianGrid 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 << 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(); + } } // end switch math mode - } while(operation>0 && operation<16); + } while (operation > 0 && operation < 16); } diff --git a/src/utilities/manip_projdata.cxx b/src/utilities/manip_projdata.cxx index 9aff4a72a..182571678 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
        */ /* @@ -29,8 +29,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" @@ -38,7 +36,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" @@ -47,204 +45,246 @@ This utility programme processes (interfile) sinogram data #include "stir/is_null_ptr.h" #include -#include -#include +#include +#include using std::cerr; using std::endl; using std::fstream; - - 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 make_buffer_header(const char *data_filename,const char *header_filename, - ProjData& input_sino, int limit_segments, - NumericType::Type output_type=NumericType::FLOAT); +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 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) +void +do_math(enum options operation, + SegmentByView& sino1, + SegmentByView& sino2, + float& accum_max, + float& accum_min, + float& accum_sum, + bool accumulators_initialized) { - switch(operation) + 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; + 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; } - else { - if (accum_maxsino1.find_min()) accum_min= sino1.find_min(); - accum_sum+=sino1.sum(); + + case _add_sino: { // sinogram addition + sino1 += sino2; + break; } - 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 + + 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 } - -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) +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); - } - break; + 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); + } + 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 _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 _div_scalar: { // scalar division + sino1 /= scalar; + break; } - case _add_scalar: { //scalar addition - 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(); + } + break; } - case _mult_scalar: { //scalar multiplication - sino1*=scalar; - break; + case _pos_ind: { + in_place_apply_function(sino1, pos_indicate); // positive indicator + break; } - case _div_scalar: { //scalar division - sino1/=scalar; - break; + case _trim: { + truncate_rim(sino1, (int)scalar); // trim rim + 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 _trunc_neg: { + in_place_apply_function(sino1, neg_trunc); + 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 + + // 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) +shared_ptr +ask_proj_data(const char* const input_query) { - char filename[max_filename_length]; + char filename[max_filename_length]; - //system("ls *hs"); - ask_filename_with_extension(filename, input_query, ".hs"); + // system("ls *hs"); + ask_filename_with_extension(filename, input_query, ".hs"); - return - ProjData::read_from_file(filename); + 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\ @@ -266,145 +306,149 @@ 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; + return (x > 0.0) ? 1.0F : 0.0F; } END_NAMESPACE_STIR //********************** main - - USING_NAMESPACE_STIR - -int main(int argc, char *argv[]) +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)) - { - - 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)"<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; + 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)) + { + + 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 << endl << "Usage: manip_projdata
        (*.hs)" << endl << endl; + first_operand = ask_proj_data("Input sinogram"); + } + else + first_operand = ProjData::read_from_file(argv[1]); - 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 + 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; + + 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; + 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 + + 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; + + 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; - } + shared_ptr second_operand; + float* scalar = NULL; - 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; + 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; } - 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 ); + 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 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 @@ -436,100 +480,105 @@ 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); + 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_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; - 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); + first_operand = ProjData::read_from_file(output_buffer_header); } -//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< 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"; + 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[]) +main(int argc, char* argv[]) { - if(argc<5) - { - usage(); - return(EXIT_FAILURE); - } - + if (argc < 5) + { + usage(); + 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; + if (strcmp(argv[1], "-p") == 0 || strcmp(argv[1], "--preserve-mean") == 0) + preserve_mean = true; else - { - usage(); - return(EXIT_FAILURE); - } + { + usage(); + return (EXIT_FAILURE); + } ++argv; } - - const char *const filename = argv[1]; + + 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 972a24c95..0f4ea1f77 100644 --- a/src/utilities/postfilter.cxx +++ b/src/utilities/postfilter.cxx @@ -12,26 +12,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. @@ -40,9 +38,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:= @@ -70,70 +68,68 @@ #include "stir/Succeeded.h" #include "stir/warning.h" #include "stir/error.h" -#include +#include using std::cerr; using std::endl; - 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) + +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(); + 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) +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; + 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) +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); + 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 @@ -141,84 +137,93 @@ 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 }; + 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]=='-') + while (argc > 1 && argv[1][0] == '-') { if (strcmp(argv[1], "--verbose") == 0) - { - verbose = true; - --argc; ++argv; - } + { + verbose = true; + --argc; + ++argv; + } else if (strcmp(argv[1], "--dynamic") == 0) { image_type = dynamic; - --argc; ++argv; + --argc; + ++argv; } else if (strcmp(argv[1], "--parametric") == 0) { image_type = parametric; - --argc; ++argv; + --argc; + ++argv; } else - { - print_usage(); - return EXIT_FAILURE; - } + { + print_usage(); + return EXIT_FAILURE; + } } - if (argc<4 || argc>5) + if (argc < 4 || argc > 5) { print_usage(); return EXIT_FAILURE; } - if (argc>1) + if (argc > 1) { out_filename = argv[1]; } else { char outfile[max_filename_length]; - ask_filename_with_extension(outfile, - "Output to which file: ", ""); + ask_filename_with_extension(outfile, "Output to which file: ", ""); out_filename = outfile; } - if (argc>2) + if (argc > 2) { input_filename = argv[2]; } - if (argc>3) + if (argc > 3) { if (post_filtering.parse(argv[3]) == false) - { - warning("postfilter aborting because error in parsing. Not writing any output"); - return EXIT_FAILURE; - } + { + 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); - + "Possible values:\n"; + DataProcessor>::list_registered_names(cerr); + post_filtering.ask_parameters(); } - if (argc>4) + if (argc > 4) { output_file_format_par = argv[4]; } @@ -231,14 +236,11 @@ main(int argc, char *argv[]) // 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) { @@ -248,28 +250,33 @@ main(int argc, char *argv[]) // Post filter! stir::Succeeded success(Succeeded::yes); if (image_type == normal) - 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 = 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; - } - } - } - 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) { + } + } + } + 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); - } - } + } + 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) @@ -281,5 +288,3 @@ main(int argc, char *argv[]) return EXIT_SUCCESS; } - - diff --git a/src/utilities/rebin_projdata.cxx b/src/utilities/rebin_projdata.cxx index a65379f0a..62a516cb8 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 @@ -30,14 +30,13 @@ 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 "stir/warning.h" #include "stir/error.h" -#include +#include using std::cerr; using std::endl; @@ -48,85 +47,71 @@ START_NAMESPACE_STIR 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: void set_defaults() override; void initialise_keymap() override; bool post_processing() override; - }; -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() +RebinProjDataParameters::post_processing() { if (is_null_ptr(proj_data_rebinning_sptr)) - { - warning("Invalid rebinning object\n"); - return true; - } + { + warning("Invalid rebinning object\n"); + return true; + } 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; - } - RebinProjDataParameters parameters( argc==2 ? argv[1] : 0); - - if (argc!=2) + 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; + cerr << "Corresponding .par file input \n" << parameters.parameter_info() << endl; } - return - parameters.proj_data_rebinning_sptr->rebin() == Succeeded::yes? - EXIT_SUCCESS: EXIT_FAILURE; + return parameters.proj_data_rebinning_sptr->rebin() == Succeeded::yes ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/utilities/separate_true_from_random_scatter_for_necr.cxx b/src/utilities/separate_true_from_random_scatter_for_necr.cxx index 0600f3269..e2b3d55df 100644 --- a/src/utilities/separate_true_from_random_scatter_for_necr.cxx +++ b/src/utilities/separate_true_from_random_scatter_for_necr.cxx @@ -5,7 +5,7 @@ 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, @@ -18,9 +18,9 @@ limitations under the License. \file \ingroup utilities - \brief This program gets a projection data file of a mouse/rat scatter phantom measured according to NEMA NU 4. + \brief This program gets a projection data file of a mouse/rat scatter phantom measured according to NEMA NU 4. It seperates number of true events from number of random+scatter events. - + \author Parisa Khateri */ @@ -41,260 +41,242 @@ limitations under the License. #include #include "stir/error.h" - - using std::cerr; USING_NAMESPACE_STIR -int find_num_tang_pos_for_FOV(float a, float r, int n) -{ //if r is radius, s is length of arc, a is length of chord, and n is number of azimuthal angles (num_detectors_per_ring) - float theta = asin((a/2.)/r); // the azimuthal angle (in radian) covered by the FOV in cylindrical geometry - float delta = 2*_PI/n;// the azimuthal angle covered by a detector element in cylindrical geometry - return int(round(2*theta/delta)); +int +find_num_tang_pos_for_FOV(float a, float r, int n) +{ // if r is radius, s is length of arc, a is length of chord, and n is number of azimuthal angles (num_detectors_per_ring) + float theta = asin((a / 2.) / r); // the azimuthal angle (in radian) covered by the FOV in cylindrical geometry + float delta = 2 * _PI / n; // the azimuthal angle covered by a detector element in cylindrical geometry + return int(round(2 * theta / delta)); } -float find_length_of_arc_for_FOV(float a, float r) -{ //if r is radius, s is length of arc and a is length of chord +float +find_length_of_arc_for_FOV(float a, float r) +{ // if r is radius, s is length of arc and a is length of chord // s = r * theta // theta = 2* asin(a/2/r) - float theta = 2*asin((a/2.)/r); // the azimuthal angle (in radian) covered by the FOV in cylindrical geometry - float s = r * theta; //length of arc + float theta = 2 * asin((a / 2.) / r); // the azimuthal angle (in radian) covered by the FOV in cylindrical geometry + float s = r * theta; // length of arc return s; } -int main(int argc, char *argv[]) +int +main(int argc, char* argv[]) { - if(argc<5) + if (argc < 5) { - cerr<<"\tUsage: " << argv[0] << " output_filename input_filename phantom_diameter single/all [axial_pos_number]\n"; - cerr<<"\tchoose single to calculate sum of the rows of a single sinogram. axial_pos_number is required for this option.\n"; - cerr<<"\tchoose all to calculate sum of the sum of the rows of all sinograms\n"; - cerr<<"\tthe input projection data should have already been processed by SSRB.\n"; + cerr << "\tUsage: " << argv[0] << " output_filename input_filename phantom_diameter single/all [axial_pos_number]\n"; + cerr + << "\tchoose single to calculate sum of the rows of a single sinogram. axial_pos_number is required for this option.\n"; + cerr << "\tchoose all to calculate sum of the sum of the rows of all sinograms\n"; + cerr << "\tthe input projection data should have already been processed by SSRB.\n"; exit(EXIT_FAILURE); } - std::string output_filename=argv[1]; - shared_ptr in_proj_data_ptr = ProjData::read_from_file(argv[2]); - const float phantom_diameter = atof(argv[3]); - const int segment_num = 0; + std::string output_filename = argv[1]; + shared_ptr in_proj_data_ptr = ProjData::read_from_file(argv[2]); + const float phantom_diameter = atof(argv[3]); + const int segment_num = 0; - if (strcmp(argv[4], "single")==0 && argc==6 ) + if (strcmp(argv[4], "single") == 0 && argc == 6) { const int axial_pos_num = atoi(argv[5]); - shared_ptr pdi_ptr (in_proj_data_ptr->get_proj_data_info_sptr()->clone()); + shared_ptr pdi_ptr(in_proj_data_ptr->get_proj_data_info_sptr()->clone()); - if (axial_pos_num get_min_axial_pos_num(segment_num) || axial_pos_num > in_proj_data_ptr->get_max_axial_pos_num(segment_num)) + if (axial_pos_num < in_proj_data_ptr->get_min_axial_pos_num(segment_num) + || axial_pos_num > in_proj_data_ptr->get_max_axial_pos_num(segment_num)) error("axial_pos_num is out of range!\n"); SegmentBySinogram segment_by_sino = in_proj_data_ptr->get_segment_by_sinogram(segment_num); Sinogram sino = segment_by_sino.get_sinogram(axial_pos_num); - //find max index in each row of sinogram and shift - Sinogram shifted_sino = in_proj_data_ptr->get_empty_sinogram(axial_pos_num,segment_num); - for (int view = sino.get_min_view_num(); - view <= sino.get_max_view_num(); - ++view) - { - float max=0; - int max_idx=0; - - //find max index in each row of sinogram - for (int tang = sino.get_min_tangential_pos_num(); - tang <= sino.get_max_tangential_pos_num(); - ++tang) + // find max index in each row of sinogram and shift + Sinogram shifted_sino = in_proj_data_ptr->get_empty_sinogram(axial_pos_num, segment_num); + for (int view = sino.get_min_view_num(); view <= sino.get_max_view_num(); ++view) { - if (max squeezed_sino; squeezed_sino.reserve(sino.get_num_tangential_poss()); - for (int tang = sino.get_min_tangential_pos_num(); - tang <= sino.get_max_tangential_pos_num(); - ++tang) - { - float sum_bins = 0; - for (int view = sino.get_min_view_num(); - view <= sino.get_max_view_num(); - ++view) + for (int tang = sino.get_min_tangential_pos_num(); tang <= sino.get_max_tangential_pos_num(); ++tang) { - sum_bins+= shifted_sino[view][tang]; + float sum_bins = 0; + for (int view = sino.get_min_view_num(); view <= sino.get_max_view_num(); ++view) + { + sum_bins += shifted_sino[view][tang]; + } + squeezed_sino.push_back(sum_bins); } - squeezed_sino.push_back(sum_bins); - } - std::ofstream out(output_filename+".txt"); - out<<"Values of the squeezed sino for segment_num="< output_iterator(out, "\n"); std::copy(squeezed_sino.begin(), squeezed_sino.end(), output_iterator); return EXIT_SUCCESS; - } - if (strcmp(argv[4], "all")==0 && argc==5 ) + if (strcmp(argv[4], "all") == 0 && argc == 5) { - shared_ptr pdi_ptr (in_proj_data_ptr->get_proj_data_info_sptr()->clone()); + shared_ptr pdi_ptr(in_proj_data_ptr->get_proj_data_info_sptr()->clone()); // keep sinograms out of the loop to avoid reallocations // initialise to something because there's no default constructor - Sinogram sino = - in_proj_data_ptr->get_empty_sinogram(in_proj_data_ptr->get_min_axial_pos_num(segment_num),segment_num); - Sinogram shifted_sino = - in_proj_data_ptr->get_empty_sinogram(in_proj_data_ptr->get_min_axial_pos_num(segment_num),segment_num); + Sinogram sino + = in_proj_data_ptr->get_empty_sinogram(in_proj_data_ptr->get_min_axial_pos_num(segment_num), segment_num); + Sinogram shifted_sino + = in_proj_data_ptr->get_empty_sinogram(in_proj_data_ptr->get_min_axial_pos_num(segment_num), segment_num); std::vector squeezed_sino_all(in_proj_data_ptr->get_num_tangential_poss(), 0.0); for (int axial_pos_num = pdi_ptr->get_min_axial_pos_num(segment_num); - axial_pos_num <= pdi_ptr->get_max_axial_pos_num(segment_num); - ++axial_pos_num) - { - sino = in_proj_data_ptr->get_sinogram(axial_pos_num, segment_num); - shifted_sino = in_proj_data_ptr->get_empty_sinogram(axial_pos_num,segment_num); - - //find max index in each row of sinogram and shift - for (int view = sino.get_min_view_num(); - view <= sino.get_max_view_num(); - ++view) + axial_pos_num <= pdi_ptr->get_max_axial_pos_num(segment_num); + ++axial_pos_num) { - float max=0; - int max_idx=0; - - //find max index in each row of sinogram - for (int tang = sino.get_min_tangential_pos_num(); - tang <= sino.get_max_tangential_pos_num(); - ++tang) - { - if (maxget_sinogram(axial_pos_num, segment_num); + shifted_sino = in_proj_data_ptr->get_empty_sinogram(axial_pos_num, segment_num); + + // find max index in each row of sinogram and shift + for (int view = sino.get_min_view_num(); view <= sino.get_max_view_num(); ++view) { - max=sino[view][tang]; - max_idx=tang; + float max = 0; + int max_idx = 0; + + // find max index in each row of sinogram + for (int tang = sino.get_min_tangential_pos_num(); tang <= sino.get_max_tangential_pos_num(); ++tang) + { + if (max < sino[view][tang]) + { + max = sino[view][tang]; + max_idx = tang; + } + } + /*Shift the bins in each row of sinogram so that the maximum stays in the centre + because the middle bin in each row of the sinogram corresponds to tang_pos=0 + tang_shifted = tang - (tang_max - tang_center) + tang_center = 0 + tang_shifted = tang - tang_max + */ + for (int tang = sino.get_min_tangential_pos_num(); tang <= sino.get_max_tangential_pos_num(); ++tang) + { + int shifted_tang = tang - max_idx; + if ((shifted_tang) < sino.get_min_tangential_pos_num()) + shifted_tang = tang + sino.get_num_tangential_poss() - max_idx; + if ((shifted_tang) > sino.get_max_tangential_pos_num()) + shifted_tang = tang - sino.get_num_tangential_poss() - max_idx; + assert(shifted_tang >= sino.get_min_tangential_pos_num() && shifted_tang <= sino.get_max_tangential_pos_num()); + shifted_sino[view][shifted_tang] = sino[view][tang]; + } } - } - /*Shift the bins in each row of sinogram so that the maximum stays in the centre - because the middle bin in each row of the sinogram corresponds to tang_pos=0 - tang_shifted = tang - (tang_max - tang_center) - tang_center = 0 - tang_shifted = tang - tang_max - */ - for (int tang = sino.get_min_tangential_pos_num(); - tang <= sino.get_max_tangential_pos_num(); - ++tang) - { - int shifted_tang = tang - max_idx; - if ( (shifted_tang)sino.get_max_tangential_pos_num()) - shifted_tang= tang - sino.get_num_tangential_poss() - max_idx; - assert(shifted_tang>=sino.get_min_tangential_pos_num() && shifted_tang<=sino.get_max_tangential_pos_num()); - shifted_sino[view][shifted_tang]=sino[view][tang]; - } - } - - //sum over the shifted rows in sinograms - for (int tang = sino.get_min_tangential_pos_num(); - tang <= sino.get_max_tangential_pos_num(); - ++tang) - { - float sum_bins = 0; - for (int view = sino.get_min_view_num(); - view <= sino.get_max_view_num(); - ++view) - { - sum_bins+= shifted_sino[view][tang]; - } - assert(tang+sino.get_max_tangential_pos_num()+1>=0 && tang+sino.get_max_tangential_pos_num()+1= 0 + && tang + sino.get_max_tangential_pos_num() + 1 < squeezed_sino_all.size()); + squeezed_sino_all[tang + sino.get_max_tangential_pos_num() + 1] += sum_bins; + } } - } - std::ofstream out(output_filename+".txt"); - out<<"Values of the squeezed sino for segment_num\n"; + std::ofstream out(output_filename + ".txt"); + out << "Values of the squeezed sino for segment_num\n"; std::ostream_iterator output_iterator(out, "\n"); std::copy(squeezed_sino_all.begin(), squeezed_sino_all.end(), output_iterator); - //trim sino with 8mm band around the phantom according to NEMA NU4 - int num_tang_pos_for_FOV = find_num_tang_pos_for_FOV(phantom_diameter+16, //16 means 8 mm from each side of the sinogram - pdi_ptr->get_scanner_ptr()->get_inner_ring_radius(), - pdi_ptr->get_scanner_ptr()->get_num_detectors_per_ring()); + // trim sino with 8mm band around the phantom according to NEMA NU4 + int num_tang_pos_for_FOV = find_num_tang_pos_for_FOV(phantom_diameter + 16, // 16 means 8 mm from each side of the sinogram + pdi_ptr->get_scanner_ptr()->get_inner_ring_radius(), + pdi_ptr->get_scanner_ptr()->get_num_detectors_per_ring()); int n = sino.get_max_tangential_pos_num() - num_tang_pos_for_FOV; // total number of tang pos to trim - squeezed_sino_all.erase(squeezed_sino_all.begin(),squeezed_sino_all.begin()+n/2+1); - squeezed_sino_all.erase(squeezed_sino_all.end()-n/2,squeezed_sino_all.end()); + squeezed_sino_all.erase(squeezed_sino_all.begin(), squeezed_sino_all.begin() + n / 2 + 1); + squeezed_sino_all.erase(squeezed_sino_all.end() - n / 2, squeezed_sino_all.end()); - std::ofstream out_trimmed(output_filename+"_trimmed.txt"); - out_trimmed<<"Values of the squeezed sino for segment_num\n"; + std::ofstream out_trimmed(output_filename + "_trimmed.txt"); + out_trimmed << "Values of the squeezed sino for segment_num\n"; std::ostream_iterator output_iterator_trimmed(out_trimmed, "\n"); std::copy(squeezed_sino_all.begin(), squeezed_sino_all.end(), output_iterator_trimmed); + // find bin value at 7 mm from center according to NEMA NU4 + float length_of_arc_for_14mm = find_length_of_arc_for_FOV(14, // 7 mm from center to both sides + pdi_ptr->get_scanner_ptr()->get_inner_ring_radius()); - //find bin value at 7 mm from center according to NEMA NU4 - float length_of_arc_for_14mm = find_length_of_arc_for_FOV(14, //7 mm from center to both sides - pdi_ptr->get_scanner_ptr()->get_inner_ring_radius()); - - int idx_mid = squeezed_sino_all.size()/2; - float delta_unit = length_of_arc_for_14mm/2.2; + int idx_mid = squeezed_sino_all.size() / 2; + float delta_unit = length_of_arc_for_14mm / 2.2; // delta_unit-1/2 is number of bins from each side of central bin - float fraction1 = delta_unit/2 - floor(delta_unit/2); - float fraction2 = ceil(delta_unit/2) - delta_unit/2; + float fraction1 = delta_unit / 2 - floor(delta_unit / 2); + float fraction2 = ceil(delta_unit / 2) - delta_unit / 2; - assert(idx_mid-floor(delta_unit/2)>=0 && idx_mid-floor(delta_unit/2)=0 && idx_mid+floor(delta_unit/2)=0 && idx_mid-ceil(delta_unit/2)=0 && idx_mid+ceil(delta_unit/2)= 0 && idx_mid - floor(delta_unit / 2) < squeezed_sino_all.size()); + assert(idx_mid + floor(delta_unit / 2) >= 0 && idx_mid + floor(delta_unit / 2) < squeezed_sino_all.size()); + assert(idx_mid - ceil(delta_unit / 2) >= 0 && idx_mid - ceil(delta_unit / 2) < squeezed_sino_all.size()); + assert(idx_mid + ceil(delta_unit / 2) >= 0 && idx_mid + ceil(delta_unit / 2) < squeezed_sino_all.size()); - float c_left = ( fraction1*squeezed_sino_all[idx_mid - floor(delta_unit/2)] - + fraction2*squeezed_sino_all[idx_mid - ceil(delta_unit/2)] ); - float c_right = ( fraction1*squeezed_sino_all[idx_mid + floor(delta_unit/2)] - + fraction2*squeezed_sino_all[idx_mid + ceil(delta_unit/2)] ); - float random_and_scatter_inside_14mm = (c_right + c_left) * ceil(delta_unit) /2; + float c_left = (fraction1 * squeezed_sino_all[idx_mid - floor(delta_unit / 2)] + + fraction2 * squeezed_sino_all[idx_mid - ceil(delta_unit / 2)]); + float c_right = (fraction1 * squeezed_sino_all[idx_mid + floor(delta_unit / 2)] + + fraction2 * squeezed_sino_all[idx_mid + ceil(delta_unit / 2)]); + float random_and_scatter_inside_14mm = (c_right + c_left) * ceil(delta_unit) / 2; float random_and_scatter_outside_14mm = 0; - for (int idx = idx_mid + ceil(delta_unit/2); idx7) { - 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); - } - + 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) ; - } - 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]) + 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]) + 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 4b5991e2a..95468c88b 100644 --- a/src/utilities/shift_image_origin.cxx +++ b/src/utilities/shift_image_origin.cxx @@ -1,13 +1,13 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup utilities \brief This program shifts the origin of an image. \author Charalampos Tsoumpas @@ -20,37 +20,32 @@ using std::cerr; USING_NAMESPACE_STIR - -int main(int argc, char **argv) +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); - } - + 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_config.cxx b/src/utilities/stir_config.cxx index a8579f303..081f281e0 100644 --- a/src/utilities/stir_config.cxx +++ b/src/utilities/stir_config.cxx @@ -1,5 +1,5 @@ /*! - + Copyright (C) 2021, National Physical Laboratory Copyright (C) 2022, 2023 University College London This file is part of STIR. @@ -10,42 +10,44 @@ \file \ingroup utilities \brief Prints configuration directory and STIR version - + \author Daniel Deidda \author Kris Thielemans */ -#include "stir/find_STIR_config.h" +#include "stir/find_STIR_config.h" #include #include USING_NAMESPACE_STIR int -main(int argc, char *argv[]) +main(int argc, char* argv[]) { - if(argc==1) + if (argc == 1) { - std::cerr<<"\nUsage: " << "stir_config" - << " [--config-dir] [--doc-dir] [--examples-dir] [--version]\n\n" - << "Each option will result in the corresponding text to be written on a separate line," - << "(in the same order as the options)\n" - << "--config-dir: directory where STIR will read its configuration files.\n" - << "--doc-dir: directory with installed STIR documentation.\n" - << "--examples-dir: directory with installed STIR examples.\n" - << "--version: version of STIR you are using.\n"<1) + + while (argc > 1) { - if(strcmp(argv[1],"--config-dir")==0) + if (strcmp(argv[1], "--config-dir") == 0) std::cout << get_STIR_config_dir() << std::endl; - else if(strcmp(argv[1],"--doc-dir")==0) + else if (strcmp(argv[1], "--doc-dir") == 0) std::cout << get_STIR_doc_dir() << std::endl; - else if(strcmp(argv[1],"--examples-dir")==0) + else if (strcmp(argv[1], "--examples-dir") == 0) std::cout << get_STIR_examples_dir() << std::endl; - else if(strcmp(argv[1],"--version")==0) + else if (strcmp(argv[1], "--version") == 0) std::cout << STIR_VERSION_STRING << std::endl; else { diff --git a/src/utilities/stir_list_registries.cxx b/src/utilities/stir_list_registries.cxx index dc5ecfd90..602ab4adf 100644 --- a/src/utilities/stir_list_registries.cxx +++ b/src/utilities/stir_list_registries.cxx @@ -1,5 +1,5 @@ /*! - + Copyright (C) 2024 University College London This file is part of STIR. @@ -9,7 +9,7 @@ \file \ingroup utilities \brief Prints all registered names for many registries - + \author Kris Thielemans */ @@ -17,8 +17,8 @@ #include "stir/modelling/ParametricDiscretisedDensity.h" #include "stir/DynamicDiscretisedDensity.h" #include "stir/DataProcessor.h" -#include "stir/recon_buildblock/ForwardProjectorByBin.h" -#include "stir/recon_buildblock/BackProjectorByBin.h" +#include "stir/recon_buildblock/ForwardProjectorByBin.h" +#include "stir/recon_buildblock/BackProjectorByBin.h" #include "stir/recon_buildblock/ProjectorByBinPair.h" #include "stir/recon_buildblock/ProjMatrixByBin.h" #include "stir/recon_buildblock/GeneralisedObjectiveFunction.h" @@ -31,7 +31,7 @@ USING_NAMESPACE_STIR int -main(int argc, char *argv[]) +main(int argc, char* argv[]) { std::cout << "------------ ProjectorByBinPair --------------\n"; ProjectorByBinPair::list_registered_names(std::cout); @@ -44,28 +44,27 @@ main(int argc, char *argv[]) std::cout << "------------ BinNormalisation --------------\n"; BinNormalisation::list_registered_names(std::cout); - std::cout << "--------------------------------------------------------------------------\n"; - + std::cout << "--------------------------------------------------------------------------\n"; + std::cout << "------------ DataProcessor> --------------\n"; - DataProcessor >::list_registered_names(std::cout); + DataProcessor>::list_registered_names(std::cout); std::cout << "------------ GeneralisedObjectiveFunction> --------------\n"; - GeneralisedObjectiveFunction>::list_registered_names(std::cout); + GeneralisedObjectiveFunction>::list_registered_names(std::cout); std::cout << "------------ GeneralisedPrior> --------------\n"; - GeneralisedPrior>::list_registered_names(std::cout); + GeneralisedPrior>::list_registered_names(std::cout); std::cout << "------------ Reconstruction> --------------\n"; - Reconstruction>::list_registered_names(std::cout); + Reconstruction>::list_registered_names(std::cout); - std::cout << "--------------------------------------------------------------------------\n"; + std::cout << "--------------------------------------------------------------------------\n"; std::cout << "------------ DataProcessor --------------\n"; - DataProcessor::list_registered_names(std::cout); + DataProcessor::list_registered_names(std::cout); std::cout << "------------ GeneralisedObjectiveFunction --------------\n"; GeneralisedObjectiveFunction::list_registered_names(std::cout); std::cout << "------------ GeneralisedPrior --------------\n"; GeneralisedPrior::list_registered_names(std::cout); std::cout << "------------ Reconstruction --------------\n"; Reconstruction::list_registered_names(std::cout); - - + return EXIT_SUCCESS; } diff --git a/src/utilities/stir_math.cxx b/src/utilities/stir_math.cxx index 147b979e4..0e54d8594 100644 --- a/src/utilities/stir_math.cxx +++ b/src/utilities/stir_math.cxx @@ -11,23 +11,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 @@ -35,27 +35,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. @@ -70,7 +70,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 @@ -92,19 +92,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" @@ -126,8 +126,8 @@ #include "stir/warning.h" #include "stir/error.h" -#include -#include +#include +#include #include #include #include @@ -141,51 +141,53 @@ using std::min; using std::string; using std::vector; - 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) +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 ) + 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; + shared_ptr current_image_ptr; - for (int i=1; ibegin_all(), image_ptr->end_all(), - current_image_ptr->begin_all(), - image_ptr->begin_all(), - std::plus()); - } + { + // 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()); - } + { + // *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) @@ -193,56 +195,58 @@ void process_data(const string& output_file_name, 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) +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) + 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); + 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()); - } - } + 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) @@ -251,81 +255,81 @@ void process_data(const string& output_file_name, } template -shared_ptr > +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(); @@ -341,147 +345,186 @@ main(int argc, char **argv) // first process command line options - while (argc>0 && argv[0][0]=='-') + 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); - } + 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; - } + 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); } + { + 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; + --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); } - - 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 (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(); if (verbose) { - cout << program_name << ": " - << (do_add ? "adding " : "multiplying ") - << num_files; + 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 << " 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; } @@ -491,114 +534,108 @@ main(int argc, char **argv) // 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)); - } + { + 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)); - } + { + 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, + { + 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< shared_ptr > all_proj_data(num_files); + 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]; + { + 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."); - } + 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); - } + { + 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; - - 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 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); - } - } - } + 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); + } + } + } return EXIT_SUCCESS; } diff --git a/src/utilities/stir_timings.cxx b/src/utilities/stir_timings.cxx index 0b4c1639c..ce17f9fd8 100644 --- a/src/utilities/stir_timings.cxx +++ b/src/utilities/stir_timings.cxx @@ -102,7 +102,10 @@ class Timings : public TimedObject //! Test function that could be used to see if reported timings are correct /*! CPU time should be close to zero, wall-clock time close to 1123ms */ - void sleep() { std::this_thread::sleep_for(std::chrono::milliseconds(1123)); } + void sleep() + { + std::this_thread::sleep_for(std::chrono::milliseconds(1123)); + } void copy_image() { @@ -114,7 +117,8 @@ class Timings : public TimedObject void copy_proj_data_file_to_file() { ProjDataInterfile tmp(this->template_proj_data_sptr->get_exam_info_sptr(), - this->template_proj_data_sptr->get_proj_data_info_sptr(), "my_timings_copy.hs"); + this->template_proj_data_sptr->get_proj_data_info_sptr(), + "my_timings_copy.hs"); tmp.fill(*this->output_proj_data_sptr); } @@ -131,7 +135,8 @@ class Timings : public TimedObject void copy_proj_data_mem_to_file() { ProjDataInterfile tmp(this->template_proj_data_sptr->get_exam_info_sptr(), - this->template_proj_data_sptr->get_proj_data_info_sptr(), "my_timings_copy.hs"); + this->template_proj_data_sptr->get_proj_data_info_sptr(), + "my_timings_copy.hs"); tmp.fill(*this->mem_proj_data_sptr); } @@ -166,7 +171,10 @@ class Timings : public TimedObject this->projectors_sptr->get_back_projector_sptr()->back_project(*this->image_sptr, *this->mem_proj_data_sptr); } - void obj_func_set_up() { this->objective_function_sptr->set_up(this->image_sptr); } + void obj_func_set_up() + { + this->objective_function_sptr->set_up(this->image_sptr); + } void obj_func_grad_no_sens() { @@ -275,9 +283,10 @@ Timings::init() // projection data set-up { std::string output_filename = "my_timings.hs"; - this->output_proj_data_sptr - = std::make_shared(this->exam_info_sptr, this->template_proj_data_sptr->get_proj_data_info_sptr(), - output_filename, std::ios::in | std::ios::out | std::ios::trunc); + this->output_proj_data_sptr = std::make_shared(this->exam_info_sptr, + this->template_proj_data_sptr->get_proj_data_info_sptr(), + output_filename, + std::ios::in | std::ios::out | std::ios::trunc); this->mem_proj_data_sptr = std::make_shared(this->exam_info_sptr, this->template_proj_data_sptr->get_proj_data_info_sptr()); } diff --git a/src/utilities/stir_write_pgm.cxx b/src/utilities/stir_write_pgm.cxx index 74e6a6e34..dc4da1bb4 100644 --- a/src/utilities/stir_write_pgm.cxx +++ b/src/utilities/stir_write_pgm.cxx @@ -10,9 +10,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. @@ -40,188 +40,185 @@ 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)) - { - warning("write_pgm: can only display 'regular' arrays. Returning.\n"); - return; - } + { + warning("write_pgm: can only display 'regular' arrays. Returning.\n"); + return; + } - FILE *pgm = fopen ( filename.c_str() , "wb"); + FILE* pgm = fopen(filename.c_str(), "wb"); if (pgm == NULL) - { - error("Error opening file %s for output to PGM.",filename.c_str()); - } + { + 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 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 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) +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"; + 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) +int +main(int argc, char** argv) { - const char * const program_name = argv[0]; + 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) + // 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]); - } + 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: " < 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': + case 't': + case 'T': // transverse, nothing to do at the moment break; - case 's': case 'S': + case 's': + case 'S': // sagital - image=stir::transpose_13(image); + image = stir::transpose_13(image); break; - case 'c': case 'C': + case 'c': + case 'C': // coronal - image=stir::transpose_12(image); + 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 008a73afa..bb4d00cae 100644 --- a/src/utilities/warp_and_accumulate_gated_images.cxx +++ b/src/utilities/warp_and_accumulate_gated_images.cxx @@ -2,16 +2,16 @@ /* Copyright (C) 2009 - 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + 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 */ @@ -30,24 +30,25 @@ USING_NAMESPACE_STIR using namespace BSpline; - -int main(int argc, char **argv) +int +main(int argc, char** argv) { - if(argc<3 || argc>4) { - cerr<<"Usage: " << argv[0] << " \n"; - exit(EXIT_FAILURE); - } + 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 44ed48990..153edb3a8 100644 --- a/src/utilities/warp_image.cxx +++ b/src/utilities/warp_image.cxx @@ -1,16 +1,16 @@ /* Copyright (C) 2010 - 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 - + See STIR/LICENSE.txt for details */ /*! - \file + \file \ingroup utilities \ingroup spatial_transformation - + \brief This program warps an image. \author Charalampos Tsoumpas */ @@ -21,43 +21,42 @@ USING_NAMESPACE_STIR - -int main(int argc, char **argv) +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); - } - + 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 8bd817166..e0d0ff319 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 @@ -35,25 +35,23 @@ using std::endl; using std::cerr; using std::endl; - 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"; - 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) - { + 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(); + proj_data_info_sptr = proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone(); } else { @@ -61,40 +59,34 @@ main(int argc, char **argv) } shared_ptr proj_matrix_sptr; - if (argc>3) + 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.add_stop_key("END"); parser.parse(argv[3]); } - - shared_ptr > image_sptr; - if (argc>4) + shared_ptr> image_sptr; + + if (argc > 4) { - image_sptr = read_from_file >(argv[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)); + 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); } @@ -104,16 +96,12 @@ main(int argc, char **argv) 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; + 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/write_sinogram_to_txt.cxx b/src/utilities/write_sinogram_to_txt.cxx index e9579498b..296350679 100644 --- a/src/utilities/write_sinogram_to_txt.cxx +++ b/src/utilities/write_sinogram_to_txt.cxx @@ -4,19 +4,19 @@ Jannis Fischer jannis.fischer@cern.ch - 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/ProjDataFromStream.h" @@ -28,7 +28,7 @@ #include "stir/IO/interfile.h" #include "stir/shared_ptr.h" -#include +#include #include USING_NAMESPACE_STIR @@ -36,38 +36,43 @@ using std::cerr; using std::cout; using std::endl; using std::ofstream; -int main( int argc, char** argv ) +int +main(int argc, char** argv) { - if( argc < 4 ) - { - cerr << "Usage: " << argv[0] << " filename.hs axial_position segment_number" << endl; - return EXIT_FAILURE; - } - std::string filename(argv[1]); - - shared_ptr projdata_sptr = ProjData::read_from_file(filename.c_str()); - Sinogram sino = projdata_sptr->get_sinogram(atoi(argv[2]), atoi(argv[3]) ); - - std::string outfilename; - size_t lastdot = filename.find_last_of("."); - if( lastdot == std::string::npos ) outfilename = filename; - else outfilename = filename.substr(0,lastdot); - outfilename.append("_axialposition"); - outfilename.append(argv[2]); - outfilename.append("_segment"); - outfilename.append(argv[3]); - outfilename.append(".csv"); - - ofstream outfile(outfilename.c_str()); - outfile << "#\tsegment=" << sino.get_segment_num() << "\taxial_pos=" << sino.get_axial_pos_num() << endl; - - for( int view = sino.get_min_view_num(); view <= sino.get_max_view_num(); view++ ) { - for( int tpos = sino.get_min_tangential_pos_num(); tpos <= sino.get_max_tangential_pos_num(); tpos++ ){ - outfile << sino[view][tpos] << "\t"; - } - outfile << endl; - } + if (argc < 4) + { + cerr << "Usage: " << argv[0] << " filename.hs axial_position segment_number" << endl; + return EXIT_FAILURE; + } + std::string filename(argv[1]); - outfile.close(); - return EXIT_SUCCESS; -} + shared_ptr projdata_sptr = ProjData::read_from_file(filename.c_str()); + Sinogram sino = projdata_sptr->get_sinogram(atoi(argv[2]), atoi(argv[3])); + + std::string outfilename; + size_t lastdot = filename.find_last_of("."); + if (lastdot == std::string::npos) + outfilename = filename; + else + outfilename = filename.substr(0, lastdot); + outfilename.append("_axialposition"); + outfilename.append(argv[2]); + outfilename.append("_segment"); + outfilename.append(argv[3]); + outfilename.append(".csv"); + + ofstream outfile(outfilename.c_str()); + outfile << "#\tsegment=" << sino.get_segment_num() << "\taxial_pos=" << sino.get_axial_pos_num() << endl; + + for (int view = sino.get_min_view_num(); view <= sino.get_max_view_num(); view++) + { + for (int tpos = sino.get_min_tangential_pos_num(); tpos <= sino.get_max_tangential_pos_num(); tpos++) + { + outfile << sino[view][tpos] << "\t"; + } + outfile << endl; + } + + outfile.close(); + return EXIT_SUCCESS; +} diff --git a/src/utilities/zeropad_planes.cxx b/src/utilities/zeropad_planes.cxx index 7919cd20d..fd4594b49 100644 --- a/src/utilities/zeropad_planes.cxx +++ b/src/utilities/zeropad_planes.cxx @@ -1,15 +1,15 @@ /* Copyright (C) 2011 - 2013, King's College London This file is part of STIR. - + SPDX-License-Identifier: Apache-2.0 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 */ @@ -19,50 +19,51 @@ USING_NAMESPACE_STIR -int main(int argc, char **argv) +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]; + 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]; 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]) + 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[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; + 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]) + 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[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; + 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; + } + 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 47d5eba97..ac321a1b2 100644 --- a/src/utilities/zoom_image.cxx +++ b/src/utilities/zoom_image.cxx @@ -10,9 +10,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. @@ -28,73 +28,73 @@ #include "stir/Succeeded.h" #include "stir/error.h" - 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" - << '\t' << prog_name << " [--scaling