STIR Versions Save

Software for Tomographic Image Reconstruction

rel_6.1.0

2 days ago

Summary of changes in STIR release 6.1

This version is 100% backwards compatible with STIR 6.0 for the user, except for the bug-fix in the RDP (see below).

Overall summary

This version adds capability of using Parallelproj (CPU and GPU versions) for TOF data. In addition, the list-mode objective function has several improvements, including speed-up by using multi-threading if caching was not enabled.

Of course, there is also the usual code-cleanup and improvements to the documentation.

This release contains mainly code written by Nicole Jurjew (UCL) and Kris Thielemans (UCL).

Summary for end users (also to be read by developers)

New functionality

  • Add TOF capability of the parallelproj projector (see PR #1356)
  • It is now possible to read TOF bin order from the interfile header (see PR #1389)
  • PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin can now compute the value as well as accumulate_Hessian_times_input. PR #1418
  • GeneralisedObjectiveFunction has 2 new members to compute the full gradient (compute_gradient and compute_gradient_without_penalty`). Previously, only subset gradients were available. PR #1418

Changed functionality

  • PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin now computes the gradient multi-threaded (if OpenMP is enabled), even if caching to file of the list-mode file is not enabled. PR #1418
  • Accumulation in computation of priors now uses doubles, which could result in slightly better precision. Part of PR #1410.

Bug fixes

  • The Relative Difference Prior gave incorrect results, probably since switching to C++-14 in version 6.0, although we are not sure. See PR #1410 and associated issue #1409.
  • Our checks for determining system byte-order were out-of-date and in particular did not work on MacOS 14 on ARM. We now use CMake's CMAKE_CXX_BYTE_ORDER (available since CMake 3.20). This could potentially affect reading of list-mode data (which would otherwise be garbled). Fixed in PR #1412.
  • The listmode objective function did not loop over TOF bins when computing the Hessian. This would give different results in OSSPS for computing the "denominator". Fixed in issue #1427.

Known problems

See our issue tracker.

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

Backward incompatibities

  • Additional checks on GeometryBlocksOnCylindrical scanner configuration, which may lead to an error being raised, while previously the code silently proceeded.

Bug fixes

  • PoissonLogLikelihoodWithLinearModelForMeanAndProjData had a (minor?) problem with TOF data that when computing the gradient, the normalisation object was not set-up with the TOF data, but non-TOF instead. This did not happen in our normal reconstruction code, and would have thrown an error if it occured. Fixed in issue #1427.

Other code changes

  • Fixes an incompatibility with C++20.

Build system

  • Force C++ version according to CERN ROOT versions: ROOT 6.28.10 needs C++17 and 6.30.2 needs C++20. Also some fixes when relying on root-config.

Test changes

C++ tests

  • Objective functions (both projection-data and list-mode) and priors now have a numerical test for accumulate_Hessian_times_input
    PR #1418

Full Changelog: https://github.com/UCL/STIR/compare/rel_6.0.0...rel_6.1.0

rel_6.0.0

3 months ago

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 locations of installed files have changed. Developers of other software that uses STIR via CMake will therefore need to adapt (see below).

Overall summary

This release is a major upgrade adding Time of Flight (TOF) capabilities to STIR.

This version has a major code-cleanup related to removing old compiler work-arounds, consistent use of override and white-space enforcement.

Overall code management and assistance was Kris Thielemans (UCL and ASC). Other main contributors include: Nikos Efthimiou (UCL, University of Hull, UPenn, MGH) for the TOF framework and list-mode reconstruction, Elise Emond (UCL) for adapting TOF framework for projection-data, Palak Wadhwa (University of Leeds) for adaptations and testing on GE Signa PET/MR data, Robert Twyman for extending projector symmetries to TOF and formalising ROOT-based testing, Nicole Jurjew (UCL) for adaptations and testing on Siemens Vision 600 data. Non-TOF contributors include Daniel Deidda (NPL) and Markus Jehl (Positrigo).

Patch release info

Summary for end users (also to be read by developers)

Changes breaking backwards compatibility from a user-perspective

General

  • When parsing Interfile headers for projection data and the originating system is not recognised, the previous version of STIR tried to guess the scanner based on the number of views or rings. This was using very old scanners though, and could lead to confusion. These guesses have now been removed.
  • (deprecated) support for the GE VOLPET format (an old format used by the GE Advance and Discover LS sinograms when using "break-pointing") has been removed.
  • (deprecated) support for the AVW format via the (very old) AnalyzeAVW commercial library has been removed.
  • Most installed files are now in versioned directories. The following shows the new and old locations relative to CMAKE_INSTALL_PREFIX, where V.v indicates the major.minor version number, e.g. 6.0:
    • documentation (including examples as subfolder): share/doc/STIR-V.v (was share/doc/stir-V.v)

    • JSON files with radionuclide database: share/STIR-V.v/config (was share/stir/config)

      Developers also need to check the new location to use for STIR_DIR documented below.

  • ProjDataInfo::ask_parameters() and therefore create_projdata_template has changed:
    1. If the scanner definition in STIR has TOF capabilities, it will ask for the TOF mashing factor.
    2. The default for arc-correction has changed to N, i.e. false.
    3. Default value for span is now 11 for Siemens and 2 for GE scanners.
    4. The span=0 case (i.e. span-3 for segment 0, span=1 for oblique ones, erroneously by STIR used for the GE Advance) is no deprecated. GE uses span=2. (Reading a "span=0" case is still supported)
  • Projection-data related classes have accessors with an optional make_num_tangential_poss_odd argument (defaulting to false), which made the returned argument a different size. This has been deprecated since version 5.0. Setting this argument to true will now raise an error.

Python (and MATLAB)

  • renamed FloatLOR to LOR, and same for derived classes.

New functionality

The new TOF support is mostly transparent, i.e. normally no changes are required to the reconstruction code etc. When using Interfile or ROOT files, certain new keywords are required, see examples/samples/PET_TOF_Interfile_header_Signa_PETMR.hs and examples/samples/root_header.hroot. See also the updated STIR_glossary. Please cite the following papers:

  • Efthimiou, N., Emond, E., Wadhwa, P., Cawthorne, C., Tsoumpas, C., Thielemans, K., 2019. Implementation and validation of time-of-flight PET image reconstruction module for listmode and sinogram projection data in the STIR library. Phys Med Biol 64, 035004. DOI: 10.1088/1361-6560/aaf9b9.
  • Wadhwa, P., Thielemans, K., Efthimiou, N., Wangerin, K., Keat, N., Emond, E., Deller, T., Bertolli, O., Deidda, D., Delso, G., Tohme, M., Jansen, F., Gunn, R.N., Hallett, W., Tsoumpas, C., 2021. PET image reconstruction using physical and mathematical modelling for time of flight PET-MR scanners in the STIR library. Methods, Methods on simulation in biomedicine 185, 110–119. DOI: 10.1016/j.ymeth.2020.01.005

See also the (enormous) PR #304.

Limitations

  • Currently on the matrix based projectors support TOF. Note that the implementation is generic but slow: a non-TOF row is computed and then multiplied with the TOF kernel. This is somewhat alleviated by the use of caching. However, as not all symmetries are supported yet, caching of the projection matrix needs substantially more memory than in the non-TOF situation.
  • We do not have TOF scatter simulation/estimation yet.
Non-TOF updates
  • Radionuclide information is read from Interfile and GE HDF5 headers. If the radionuclide name is recognised to the STIR database, its values for half-life etc are used, as opposed to what was recorded in the file (if anything).
  • list_lm_events now has an additional option --event-bin which lists the bin assigned for the event (according to the "native" projection data, i.e. without any mashing). In addition, the --event-LOR option now also works for SPECT (it was disabled by accident).
  • stir_list_registries is a new utility that list possible values of various registries, which can be useful to know what to use in a .par file.
  • Radionuclide database now has a datasource entry with the radionuclide decay table (lnHB ). This makes it traceable to standardised measures of branching ratios, half lives etc. The change is backward compatible and old format is still supported. However we encourage to use the new one, see src/config/radionuclide_info.json.

Python (and MATLAB)

  • exposed ProjMatrixByBinPinholeSPECTUB PR #1366
  • PR #1288
    • exposed ListRecord etc, such that loops over list-mode data can now be performed in Python (although this will be somewhat slow). See examples/python/listmode_loop_demo.py.
    • added LORAs2Points,LORInCylinderCoordinates, LORInAxialAndSinogramCoordinates and PointOnCylinder. Warning: renamed FloatLOR to LOR, and same for derived classes.
  • add DetectionPositionPair.__repr__ for printing and change order of text in DetectionPosition.__repr__ to fit with constructor to avoid confusion. PR #1316

Changed functionality

  • We now always check (in ProjDataInfo*NoArcCorr) if number of tangential positions in the projection data exceeds the maximum number of non arc-corrected bins set for the scanner. If it is, an error is raised. You might therefore have to adapt your interfile header.
  • Interfile header changes:
    • Write STIR6.0 as Interfile key version to denote TOF changes. This is currently ignored for parsing though.
    • (PET) The effective central bin size (cm) keyword for projection data is now only used for arc-corrected data. It is no longer written to the header for non-arccorrected data.

Build system

  • CMake version 3.14 is now required.
  • C++-14 is now required. In fact, it is possible that C++-11 still works. If you really need it, you can try to modify the main CMakeLists.txt accordingly.
  • STIR_CONFIG_DIR is no longer a CMake cached variable, such that it automatically moves along with CMAKE_INSTALL_PREFIX. However, if you are upgrading an existing STIR build, you might have to delete the cached variable, or it will point to the old location.

Bug fixes

  • Interfile parsing no longer gets confused by the use of : in a keyword (e.g., used by Siemens for dates). PR #1267

Known problems

See our issue tracker.

Documentation changes

  • Added (some) documentation on TOF features
  • Added examples/C++/using_installed_STIR to illustrate how to use STIR as a "library".
  • Renamed examples/C++/src to examples/C++/using_STIR_LOCAL.

New deprecations for future versions

  • CMake option STIR_USE_BOOST_SHARED_PTR will be removed. It probably no longer works anyway. Therefore stir::shared_ptr will always be std::shared_ptr.
  • Direct X-windows display (corresponding to the CMake option `GRAPHICS=X`) will be removed. It is very outdated and sometimes doesn't work.
  • remaining files for ECAT6 support will be removed.

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

  • ListModeData now has a shared_ptr<const ProjDataInfo> proj_data_info_sptr protected member, and the scanner_sptr member has been removed. Warning: If your derived class had its own proj_data_info_sptr, it should be removed.

  • virtual ListModeData::get_scanner_ptr() is replaced by ListModeData::get_scanner().

  • ProjDataInfo*NoArcCorr::get_bin_for_det_pair is now private. Use get_bin_for_det_pos_pair instead.

  • The GeneralisedObjectiveFunction hierarchy now has a already_set_up member variable that needs to be set to false by set_* functions and checked by callers.

  • (deprecated) members/functions have been removed

    • BinNormalisation::undo and apply members that take explicit time arguments
    • extend_sinogram_in_views, extend_segment_in_views and interpolate_axial_position
  • As mentioned above, installation locations are now versioned. New locations that could affect developers that use STIR as an external project:

    • include files: include/STIR-V.v (was include). This should be transparant if you use find_package(STIR).
    • CMake exported STIRConfig.cmake etc: lib/cmake/STIR-V.v (was share/lib). The CMake variable STIR_DIR should now be set to <STIR_CMAKE_INSTALL_PREFIX>/lib/cmake/STIR-V.v. However, this new location increases chances that find_package finds STIR as it follows conventions better. For instance, STIR can now by found by find_package when setting CMAKE_PREFIX_PATH to what was used for CMAKE_INSTALL_PREFIX when installing STIR (indicated as STIR_CMAKE_INSTALL_PREFIX above). Moreover, if you use the same CMAKE_INSTALL_PREFIX for your project as for STIR, you shouldn't need to set STIR_DIR nor CMAKE_PREFIX_PATH.

New functionality

  • Scanner now allows storing TOF information. This is currently not yet done for all TOF-capable scanners though. Contributions welcome!

  • All projection-data related classes and their members now have a TOF bin index and related information. At present, old-style accessors are in an awkward format such as

              auto sino = proj_data.get_sinogram(ax_pos_num, segment_num, false, timing_pos_num);
    

    These are deprecated since version 5.2 and should be replaced by

              const SinogramIndices sinogram_idxs{ax_pos_num, segment_num, timing_pos_num};
              auto sino = proj_data.get_sinogram(sinogram_idxs);
    
  • List-mode data for TOF-capable scanners need to pass the relevant information through appropriately of course.

  • Projectors now have a clone() member, currently returning a bare pointer (like other STIR classes).
  • Bin can now be output to stream as text.
  • Added RunTests::check_if_equal for Bin.
  • KeyParser has a new facility to add an alias to a keyword. This can be used to rename a keyword for instance while remaining backwards compatible. By default, a warning will be written, but this can be disabled.

Changed functionality

  • ProjDataInfoCylindricalNoArcCorr::get_all_det_pos_pairs_for_bin is in most places intended to return the physical locations. However, a `DetectionPositionPair` also contains (unmashed) TOF bin information. This will be further complicated once energy windows are supported. The method therefore has an extra boolean argument ignore_non_spatial_dimensions, which defaults to true.
  • multiply_crystal_factors is essentially a non-TOF calculation. When given TOF projection data, it will "spread" the non-TOF result equally over all TOF bins. This is also appropriate for randoms_from_singles.

Code clean-up

  • Clean-up of various work-arounds such as STIR_NO_NAMESPACES, STIR_NO_MUTABLE, BOOST_NO_TEMPLATE_SPECIALIZATION, BOOST_NO_STRINGSTREAM and various items specifically for VC 6.0.
  • Consistently use override in derived classes, via clang-tidy --modernize-use-override.

Test changes

recon_test_pack changes

  • additional tests for TOF, expansion of some existing tests for TOF
  • updated version number and added some clarification to the README.txt

C++ tests

  • additional tests for TOF, expansion of some existing tests for TOF

rel_5.2.0

6 months ago

Summary of changes in STIR release 5.2.0

This version is 100% backwards compatible with STIR 5.0 as far as usage goes. However, there are changes in the output of scatter estimation and ECAT8 normalisation, see below for more information.

Overall summary

Of course, there is also the usual code-cleanup and improvements to the documentation. See also the 5.2 milestone on GitHub.

Overall code management and assistance by Kris Thielemans (UCL and ASC). Other main contributors were Daniel Deidda (NPL) and Markus Jehl (Positrigo).

Patch release info

  • 5.2.0 released 30/10/2023

Summary for end users (also to be read by developers)

Bug fixes

  • Scatter estimation was setting initial activity image to 1 at set-up, effectively ignoring the initial image, aside from geometric info.
  • Setting SPECTUB resolution model with STIR python or SIRF divided slope by 10 in error. The problem did not occur when set using parameter file

Changed functionality

  • The ECAT8 normalisation (used for the Siemens mMR) code now takes the 4th component axial effects into account. These normalisation factors are therefore different (even up to ~10%). This gives improved axial uniformity in the images. The use of the axial effects can be switched off by adding setting use_axial_effects_factors:=0 to the parameter file (see an example in examples/Siemens-mMR/correct_projdata_no_axial_effects.par), or the class member of the same name. In addition, the Siemens normalisation header is now read (using a new class InterfileNormHeaderSiemens) such that hard-coded variables for the Siemens mMR have been removed. Further testing of this functionality is still required however. PR #1182.
  • Interfile header parsing now correctly identifies keywords that contain a colon by checking for :=.
  • The set_up() method of the ray-tracing projection matrix now skips further processing if it was already called with data of the same characteristics. This will means that any cached data will be re-used, potentially leading to a speed-up when re-using it from Python. PR #1281.

New functionality

  • The Discretised Shape3D shape/ROI has now an extra value label index. For ROIs, this allows using a single volume with multiple ROIs encoded as labels, such as output by ITKSnap and many others. When used as a shape in generate_image, it could be used to extract a single ROI from such a label image. PR #1196.

  • Global variables in SPECTUB have been substituted by class members, such that multiple SPECTUB projectors can be used. PR #1169.

  • Global variables in PinholeSPECTUB have been substituted by class members, such that multiple PinholeSPECTUB projectors can be used. PR #1212.

  • Scatter estimation is now smoothed in axial direction for BlocksOnCylindrical scanners. PR #1172.

  • InverseSSRB now works for BlocksOnCylindrical after a rewrite. PR #1172. /

  • Parallelised function set_fan_data_add_gaps_help across segments to reduce computation time. PR #1168.

  • New utility SPECT_dicom_to_interfile which reads a DICOM file with SPECT projection data and extracts the data and writes one or more Interfile 3.3 headers (still somewhat preliminary). PR #1182.

  • The new stir_timings utility is mostly useful for developers, but you could use it to optimise the number of OpenMP threads to use for your data. PR #1237.

  • New classes SegmentIndices, ViewgramIndices and SinogramIndices, used by ProjData related classes, as opposed to having to specify all the elements directly, e.g. in C++

          auto sinogram = proj_data.get_sinogram(sinogram_indices);
    

    This makes these functions more future proof, in particular for TOF. The older functions are now deprecated. Note that as Bin is now derived from ViewgramIndices, instantations of Bin can now be used to specify the indices as well in most places. There is still more work to do here, mostly related to the symmetries. PR #1273.

Python (and MATLAB)

  • Examples use stir.ProjData.read_from_file as opposed to stir.ProjData_read_from_file. The former is supported since SWIG 3.0, and the default from SWIG 4.1.
  • Addition of DetectionPosition and DetectionPositionPair.
  • bin.time_frame_num is now no longer a function in Python, but acts like a variable (as the other Bin members).
  • Addition of RadionuclideDB

New examples

  • examples/python/construct_projdata_demo.py illustrates constructing a ProjDataInMemory

Changed functionality

  • Scatter estimation was resetting the activity image to 1 before each iteration. This led to cases where the reconstructed image (and therefore the scatter estimation) did not converge, especially when using a small number of sub-iterations. Now, the reconstructed image is continuouslu updated between scatter iterations by default. This should also allow users to use less sub-iterations, therefore saving some time for the scatter estimation. The old behaviour can be re-enabled by setting restart_reconstruction_every_scatter_iteration to true either via a parameter file or via the set_restart_reconstruction_every_scatter_iteration() function. PR #1160.
  • energy resolution functions and keywords have now more documentation. Scanner::check_consistency also checks if the energy resolution is less than 20 (as it is FWHM/reference_energy). PR #1149.
  • Errors now throw std::runtime_error instead of std::string. PR #1131.
  • The parameter use_view_offset was removed from the interpolate_projdata functions. View-offset is now always taken into account. PR #1172.
  • The info, warning and error calls are thread safe now (which makes them slower), and the logging output in distributable.cxx was changed from verbosity 2 (which is the STIR default) to verbosity 3. This is to reduce the default output during iterative reconstructions. PR #1243.
  • The Succeeded class has a new method bool succeeded() enabling more concise code (avoiding the need for comparing with Succeeded::yes which is especially verbose in Python).
  • The example files for the Siemens mMR now use lower min/max thresholds for the (single) scatter scale. This gives better results, see Issue #1163. PR #1279.

Deprecated functionality and upcoming changes to required tool versions

  • The following functions (previously used for upsampling the scatter estimate) have been made obsolete or replaced, and will be removed in STIR version 6.0.0: interpolate_axial_position, extend_sinogram_in_views and extend_segment_in_views
  • Constructors/functions in ProjData related classes that explicitly use axial_pos_num, view_num etc in their arguments are now deprecated, and should be replaced by their respective versions that use SegmentIndices, ViewgramIndices or SinogramIndices. The former will not be compatible with TOF information that will be introduced in version 6.0.0.
  • Use of the AVW library to read Analyze files will be removed in 6.0, as this has not been checked in more than 15 years. Use ITK instead.
  • GE VOLPET and IE support will be removed in 6.0, as we have no files to test this, and it's obsolete anyway.
  • STIR version 6.0.0 will require C++ 14 (currently we require C++ 11, but already support C++ 20) and CMake 3.14.

Build system and dependencies

  • CMake 3.12 is now required on Windows.
  • We now use CMake's OBJECT library feature for the registries. This avoids re-compilation of the registries for every executable and therefore speeds-up building time. Use of STIR in an external project is not affected as long as the recommended practice was followed. This is now documented in the User's Guide. PR #1141.
  • The error and warning functions are now no longer included from common.h and need to be included manually when used (as was already the case for #include "stir/info.h"). PR #1192.
  • add .h and .i as dependencies for SWIG generated wrappers to make sure they get rebuild. (Currently adding all .h files, which is too much, but CMake needs a fix before we can do this properly). PR #1218.

Changes for developers

  • moved all functionality in CListEventCylindricalScannerWithDiscreteDetectors to template class CListEventScannerWithDiscreteDetectors (templated in ProjDataInfoT). This enables re-use for generic/blocksoncylindrical scanners. PR #1222.
  • rewritten ProjDataInMemory to avoid streams, causing a speed-up of some operations, and removing a limit of total size of 2GB. PR #1260.

Known problems

Minor (?) bug fixes

  • Small change in scatter simulation to how non-arccorrected bins are computed. Added a check in the construction of non-arccorrected projdata that the number of tangential bins is not larger than the maximum non-arccorrected bins. PR #1152.
  • extend_segment_in_views does not handle view offsets correctly and does not work for BlocksOnCylindrical scanners issue #1177. A new function extend_segment was added that works for Cylindrical and BlocksOnCylindrical and allows extension in tangential and axial direction as well. PR #1172.
  • sample_function_on_regular_grid did not handle offset correctly in all places issue #1178. PR #1172.
  • Ray tracing projection for BlocksOnCylindrical scanner geometries contained a bug where some bins were swapped across oblique segments issue #1223. This sometimes lead to large artifacts in reconstructions. PR #1231.

Documentation changes

  • Updated the STIR developers guide, which was quite out-of-date w.r.t. C++ features etc.

recon_test_pack changes

  • Updated headers of most images and projection data to avoid warnings.

Other changes to tests

  • test_Scanner.cxx tests for energy resolution, PR #1149.
  • New file test_interpolate_projdata, PR #1141.

rel_5.1.2

8 months ago

Code is identical to 5.1.0 and 5.1.1, aside from handling the scatter test with a slightly larger threshold due to occasional failures (as it uses random placements). This change is a backport from STIR master.

rel_5.1.1

8 months ago

Code is identical to 5.1.0, aside from handling numerical precision in 2 tests, which otherwise can fail.

rel_5.1.0

1 year ago

Summary of changes in STIR release 5.1

This version is 100% backwards compatible with STIR 5.0.

Overall summary

  • This release includes the first open-source code available for reconstructing pinhole-SPECT datasets (see PR #1100). It contains code by Carlés Falcón (Neuroimaging Group, Barcelonaβeta Brain Research Center) to create the pinhole-SPECT system matrix. Integration into STIR was completed by Matthew Strugari (Dalhousie University) and Kris Thielemans (UCL). This work is reported in
    • Matthew Strugari, Carles Falcon, Kjell Erlandsson, Brian Hutton, G. Andrew Reid, Ian Pottie, Sultan Darvesh, Steven Beyea, Kimberly Brewer, Kris Thielemans, Integration of advanced 3D SPECT modelling for pinhole collimators into the open-source STIR framework, Proc. IEEE MIC 2022, Milan, Italy
  • Improvements to listmode reconstruction by Nikos Efthimiou, see PR #1030.
  • Support for PENNPET Explorer listmode data (if proprietary libraries are found) by Nikos Efthimiou, see PR #1028.
  • Scatter simulation, estimation and down/up-sampling, randoms handling and ML normalisation estimation adapted for scanner with Block geometry by Daniel Deidda (NPL) and Kris Thielemans (UCL).
  • Various small changes to add functionality to Python interface, mainly by Markus Jehl (Positrigo).
  • Python projection data visualiser (in examples/python) by Robert Twyman (UCL).

Of course, there is also the usual code-cleanup and improvements to the documentation. See also the 5.1 milestone on GitHub and the full release notes

Overall code management and assistance by Kris Thielemans (UCL and ASC).

rel_5.0.2

1 year ago

bug-fix release:

  • fix in exported STIRConfig.cmake for HDF5
  • fix Block/Generic get_phi() which could cause 180 degrees swaps

rel_5.0.1

1 year ago

bug-fix release

  • PR 1019: fixes for SWIG and hence Python interface.
  • PR #1012 and PR #1016: rotational changes to STIR's interface to ROOT files, breaking compatibility with 4.x (and 5.0.0 but this was broken). See below for more information.
  • PR #1026: various fixes to the radionuclide database code. WARNING: This PR changed the file format for radionuclide_info.json file to be more future proof.

rel_5.0.0

2 years ago

This version is 95% backwards compatible with STIR 4.0 for the user (see below). Developers might need to make code changes as detailed below.

Overall summary

  • At least C++-11 is now required. We are not aware of any problems with more recent versions of C++.
  • Initial support for PET scanners with block detectors or even generic location of detectors (less tested feature), taking into account appropriate geometry. This is currently kept independent of the cylindrical scanner modelling used normally, but this will be changed in a future version. See PR #577. This work is described in P. Khateri, J. Fischer, W. Lustermann, C. Tsoumpas, and G. Dissertori, Implementation of cylindrical PET scanners with block detector geometry in STIR, EJNMMI Physics, vol. 6, no. 1, p. 15, Jul. 2019, doi: 10.1186/s40658-019-0248-9. V. Dao, E. Mikhaylova, M. L. Ahnen, J. Fischer , K. Thielemans, C. Tsoumpas, Image Reconstruction for PET Scanners With Polygonal Prism Geometry Using STIR, proc. IEEE MIC 2021 This code was initially developed by Parisa Khateri and Michael Roethlisberger (ETH), and further improved and tested by Viet Dao (Leeds), Daniel Deidda (NPL) and Kris Thielemans (UCL and ASC) with funding by the University of Leeds and Positrigo AG.
  • View Offset Support enabled for the PET scanners, contributed by Palak Wadhwa (Leeds Univ), allowing fixing rotation of reconstructed images, see PR 181.
  • Maximum Likelihood estimation of normalisation factors now includes estimation of geometric factors in 3D, see PR 619. This code was mostly contributed by Tahereh Niknejad (work completed at University of Lisbao, Portugal and PETsys Electronics, together with Kris Thielemans, UCL), as well as capabilities to work with virtual crystals, see PR 833 and PR 949. See the following proceedings for the initial work Tahereh Niknejad, Stefaan Tavernier, Joao Varela, and Kris Thielemans, Validation of 3D Model-Based Maximum-Likelihood Estimation of Normalisation Factors for Partial Ring Positron Emission Tomography In 2016 IEEE Nuclear Science Symposium, Medical Imaging Conference and Room-Temperature Semiconductor Detector Workshop (NSS/MIC/RTSD), 1–5. DOI: 10.1109/NSSMIC.2016.8069577.
  • A new ProjDataInfoSubsetByView class has been implemented which allows for subsets of projection data. Previously, subset projections could only be stored in fully sampled ProjData. This is still possible, the implementation is backward compatible, and subset reconstructions such as OSMAPSOL have not been changed. However, there is now an option to create subsets with ProjData::get_subset which only store a subset of views and so are more memory efficient when subsets might be handled separately. ProjDataInfoSubsetByView currently does not support file I/O.
  • ROOT files produced by GATE can now be interpreted using "virtual crystals", see PR #617.
  • A calibration factor can be applied in the normalisation with a new BinNormalisation derived class BinNormalisationWithCalibration; Interfile now reads/writes isotope name and calibration factor. See PR 672. This code was contributed by Daniel Deidda (NPL) and Kris Thielemans (UCL)
  • Radionuclide information is saved into a JSON configuration file for a number of popular radionuclide for PET and SPECT. This can make operations like decay correction easier and accurate. To be able to use the database we need to provide the isotope name used in the acquisition. For SPECT this is extracted from the Dicom header and saved in the interfile. For PET ways to read this information need to be implemented for each scanner/vendor. The new classes are new Radionuclide and RadionuclideDB; This code was contributed by Daniel Deidda (NPL) and Kris Thielemans (UCL)
  • KOSMAPOSL (HKEM) allows now to freeze the iterative part of the kernel at a specific subiteration. Code contributed by Daniel Deidda (NPL), Kris Thielemans (UCL) and Ashley Gillman (CSIRO)
  • It is now possibly to call the Georg's Schramm parallelproj projectors (using either OpenMP or CUDA), see PR 817, contributed by Kris Thielemans (UCL) with Georg Schramm (KUL).
  • OpenMP loop scheduling changed to use dynamic instead of runtime, resulting in faster performance.

Of course, there is also the usual code-cleanup and improvements to the documentation.

This release contains mainly code written by Kris Thielemans (UCL), Richard Brown (UCL), Parisa Khateri and Michael Roethlisberger (ETHZ), Robert Twyman (UCL), Daniel Deidda (NPL), Tahereh Nikjenad (PETsys), Palak Wadhwa (Univ of Leeds), Viet Ahn Dao (Univ of Leeds), Ashley Gillman (CSIRO), Georg Schramm (KUL), Markus Jehl (Positrigo), Gefei Chen (Univ of Macao)

Summary for end users (also to be read by developers)

Changes breaking backwards compatibility from a user-perspective

  • View Offset Support enabled for the PET scanners.

    • For the scanners that have non-zero intrinsic azimuthal tilt angle, reconstructed images will now get rotated.
    • If you use view mashing, in previous STIR versions images were rotated according to half the number of mashed views. This is now corrected.

    WARNING This means that reconstructed PET images will not be identical when either the scanner has non-zero view-offset, or view-mashing is on. To reflect this change, Scanner::get_default_intrinsic_tilt() has been renamed to get_intrinsic_azimuthal_tilt(). Note: start angle was already supported for SPECT Backward compatibility for reconstructed images can be achieved by setting the STIR_LEGACY_IGNORE_VIEW_OFFSET CMake option to ON. (However, copied sinogram data will then always have the offset set to 0, in contrast to earlier versions of STIR).

  • PoissonLogLikelihood Hessian methods have been corrected to reflect the concavity of the function. Hessian vector products now return non-positive voxels, if the vector (input) is non-negative. STIR usages of these methods (OSSPS and SqrtHessianRowSum) have been updated to see no effective change in functionality. However, calling the Hessian vector product methods, via python etc., will result in a change in functionality as the sign of the output voxel values has changed.

  • Python/MATLAB wrappers no longer have ProjDataInfo::ProjDataInfoCTI, use ProjDataInfo::construct_proj_data_info instead. However, this now returns an object of the appropriate (derived) type as opposed to just ProjDataInfo. This should be transparent, except apparently for testing equality of objects.

Bug fixes

  • There was an inconsistency between log-likelihood function and its gradient when use_subset_sensitivities was false and num_subsets greater than 1. Fixing this isssue means that images reconstructed with OSSPS are different from previous versions of STIR when the above conditions are met. See Issue #873 and associated PR #893.
  • Parametric image reconstruction with POSMAPOSL could lead to zeroes being introduced gradually during reconstruction. See Issue #906 and associated PR #978.

New functionality

  • Capability to model block and generic PET detectors was added. This is currently limited to span=1, no view mashing and the ray-tracing matrix (single LOR). It is enabled by specifying appropriate keywords in the Interfile header of the projection data.

          Scanner parameters:=
          normal parameters...
          Scanner geometry (BlocksOnCylindrical/Cylindrical/Generic)  := BlocksOnCylindrical
          Distance between crystals in axial direction (cm)           := 0.22
          Distance between crystals in transaxial direction (cm)      := 0.22
          Distance between blocks in axial direction (cm)             := 0.22
          Distance between blocks in transaxial direction (cm)        := 3.3
          end scanner parameters:=
    

    Scatter and normalisation code are still pending changes.

  • Georg's Schramm parallelproj is an implementation of the Joseph algorithm for projection. If it has been installed in your system, and you tell CMake where to find it (`parallelproj_DIR=/wherever/lib/cmake`), the STIR user is now able to select an additional projector, called Parallelproj. This will use the CUDA version if available, otherwise will fall-back to the OpenMP version. Check the new sample files in examples/samples and the section in the User's Guide.

  • The (still preliminary) code for Maximum Likelihood estimation of normalisation factors now includes estimation of geometric factors in 3D as well

  • The (also preliminary) ProjDataInfoSubsetByView is backwards compatible and allows a new, memory efficient method for subset projections. Subset projections are created with with ProjData::get_subset, which is the only addition to the ProjData class (additions are mostly in the aforementioned new Info class). ProjDataInfoSubsetByView can be used to set up projectors, which will project only the subset. ProjDataInfoSubsetByView currently does not support file I/O. Therefore, the interface is not yet accessible through parameter files, only through C++ interface. PR #969

  • calculate_attenuation_coefficients utility now accepts an optional forward projection parameter file in the same format as the forward_project utility. Example usage has been added to src/recon_test_pack/simulate_data.sh.

  • ROOT files produced by GATE can now be interpreted using ``virtual crystals", i.e. by inserting ``dummy" crystals before converting to cylindrical geometry (as is done on many Siemens scanners). LmToProjData and list mode reconstructions will then put the LORs more accurately (at least when the ``virtual crystals" roughly correspond to gaps between blocks). See the update .hroot file in examples/samples. Warning: if you use the originating system to specify the scanner, this will be automatically enabled. (If you do not want this, set it to User_defined_scanner and specify all values). PR #617

  • Moved most code from the ctac_to_mu_values.cxx utility to a new HUToMuImageProcessor class (derived from DataProcessor. This allows combining it with filtering etc, also from in Python. It means that the ctac_to_mu_values.cxx utility itself is now obsolete, but it still exists in this version. (Note that this functionality depends on an external JSON library.)

  • Addition of a new utility create_multi_header which can be used to create a single header pointing to several files (e.g. one image per time frame). The header uses the (STIR-specific) multi format.

  • Addition of a new utility extract_single_images_from_parametric_image to get each parametric image in a single file.

  • generate_image parameter files now support the originating system keyword.

  • list_image_info now works for dynamic images, with a new --per-volume option to list min/max/sum for every volume.

  • SSRB now has the option of taking a template sinogram.

  • KOSMAPOSL (HKEM) allows now to freeze the iterative part of the kernel at a specific subiteration. This can be set in the parameter file through the keyword freeze_iterative_kernel_at_subiter_num

  • BinNormalisationWithCalibration is a new class derived from BinNormalisation. This class allows to apply calibration factor from the scanner and save the information into the interfile header. To use this, a specific BinNormalisation class should be derived from BinNormalisationWithCalibration, the information about the calibration factor read, and the function get_uncalibrated_bin_efficiencies() needs to be overwritten. Note that also the isotope name and branching ratio can be set here (the latter will need to be set according to the isotope by reading into a radionuclide database, see below). BinNormalisationSPECT already reads Calibration factor and isotope name and apply the calibration factor read from interfile. Since not all SPECT scanner do quantitative reconstruction an option of setting the calibration factor from the parameter file is added. Factors for BinNormalisationECA8/ECAT7 and GEHDF5 are set to one at the moment as we need to double check on the meaning of cross calibration factor for ECAT and find out how to read them for GEHDF5. Documentation for this is pending and will be added in the following PR.

  • Radionuclide is a new class which contains radionuclide information such as halflife, branching ratio, energy etc. This class allows to propagate infrmation trough the reconstruction as it is now a member in the ExamInfo. It is populated from the information extracted from RadionuclideDB which allows to create a Radionuclide object from the information stored in the radionuclide_info.json in the STIR configuration directory. Different vendors, as we saw with SPECT, may have different standards for the isotope name. Three different ones were observed, therefore a lookup table has been added to allow the use of the data base for any different isotope name format. The lookup table is a JSON file stored in radionuclide_names.json.

  • Logcosh Prior.

  • SAFIR input file format now supports a Gaussian LOR randomization, which is applied on the endpoints of each LOR when sorting the listmode events into virtual scanner projection data.

  • Scanner has now a new static member get_names_of_predefined_scanners returning a list of names.

  • Exposed compute_total_ROI_values and ROIValues to Python/MATLAB via swig. Added python example ROI_demo.py to demonstrate usage.

  • Additional C++ demo demonstrating the use the objective function and gradient ascent optimisation, see examples/src/demo4_obj_fun.cxx.

  • A few functions related to TOF were added to ProjDataInfo and Scanner for future compatibility. However, this release still does not support TOF. (Check the GitHub site for the relevant PR).

  • Exposed BinNormalisation, ListModeData, LmToProjData, ProjectorByBinPair, ScatterSimulation, ScatterEstimation and a couple of support classes and functions to Python/MATLAB via swig. Added python example listmode_demo.py to demonstrate usage.

  • More setter functions on ScatterEstimation.

Changed functionality

  • OpenMP loop scheduling changed to use dynamic instead of runtime. On some machines, this was causing slower projection operations due to a static scheduler being selected by default. See Issue #935 for more details.
  • Many operations with ProjDataInMemory are now much faster (it now uses an underlying 1D array).
  • ParametricDiscretisedDensity objects can now have an ExamInfo object with multiple time frames (corresponding to the time frames of the data where the parametric image is derived from). In some cases, there could only be a single time frame (start to end of the study).
  • find_ML_normfactors3D and apply_ML_normfactors3D can be used for scanner with virtual crystal (Only verified on mCT). Contributed by Gefei Chen, see PR 833.
  • If there are multiple buckets specified in the interfile header, we increase the symmetry size to a bucket in the find_ML_normfactors3D. Otherwise, we use a block. The use of an argument --for-symmetry-per-block in the find_ML_normfactors3D utility will use the symmetry size of a block.
  • apply_patlak_to_images no longer uses an existing file as a template for the dynamic image but will overwrite it.
  • ROOT file I/O improvements. An entire entry's tree is no longer loaded by default and instead individual branches are loaded as needed. ROOT file event processing is now up to 4x faster. In addition, there is now an option to check energy window information (defaulting to on). Futhermore, added functionality to exclude true and unscattered event types from list mode processing.

Build system

  • We now require CMake at least version 3.1, although we highly recommended to use a very recent version of CMake to avoid problems with libraries or compilers which are more recent than your CMake version.
  • At least C++-11 is now required. We are not aware of any problems with most recent versions of C++. When building, you can change the C++ version by setting CMAKE_CXX_STANDARD, see the CMake documentation for supported values. When importing STIR's STIRConfig.cmake via find_package(STIR), your compiler will be set to use at least C++-11 (via CMake's target_compile_features). Note that some external libraries that STIR depends on (such as ROOT) might increase the required C++ version, depending on how they were built.
  • CERN's ROOT library is now preferentially found by searching for its own exported ROOTConfig.cmake. Set the CMake variable ROOT_DIR accordingly. Older behaviour relying on ROOTSYS and root-config will be deprecated in a future version.
  • If you have CMake 3.14 or more recent, Python is found using the FindPython module, as opposed to the deprecated FindPythonLibs. FindPythonInterp modules. You can set the Python_EXECUTABLE variable to a particular version (see the CMake doc for other hints you can provide).( If the old PYTHON_EXECUTABLE is set, we use it to initialise Python_EXECUTABLE).

Known problems

Minor bug fixes

  • Removed boolean state from SAFIR ListMode factory, to enable reading more than one listmode file in the same runtime environment.

Documentation changes

  • Added documentation on new features
  • Also check the wiki in addition to the provided PDFs.

recon_test_pack changes

  • updated version number and added some clarification to the README.txt
  • moved the src/recon_test/test_modelling.sh and associated input files to the recon_test_pack. It is also modified to be independent of ECAT7 and now runs again.

Other changes to tests

  • expanded test_proj_data_in_memory to also test ProjDataInterfile so renamed the test to test_proj_data.

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

Major bugs fixed

  • see above

Backward incompatibities

  • Classes that use InterfilePDFSHeader now contain a shared_ptr<ProjDataInfo> instead of a raw pointer, removing a memory leak.
  • Changes improving safety of use of shared_ptr: In the previous version of STIR, the use of shared_ptr allowed unsafe access to the objects (although this never happened in distributed STIR code). We now prevent this with changes to the class interface (although there is still work to do):
    • Where possible, classes that internally contained a shared_ptr<ProjDataInfo> now contain a shared_ptr<const ProjDataInfo>, and similar for DiscretisedDensity
    • get_proj_data_info_sptr used to return shared_ptr<ProjDataInfo>, but now returns shared_ptr<const ProjDataInfo>, similar for ExamInfo.
    • Corresponding constructors and some functions, including set_up, that accept shared_ptr now take a shared_ptr to a const object.
  • ProjData*::copy_to and fill_from now return the updated iterator (as opposed to the size). This is like std::copy, and more convenient for reusing it.
  • ModelMatrix::set_if_uncalibrated and ModelMatrix::get_if_uncalibrated renamed to ModelMatrix::set_is_uncalibrated and ModelMatrix::get_is_uncalibrated
  • PlasmaData::set_if_decay_corrected and PlasmaData::get_if_decay_corrected renamed to PlasmaData::set_is_decay_corrected and PlasmaData::get_is_decay_corrected
  • Remove overloaded PatlakPlot::get_model_matrix, now it can only be called using class members
  • BinNormalisation::set_up() now need exam_info_sptr as input.
  • BinNormalisation::apply() and undo now no longer accept start_time and end_time as they are taken from exam_info. To allow this to happen, class Bin has now an extra member time_frame(). Note that it defaults to 1. If this is incorrect, it has to be initialised explicitly (not via a constructor).
  • Poisson log-likelihood hierarchy has changed for gradient methods to now use actual_compute_subset_gradient_without_penalty in the derived classes (which has an extra argument add_sensitivity). Therefore developers that created their own derived class will need to adjust their class accordingly. The public class interface is identical though.
  • DetectorCoordinateMapFromfile (used by SAFIR listmode files) has been renamed to DetectorCoordinateMap and moved from listmode to buildblock.
  • Scanner now has a set_up() function. This needs to be called after using any of the set_*() functions (except set_params). For the blocks/generic scanners, this will fill in the detector maps etc. You will get a run-time exception if you forgot to do this.

New functionality

  • New templated functions stir::copy_to and stir::fill_from in stir/copy_fill.h which can be used to fill most STIR objects from an iterator range (or copy to). The functions normally use stir_object.begin_all() but resort to stir_object::fill_from or copy_to for a few cases where no iterators exist. We use some specialisations to try and find the fastest version.

  • Introduced ProjData::standard_segment_sequence function returning 0,+1,-1,..., as used by copy_to and fill_from

  • stir::read_from_file can now be called with a "node", e.g.

        auto uptr = read_from_file<VoxelsOnCartesianGrid<float> >(filename);
    

; To do this, we now need a typedef hierarchy_base_type at the top level, as otherwise we would need multiple registries. However, this was already required by write_to_file anyway.

  • GeneralisedPrior and QuadraticPrior have a new method accumulate_Hessian_times_input(output, current_estimate, input). This computes the hessian of the prior at the current_image_estimate and multiplies this by input. Before this, the add_multiplication_with_approximate_Hessian(output, input) method was used that assumed a quadratic function and therefore hessian = 1.
  • Exam_info, TimeFrameDefinition and PatientPosition have now a == operator
  • Overloaded compute_total_ROI_values and compute_ROI_values_per_plane functions to allow the passing of aVoxelsOnCartesianGrid object instead of a Shape3D as the ROI shape. This allows the ROI volume to be constructed during preprocessing for multiple image analysis.
  • KeyParser::parameter_info() now outputs vectorised keys as well
  • DetectionPosition now has all comparison operators.
  • LOR classes now no longer require phi at input to be between 0 and pi, nor psi to be between 0 and 2 pi. They will standardise the input automatically.

Other code changes

  • store data in ProjDataInMemory in the same order as what is used by copy_to and fill_from. This enabled using straight-forward copy. (This change should not affect anyone, except if you relied on a specific order in the buffer before.)

rel_4.1.0

3 years ago

These notes only describe a summary of the changes. Please check documentation/release_4.1.htm

New functionality

  • Almost all modifications and additions since version 0.92 in 2001 are now licensed under the Apache 2.0 license as opposed to the (L)GPL.
  • Reading of GE HDF5 data (GE fileformat RDF 9) for the GE Signa PET/MR and recent GE PET/CT scanners (but depending on their software version). We currently read listmode, sinograms and calibration files (except for the WCC (well-counter calibration) files). This code is TOF-ready, but TOF is not enabled pending merge of the TOF Pull Request. Therefore, all reconstructions will be non-TOF.
  • Addition of the Relative Difference Prior [J. Nuyts, et al., 2002].
  • Interfile and ITK image IO now understand some date/time fields. This required a change to our Interfile version specification to be able to handle time-zones. These can now be added via the same suffix as used by DICOM, e.g. 10:01:01.00+0130.
  • NiftyPET's GPU projectors have been wrapped.
  • stir_math now supports the --output-format option for dynamic and parametric images as well. (An example file using the Multi format is given in the examples/samples folder).
  • Added a utility list_lm_info - A new script create_fdef_from_listmode.sh that can be used to create a single-time frame definition file for a given listmode file.
  • Implementation of ax+by methods xapyb and sapyb where a and b can be scalar or vector types.
  • The LmToProjData hierarchy has a new member function set_up(), and more set_* functions, such that it can be used without parsing.

Changed functionality

  • Modification of log-likelihood computation to use more doubles, improving numerical stability, see PR 528.
  • Reconstruction algorithms perform now more checks during set_up() etc. However, this means that you have to call set_up() also for analytic reconstruction algorithms. (This was already documented, but not yet enforced).
  • copy energy information from the template in the forward_project utility.
  • PET scatter improvements:
    • the scatter estimation parsing now prefers specifying normalisation and attenuation via two separate keywords (as opposed to via a chained bin normalisation), (keyword normalisation type) and the attenuation factors. Check the updated sample file. The old parsing keyword Bin normalisation type will still work but is deprecated and will be removed in a future version.
    • scatter estimation uses now more defaults such that you need to have less files.
    • ScatterEstimation has now many more set* functions such that most (all?) parameters can be set from C++/Python (i.e. without parsing).
  • The SinglesRates hierarchy has been revised. The SinglesRates classes assumed that stored singles were rates but in practice were totals-per-time-interval (for both ECAT7 and RDF9). It is convenient to be able to access totals and rates, so SinglesRates has now get_singles (returning the singles in the time interval) and get_singles_rates (returning the rate per second). Due to the previous confusion, "client"-code will need to be adapted to use either get_singles or get_singles_rate, depending on what is needed