Skip to content

Commit 54587e7

Browse files
Create SPECT subsets from ProjData (#1596)
* fix SPECT subsets functionality * separated subset tests for pet & spect --------- Co-authored-by: Kris Thielemans <[email protected]>
1 parent f2e1ca3 commit 54587e7

File tree

8 files changed

+665
-23
lines changed

8 files changed

+665
-23
lines changed

documentation/release_6.3.htm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ <h4>General</h4>
7575
larger than the default from the vendor).<br>
7676
<a href=https://github.com/UCL/STIR/pull/1315>PR #1315</a>
7777
</li>
78+
<li>
79+
Adapt the SPECTUB projector to handle data with only a subset of the views (constructed using <code>ProjData::get_subsets()</code>.
80+
This is useful for SIRF/CIL applications using stochastic optimisation.<br>
81+
<a href=https://github.com/UCL/STIR/pull/1596>PR #1596</a>
82+
</li>
7883
</ul>
7984
<h4>Python</h4>
8085
<ul>

examples/samples/SPECT_Interfile_header.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
!imaging modality := nucmed
66

77
; name of file with binary data
8-
name of data file := somefile.s
8+
; Note: we are "self-referring" to the header here such that this file can be read by STIR as a "template".
9+
; (This is used in one of our tests.)
10+
; Obviously, this would normally not be the case.
11+
name of data file := SPECT_Interfile_header.hs
912

1013
!version of keys := 3.3
1114
!GENERAL DATA :=

src/include/stir/recon_buildblock/SPECTUB_Tools.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define _WM_SPECTUB_H
1515

1616
#include <string>
17+
#include <vector>
1718

1819
namespace SPECTUB
1920
{
@@ -84,10 +85,9 @@ typedef struct
8485
int Nsli; // number of slices
8586
float thcm; // slice thickness in cm
8687

87-
int Nang; // number of projection angles
88-
float ang0; // initial projection angle. degrees from upper detection plane (parallel to table). Negative for CW rotacions (see
89-
// manual)
90-
float incr; // angle increment between two consecutive projection angles. Degrees. Negative for CW, Positive for CCW
88+
int Nang; // number of projection angles
89+
std::vector<float> angles; // projection angles. degrees from upper detection plane (parallel to table). Negative for CW
90+
// rotations (see manual)
9191

9292
int NOS; // number of subsets in which to split the matrix
9393
int NangOS; // Number of angles in each subset = Nang/NOS
@@ -339,4 +339,4 @@ void free_wm_da(wm_da_type* f); // to free weight_mat_da
339339

340340
} // namespace SPECTUB
341341

342-
#endif //_WM_SPECT_H
342+
#endif //_WM_SPECT_H

src/recon_buildblock/ProjMatrixByBinSPECTUB.cxx

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@
2424
#include "stir/recon_buildblock/ProjMatrixByBinSPECTUB.h"
2525
#include "stir/recon_buildblock/TrivialDataSymmetriesForBins.h"
2626
#include "stir/ProjDataInfoCylindricalArcCorr.h"
27+
#include "stir/ProjDataInfoSubsetByView.h"
2728
#include "stir/IO/read_from_file.h"
2829
#include "stir/ProjDataInfo.h"
2930
#include "stir/VoxelsOnCartesianGrid.h"
3031
#include "stir/Succeeded.h"
3132
#include "stir/is_null_ptr.h"
3233
#include "stir/Coordinate3D.h"
34+
#include "stir/stream.h"
3335
#include "stir/info.h"
3436
#include "stir/warning.h"
3537
#include "stir/error.h"
@@ -254,9 +256,6 @@ ProjMatrixByBinSPECTUB::set_up(const shared_ptr<const ProjDataInfo>& proj_data_i
254256
this->voxel_size = image_info_ptr->get_voxel_size();
255257
this->origin = image_info_ptr->get_origin();
256258

257-
const ProjDataInfoCylindricalArcCorr* proj_Data_Info_Cylindrical
258-
= dynamic_cast<const ProjDataInfoCylindricalArcCorr*>(this->proj_data_info_ptr.get());
259-
260259
CPUTimer timer;
261260
timer.start();
262261

@@ -299,15 +298,23 @@ ProjMatrixByBinSPECTUB::set_up(const shared_ptr<const ProjDataInfo>& proj_data_i
299298
vox.thcm = vol.thcm;
300299

301300
//... projecction parameters ..........................................
302-
prj.ang0 = this->proj_data_info_ptr->get_scanner_ptr()->get_intrinsic_azimuthal_tilt() * float(180 / _PI);
303-
prj.incr = proj_Data_Info_Cylindrical->get_azimuthal_angle_sampling() * float(180 / _PI);
304-
prj.thcm = proj_Data_Info_Cylindrical->get_axial_sampling(0) / 10;
301+
prj.angles = std::vector<float>(prj.Nang);
302+
{
303+
Bin bin;
304+
for (int i = 0; i < prj.Nang; i++)
305+
{
306+
bin.view_num() = i;
307+
prj.angles[i] = static_cast<float>(this->proj_data_info_ptr->get_phi(bin) * 180 / _PI);
308+
}
309+
// all bins will have same axial sampling
310+
prj.thcm = this->proj_data_info_ptr->get_sampling_in_m(bin) / 10;
311+
}
305312

306313
//.......geometrical and other derived parameters of projection structure...........
307-
prj.Nsli = proj_Data_Info_Cylindrical->get_num_axial_poss(0); // number of slices
308-
prj.lngcm = prj.Nbin * prj.szcm; // length in cm of the detection line
309-
prj.Nbp = prj.Nbin * prj.Nsli; // number of bins for each projection angle (2D-projection)
310-
prj.Nbt = prj.Nbp * prj.Nang; // total number of bins considering all the projection angles
314+
prj.Nsli = this->proj_data_info_ptr->get_num_axial_poss(0); // number of slices
315+
prj.lngcm = prj.Nbin * prj.szcm; // length in cm of the detection line
316+
prj.Nbp = prj.Nbin * prj.Nsli; // number of bins for each projection angle (2D-projection)
317+
prj.Nbt = prj.Nbp * prj.Nang; // total number of bins considering all the projection angles
311318
prj.Nbind2 = (float)prj.Nbin / (float)2.; // half of the number of bins in a detection line (integer or semi-integer)
312319
prj.lngcmd2 = prj.lngcm / (float)2.; // half of the length of detection line (cm)
313320
prj.Nslid2 = (float)prj.Nsli / (float)2.; // half of the number of slices (integer or semi-integer)
@@ -329,7 +336,35 @@ ProjMatrixByBinSPECTUB::set_up(const shared_ptr<const ProjDataInfo>& proj_data_i
329336
wmh.prj.Nsli,
330337
vol.Nsli));
331338
//....rotation radius .................................................
332-
const VectorWithOffset<float> radius_all_views = proj_Data_Info_Cylindrical->get_ring_radii_for_all_views();
339+
VectorWithOffset<float> radius_all_views(prj.Nang);
340+
{
341+
if (auto proj_Data_Info_Cylindrical = dynamic_cast<const ProjDataInfoCylindricalArcCorr*>(this->proj_data_info_ptr.get()))
342+
{
343+
radius_all_views = proj_Data_Info_Cylindrical->get_ring_radii_for_all_views();
344+
}
345+
else if (auto proj_data_info_subset_ptr = dynamic_cast<const ProjDataInfoSubsetByView*>(this->proj_data_info_ptr.get()))
346+
{
347+
if (auto proj_Data_Info_Cylindrical = dynamic_cast<const ProjDataInfoCylindricalArcCorr*>(
348+
proj_data_info_subset_ptr->get_original_proj_data_info_sptr().get()))
349+
{
350+
for (int i = 0; i < prj.Nang; ++i)
351+
{
352+
Bin bin;
353+
bin.view_num() = i;
354+
const int org_view = proj_data_info_subset_ptr->get_original_bin(bin).view_num();
355+
radius_all_views[i] = proj_Data_Info_Cylindrical->get_ring_radius(org_view);
356+
}
357+
}
358+
else
359+
{
360+
error("ProjMatrixByBinSPECTUB: can only handle ProjDataInfoCylindricalArcCorr");
361+
}
362+
}
363+
else
364+
{
365+
error("ProjMatrixByBinSPECTUB: can only handle ProjDataInfoCylindricalArcCorr");
366+
}
367+
}
333368

334369
{
335370
const auto max_radius = *std::max_element(radius_all_views.begin(), radius_all_views.end());
@@ -493,8 +528,7 @@ ProjMatrixByBinSPECTUB::set_up(const shared_ptr<const ProjDataInfo>& proj_data_i
493528
info_stream << "Number of slices: " << wmh.vol.Nsli << "\tslice_thickness: " << wmh.vol.thcm << std::endl;
494529
info_stream << "Number of bins: " << wmh.prj.Nbin << "\tbin size: " << wmh.prj.szcm << "\taxial size: " << wmh.prj.thcm
495530
<< std::endl;
496-
info_stream << "Number of angles: " << wmh.prj.Nang << "\tAngle increment: " << wmh.prj.incr
497-
<< "\tFirst angle: " << wmh.prj.ang0 << std::endl;
531+
info_stream << "Number of angles: " << wmh.prj.Nang << "\tangles (deg): " << wmh.prj.angles << std::endl;
498532
info_stream << "Number of subsets: " << wmh.prj.NOS << std::endl;
499533
if (wmh.do_att)
500534
{

src/recon_buildblock/SPECTUB_Tools.cxx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// system libraries
1414
#include <stdlib.h>
1515
#include <math.h>
16+
1617
using namespace std;
1718

1819
//... user defined libraries .......................................
@@ -301,9 +302,9 @@ fill_ang(angle_type* ang, const SPECTUB::wmh_type& wmh, const float* Rrad)
301302

302303
//... ratios calculation .......................................................
303304

304-
const float deg = wmh.prj.ang0 + (float)i * wmh.prj.incr; // angle in degrees
305-
ang[i].cos = cos(deg * dg2rd); // cosinus of the angle
306-
ang[i].sin = sin(deg * dg2rd); // sinus of the angle
305+
const float deg = wmh.prj.angles[i];
306+
ang[i].cos = cos(deg * dg2rd); // cosinus of the angle
307+
ang[i].sin = sin(deg * dg2rd); // sinus of the angle
307308

308309
//... first octave (0->45degrees) equivalent angle and its trigonometric ratios .......
309310

src/test/CMakeLists.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ set(${dir_SIMPLE_TEST_EXE_SOURCES}
2626
test_DynamicDiscretisedDensity.cxx
2727
test_ScatterSimulation.cxx
2828
test_ML_norm.cxx
29-
test_proj_data_info_subsets.cxx
29+
test_proj_data_info_subsets_pet.cxx
3030
)
3131

3232
set(${dir_SIMPLE_TEST_EXE_SOURCES_NO_REGISTRIES}
@@ -43,6 +43,7 @@ Set(${dir_INVOLVED_TEST_EXE_SOURCES}
4343
test_linear_regression.cxx
4444
test_stir_math.cxx
4545
test_time_of_flight.cxx
46+
test_proj_data_info_subsets_spect.cxx
4647
# the next 2 are interactive, so we don't add a test for it, but only compile them
4748
test_display.cxx
4849
test_interpolate.cxx
@@ -98,6 +99,11 @@ endforeach()
9899

99100
if (BUILD_TESTING)
100101

102+
# Add test for test_proj_data_info_subsets_spect with arguments
103+
ADD_TEST(NAME test_proj_data_info_subsets_spect
104+
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test_proj_data_info_subsets_spect ${CMAKE_SOURCE_DIR}/examples/samples/SPECT_Interfile_header.hs)
105+
add_STIR_CONFIG_DIR(test_proj_data_info_subsets_spect)
106+
101107
ADD_TEST(test_linear_regression
102108
${CMAKE_CURRENT_BINARY_DIR}/test_linear_regression ${CMAKE_CURRENT_SOURCE_DIR}/input/test_linear_regression.in
103109
)
@@ -166,6 +172,7 @@ ADD_TEST(test_IO_DynamicDiscretisedDensity_Interfile_short
166172
ADD_TEST(test_IO_DynamicDiscretisedDensity_Multi
167173
${CMAKE_CURRENT_BINARY_DIR}/test_IO_DynamicDiscretisedDensity ${CMAKE_CURRENT_SOURCE_DIR}/input/test_MultiOutputFileFormat.in)
168174

175+
169176
endif(BUILD_TESTING)
170177

171178
endif() # MINI_STIR

0 commit comments

Comments
 (0)