From c6adcbba8211245cff0907923656691bde1411f5 Mon Sep 17 00:00:00 2001 From: Kris Thielemans Date: Wed, 4 Sep 2024 17:07:58 +0100 Subject: [PATCH 1/3] add GE DMI TOF info and 6-ring version --- src/buildblock/Scanner.cxx | 53 +++++++++++++++++++++++++++++++------- src/include/stir/Scanner.h | 1 + 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/buildblock/Scanner.cxx b/src/buildblock/Scanner.cxx index 2f48f1438..e8341af61 100644 --- a/src/buildblock/Scanner.cxx +++ b/src/buildblock/Scanner.cxx @@ -864,9 +864,10 @@ Scanner::Scanner(Type scanner_type) 1, 0.0944F, // energy resolution from Hsu et al. 2017 511.F, - (short int)(0), - (float)(0), // TODO - (float)(0)); + (short int)(2 * 188 + 1), // from RDF file + (float)(13), // from RDF file + (float)(375.4) // Hsu et al. + ); break; case DiscoveryMI4ring: // This is the 4-ring DMI @@ -895,9 +896,10 @@ Scanner::Scanner(Type scanner_type) 1, 0.0944F, // energy resolution from Hsu et al. 2017 511.F, - (short int)(0), - (float)(0), // TODO - (float)(0)); + (short int)(2 * 188 + 1), // from RDF file + (float)(13), // from RDF file + (float)(375.4) // Hsu et al. + ); break; case DiscoveryMI5ring: // This is the 5-ring DMI @@ -926,9 +928,42 @@ Scanner::Scanner(Type scanner_type) 1, 0.0944F, // energy resolution from Hsu et al. 2017 511.F, - (short int)(0), - (float)(0), // TODO - (float)(0)); + (short int)(2 * 188 + 1), // from RDF file + (float)(13), // from RDF file + (float)(375.4) // Hsu et al. + ); + break; + + case DiscoveryMI6ring: // This is the 6-ring DMI + // as above, but one extra block + // Hsu et al. 2017 JNM + // crystal size 3.95 x 5.3 x 25 + set_params(DiscoveryMI6ring, + string_list("GE Discovery MI 6 rings", + "Discovery MI6", + "Discovery MI"), // needs to include last value as used by GE in RDF files + 54, + 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 + 6, + 4, + 9, + 4, + 1, + 1, + 1, + 0.0944F, // energy resolution from Hsu et al. 2017 + 511.F, + (short int)(2 * 188 + 1), // from RDF file + (float)(13), // from RDF file + (float)(375.4) // Hsu et al. + ); break; case HZLR: diff --git a/src/include/stir/Scanner.h b/src/include/stir/Scanner.h index e5b7332bd..5b2210c69 100644 --- a/src/include/stir/Scanner.h +++ b/src/include/stir/Scanner.h @@ -165,6 +165,7 @@ class Scanner DiscoveryMI3ring, DiscoveryMI4ring, DiscoveryMI5ring, + DiscoveryMI6ring, HZLR, RATPET, PANDA, From a88ccdea60b0c777730bd652100803bcfb9ddc95 Mon Sep 17 00:00:00 2001 From: Kris Thielemans Date: Wed, 4 Sep 2024 17:08:20 +0100 Subject: [PATCH 2/3] fix RDF9 import of non-TOF data also avoid hard-wired length of manufacturer etc dataset, which can cause problems --- src/IO/GEHDF5Wrapper.cxx | 57 ++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/src/IO/GEHDF5Wrapper.cxx b/src/IO/GEHDF5Wrapper.cxx index 45978ba2e..bc6abad67 100644 --- a/src/IO/GEHDF5Wrapper.cxx +++ b/src/IO/GEHDF5Wrapper.cxx @@ -65,6 +65,17 @@ read_float(const H5::H5File& file, const std::string& dataset) return tmp; } +static std::string +read_string(const H5::H5File& file, const std::string& dataset) +{ + H5::DataSet ds = file.openDataSet(dataset.c_str()); + H5::StrType datatype = ds.getStrType(); + + std::string value; + ds.read(value, datatype); + return value; +} + bool GEHDF5Wrapper::check_GE_signature(const std::string& filename) { @@ -90,13 +101,7 @@ GEHDF5Wrapper::check_GE_signature(H5::H5File& file) if (file.getId() == -1) error("File is not open. Aborting"); - H5::StrType vlst( - 0, - 37); // 37 here is the length of the string (PW got it from the text file generated by list2txt with the LIST000_decomp.BLF - std::string read_str_manufacturer; - - H5::DataSet dataset2 = file.openDataSet("/HeaderData/ExamData/manufacturer"); - dataset2.read(read_str_manufacturer, vlst); + std::string read_str_manufacturer = read_string(file, "/HeaderData/ExamData/manufacturer"); if (read_str_manufacturer == "GE MEDICAL SYSTEMS") { @@ -277,14 +282,7 @@ GEHDF5Wrapper::open(const std::string& filename) 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); - + std::string read_str_scanner = read_string(this->file, "/HeaderData/ExamData/scannerDesc"); float effective_ring_diameter; int num_transaxial_blocks_per_bucket = 0; int num_axial_blocks_per_bucket = 0; @@ -425,6 +423,11 @@ GEHDF5Wrapper::initialise_proj_data_info_from_HDF5() { shared_ptr scanner_sptr = get_scanner_from_HDF5(); + // TODO get TOF mashing when reading sinos as TOF + const auto num_tof_bins = read_dataset_uint32("/HeaderData/Sorter/numTOF_bins"); + if (num_tof_bins > 1) + warning("GE RDF data currently still read as non-TOF"); + this->proj_data_info_sptr = ProjDataInfo::construct_proj_data_info(scanner_sptr, /*span*/ 2, @@ -654,11 +657,20 @@ GEHDF5Wrapper::initialise_proj_data(const unsigned int view_num) 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"); + const auto num_tof_bins = read_dataset_uint32("/HeaderData/Sorter/numTOF_bins"); + 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))); + if (num_tof_bins > 1) + { + m_address = "/SegmentData/Segment2/3D_TOF_Sinogram/view" + std::to_string(view_num); + m_dataset_sptr.reset(new H5::DataSet(file.openDataSet(m_address))); + } + else + { + m_address = "/SegmentData/Segment2/3D_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(); @@ -673,13 +685,7 @@ GEHDF5Wrapper::initialise_proj_data(const unsigned int view_num) // AB for signa, these where [1981,27,357] and [45,448,357] m_NX_SUB = dims[0]; // hyperslab dimensions m_NY_SUB = dims[1]; - m_NZ_SUB = dims[2]; -#if 0 - // AB todo: ??? why are these different? - m_NX = 45; // output buffer dimensions - m_NY = 448; - m_NZ = 357; -#endif + m_NZ_SUB = rank > 2 ? dims[2] : 1; } else return Succeeded::no; @@ -831,7 +837,6 @@ GEHDF5Wrapper::read_sinogram(Array<3, unsigned char>& output, } } } - output.release_data_ptr(); } return Succeeded::yes; From 66c60daa22bbb368e0def92f2fe4e81e1daad3de Mon Sep 17 00:00:00 2001 From: Kris Thielemans Date: Wed, 4 Sep 2024 20:05:18 +0100 Subject: [PATCH 3/3] updated release notes [ci skip] --- documentation/release_6.3.htm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/documentation/release_6.3.htm b/documentation/release_6.3.htm index fc818f8db..43342331f 100644 --- a/documentation/release_6.3.htm +++ b/documentation/release_6.3.htm @@ -25,6 +25,11 @@

New functionality

is disabled for backwards compatibility.
PR #1291 +
  • + Data from GE Discovery MI systems in RDF9 should now be readable. TOF information on these scanners has also been added. + However, projection data is currently still always returned as non-TOF (but list-mode data is read as TOF).
    + PR #1503 +