From 7f7d37ab0a2a6add7743bfe0eaab68b3c2341736 Mon Sep 17 00:00:00 2001 From: rts Date: Mon, 29 Jan 2024 13:10:01 -0800 Subject: [PATCH] create_empty_interfile_binary improvements using InterfileImageHeader and InterfilePDFSHeader Split functionality of create_image_and_header_from(). This was to grant access to create_image_from_header, where the argument is a InterfileImageHeader object with parsed data --- src/IO/interfile.cxx | 80 +++++++++------- src/include/stir/IO/interfile.h | 6 +- src/utilities/CMakeLists.txt | 2 +- .../create_empty_interfile_binary.cxx | 96 ++++++++++++++++++- 4 files changed, 140 insertions(+), 44 deletions(-) diff --git a/src/IO/interfile.cxx b/src/IO/interfile.cxx index 4233af724..73304583b 100644 --- a/src/IO/interfile.cxx +++ b/src/IO/interfile.cxx @@ -20,6 +20,7 @@ \author PARAPET project \author Richard Brown \author Parisa Khateri + \author Robert Twyman */ // Pretty horrible implementations at the moment... @@ -87,53 +88,58 @@ is_interfile_signature(const char * const signature) // help function -static -VoxelsOnCartesianGrid * -create_image_and_header_from(InterfileImageHeader& hdr, - char * full_data_file_name, // preallocated - istream& input, - const string& directory_for_data) + + +VoxelsOnCartesianGrid +create_image_from_header(stir::InterfileImageHeader& hdr) { - if (!hdr.parse(input)) - { - return 0; //KT 10/12/2001 do not call ask_parameters anymore - } - - // prepend directory_for_data to the data_file_name from the header - strcpy(full_data_file_name, hdr.data_file_name.c_str()); - prepend_directory_name(full_data_file_name, directory_for_data.c_str()); - - - CartesianCoordinate3D voxel_size(static_cast(hdr.pixel_sizes[2]), - static_cast(hdr.pixel_sizes[1]), - static_cast(hdr.pixel_sizes[0])); - + 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; + const BasicCoordinate<3,int> min_indices = make_coordinate(0, -y_size/2, -x_size/2); + const BasicCoordinate<3,int> max_indices = min_indices + make_coordinate(z_size, y_size, x_size) - 1; CartesianCoordinate3D origin(0,0,0); if (hdr.first_pixel_offsets[2] != InterfileHeader::double_value_not_set) + { + // make sure that origin is such that + // first_pixel_offsets = min_indices*voxel_size + origin + origin = + make_coordinate(float(hdr.first_pixel_offsets[2]), + float(hdr.first_pixel_offsets[1]), + float(hdr.first_pixel_offsets[0])) + - voxel_size * BasicCoordinate<3,float>(min_indices); + } + + return VoxelsOnCartesianGrid + (hdr.get_exam_info_sptr(), + IndexRange<3>(min_indices, max_indices), + origin, + voxel_size); +} + +// help function +static +VoxelsOnCartesianGrid * +create_image_and_header_from(InterfileImageHeader& hdr, + char * full_data_file_name, // preallocated + istream& input, + const string& directory_for_data) +{ + if (!hdr.parse(input)) { - // make sure that origin is such that - // first_pixel_offsets = min_indices*voxel_size + origin - origin = - make_coordinate(float(hdr.first_pixel_offsets[2]), - float(hdr.first_pixel_offsets[1]), - float(hdr.first_pixel_offsets[0])) - - voxel_size * BasicCoordinate<3,float>(min_indices); + return 0; // KT 10/12/2001 do not call ask_parameters anymore } - return - new VoxelsOnCartesianGrid - (hdr.get_exam_info_sptr(), - IndexRange<3>(min_indices, max_indices), - origin, - voxel_size); + // 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()); +// return create_image_from_header(hdr); + return new VoxelsOnCartesianGrid(create_image_from_header(hdr)); } VoxelsOnCartesianGrid * diff --git a/src/include/stir/IO/interfile.h b/src/include/stir/IO/interfile.h index ce2595903..aaa0de9a1 100644 --- a/src/include/stir/IO/interfile.h +++ b/src/include/stir/IO/interfile.h @@ -6,7 +6,7 @@ /* Copyright (C) 2000 PARAPET partners Copyright (C) 2000- 2011, Hammersmith Imanet Ltd - Copyright (C) 2018, University College London + Copyright (C) 2018, 2024 University College London This file is part of STIR. SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license @@ -22,6 +22,7 @@ \author Sanida Mustafovic \author PARAPET project \author Richard Brown + \author Robert Twyman */ @@ -31,6 +32,7 @@ // has to include Succeeded.h (even if it doesn't use the return value). #include "stir/Succeeded.h" #include "stir/ByteOrder.h" +#include "stir/IO/InterfileHeader.h" #include #include @@ -82,6 +84,8 @@ bool is_interfile_signature(const char * const signature); VoxelsOnCartesianGrid* read_interfile_image(std::istream& input, const std::string& directory_for_data = ""); +VoxelsOnCartesianGrid create_image_from_header(InterfileImageHeader& hdr); + //! This reads the first 3d image in an Interfile header file, given as a filename. /*! \ingroup InterfileIO diff --git a/src/utilities/CMakeLists.txt b/src/utilities/CMakeLists.txt index 5976a124e..464385622 100644 --- a/src/utilities/CMakeLists.txt +++ b/src/utilities/CMakeLists.txt @@ -74,7 +74,7 @@ set(${dir_EXE_SOURCES} find_sum_projection_of_viewgram_and_sinogram.cxx separate_true_from_random_scatter_for_necr.cxx stir_timings.cxx - create_empty_interfile_binary.cxx + create_empty_interfile_binary.cxx ) if (HAVE_ITK) diff --git a/src/utilities/create_empty_interfile_binary.cxx b/src/utilities/create_empty_interfile_binary.cxx index ce993b751..a0e692362 100644 --- a/src/utilities/create_empty_interfile_binary.cxx +++ b/src/utilities/create_empty_interfile_binary.cxx @@ -15,6 +15,10 @@ be used for collaborative development. If one user experiences issues with STIR, the only the header file needs to be transferred to the other user for debugging issues. + This utility will not overwrite existing binary files. + + Currently, requires header file to have a valid extension (.hs or .hv) to determine the type of data. + \author Robert Twyman */ /* @@ -28,10 +32,85 @@ #include #include +#include "stir/ProjData.h" +#include "stir/ProjDataInterfile.h" +#include "stir/IO/InterfileHeader.h" +#include "stir/Succeeded.h" +#include "stir/IO/interfile.h" +#include "stir/utilities.h" +#include "stir/VoxelsOnCartesianGrid.h" +#include "stir/IO/write_to_file.h" + +using namespace stir; + +Succeeded +create_empty_projdata_interfile_binary(char* header_file, float fill_value) +{ + InterfilePDFSHeader hdr; + + if (!hdr.parse(header_file)) + return Succeeded::no; + + if (std::ifstream(hdr.data_file_name).good()) + { + warning("create_empty_projdata_interfile_binary: data file already exists"); + return Succeeded::no; + } + shared_ptr proj_data_sptr(new ProjDataInterfile(hdr.get_exam_info_sptr(), hdr.data_info_sptr, hdr.data_file_name)); + proj_data_sptr->fill(fill_value); + return Succeeded::yes; +} + +Succeeded +create_empty_discretised_density_interfile_binary(char* header_file, float fill_value) +{ + InterfileImageHeader hdr; + if (!hdr.parse(header_file)) + return Succeeded::no; + + if (std::ifstream(hdr.data_file_name).good()) + { + warning("create_empty_discretised_density_interfile_binary: data file already exists"); + return Succeeded::no; + } + + VoxelsOnCartesianGrid density = create_image_from_header(hdr); + density.fill(fill_value); + write_to_file(hdr.data_file_name, density); + return Succeeded::yes; +} -#ifndef STIR_NO_NAMESPACES -using std::cerr; -#endif +Succeeded +process_header_file(char* header_file, float fill_value) +{ + // Verify that the header file is valid and can be parsed + if (!std::ifstream(std::string(header_file).c_str()).is_open()) + error("read_interfile_image: couldn't open file %s\n", header_file); + + if (strlen(header_file) < 3) + { + std::cerr << "Warning: Header file name is too short.\n"; + return Succeeded::no; + } + + std::string header_file_ext = std::string(header_file).substr(strlen(header_file) - 3); + if (header_file_ext == ".hs") + { + std::cerr << "File extension indicates a ProjData. Creating empty ProjData with uniform value: " << fill_value << '\n'; + return create_empty_projdata_interfile_binary(header_file, fill_value); + } + else if (header_file_ext == ".hv") + { + std::cerr << "File extension indicates a DiscretisedDensity. Creating empty DiscretisedDensity with uniform value: " + << fill_value << '\n'; + return create_empty_discretised_density_interfile_binary(header_file, fill_value); + } + else + { + std::cerr << "Error: Invalid header file extension: " << header_file_ext << '\n'; + return Succeeded::no; + } +} int main(int argc, char* argv[]) @@ -63,8 +142,15 @@ main(int argc, char* argv[]) } } - std::cerr << "Valid configuration: " << argv[1] << " " << fill_value << '\n'; - + std::cerr << "Valid configuration:\n\tHeader File:\t" << argv[1] << "\n\tFill Value:\t\t" << fill_value << '\n'; + + if (process_header_file(argv[1], fill_value) == Succeeded::no) + { + std::cerr << "Error: Failed to create empty interfile binary file.\n"; + return EXIT_FAILURE; + } + std::cerr << "Successfully created empty interfile binary file:\n\tHeader File:\t" << argv[1] << "\n\tFill Value:\t\t" + << fill_value << '\n'; return EXIT_SUCCESS; } \ No newline at end of file