-
Notifications
You must be signed in to change notification settings - Fork 94
/
DetectorCoordinateMap.h
157 lines (132 loc) · 5.22 KB
/
DetectorCoordinateMap.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
Copyright 2015, 2017 ETH Zurich, Institute of Particle Physics
Copyright 2020 Positrigo AG, Zurich
Copyright (C) 2021 University College London
This file is part of STIR.
SPDX-License-Identifier: Apache-2.0
See STIR/LICENSE.txt for details
*/
/*!
\file
\ingroup buildblock
\brief Declaration of class stir::DetectorCoordinateMap
\author Jannis Fischer
\author Parisa Khateri
\author Kris Thielemans
*/
#include <fstream>
#include <string>
#include <vector>
#include <random>
#include <map>
#include <boost/algorithm/string.hpp>
#include <boost/unordered_map.hpp>
#ifdef STIR_OPENMP
# include <omp.h>
#endif
#include "stir/CartesianCoordinate3D.h"
#include "stir/DetectionPosition.h"
#ifndef __stir_DetectorCoordinateMap_H__
# define __stir_DetectorCoordinateMap_H__
START_NAMESPACE_STIR
class Succeeded;
/*! Class providing map functionality to convert detector indices to spatial coordinates.
Map files can have 5 or 6 tab- or comma-separated columns. Lines beginning with '#' are ignored. The layer column is
optional \par Format: ring,detector,(layer,)x,y,z An empty line will terminate the reading at that line.
Optionally LOR end-points can be randomly displaced using a Gaussian distribution with standard deviation sigma (in mm).
*/
class DetectorCoordinateMap
{
struct ihash
{
std::size_t operator()(stir::DetectionPosition<> const& detpos) const
{
std::size_t seed = 0;
boost::hash_combine(seed, detpos.axial_coord());
boost::hash_combine(seed, detpos.radial_coord());
boost::hash_combine(seed, detpos.tangential_coord());
return seed;
}
};
public:
typedef boost::unordered_map<stir::DetectionPosition<>, stir::CartesianCoordinate3D<float>, ihash> det_pos_to_coord_type;
typedef boost::unordered_map<stir::DetectionPosition<>, stir::DetectionPosition<>, ihash> unordered_to_ordered_det_pos_type;
//! Constructor calls read_detectormap_from_file( filename ).
DetectorCoordinateMap(const std::string& filename, double sigma = 0.0)
: DetectorCoordinateMap(sigma)
{
read_detectormap_from_file(filename);
}
//! Constructor calls set_detector_map(coord_map).
DetectorCoordinateMap(const det_pos_to_coord_type& coord_map, double sigma = 0.0)
: DetectorCoordinateMap(sigma)
{
set_detector_map(coord_map);
}
//! Reads map from file and stores it.
void read_detectormap_from_file(const std::string& filename);
//! stores the map
/*! applies sorting to standard STIR order */
void set_detector_map(const det_pos_to_coord_type& coord_map);
stir::DetectionPosition<> get_det_pos_for_index(const stir::DetectionPosition<>& index) const
{
return input_index_to_det_pos.at(index);
}
//! Returns a cartesian coordinate given a detection position.
stir::CartesianCoordinate3D<float> get_coordinate_for_det_pos(const stir::DetectionPosition<>& det_pos) const
{
auto coord = det_pos_to_coord.at(det_pos);
if (sigma == 0.0)
return coord;
# ifdef STIR_OPENMP
auto thread_id = omp_get_thread_num();
# else
auto thread_id = 0;
# endif
coord.x() += static_cast<float>(distributions[thread_id](generators[thread_id]));
coord.y() += static_cast<float>(distributions[thread_id](generators[thread_id]));
coord.z() += static_cast<float>(distributions[thread_id](generators[thread_id]));
return coord;
}
//! Returns a cartesian coordinate given an (unsorted) index.
stir::CartesianCoordinate3D<float> get_coordinate_for_index(const stir::DetectionPosition<>& index) const
{
return get_coordinate_for_det_pos(get_det_pos_for_index(index));
}
Succeeded find_detection_position_given_cartesian_coordinate(DetectionPosition<>& det_pos,
const CartesianCoordinate3D<float>& cart_coord) const;
unsigned get_num_tangential_coords() const { return num_tangential_coords; }
unsigned get_num_axial_coords() const { return num_axial_coords; }
unsigned get_num_radial_coords() const { return num_radial_coords; }
protected:
explicit DetectorCoordinateMap(double sigma = 0.0)
: sigma(sigma)
{
# ifdef STIR_OPENMP
generators.resize(omp_get_max_threads());
distributions.resize(omp_get_max_threads());
for (auto& distribution : distributions)
distribution = std::normal_distribution<double>(0.0, sigma);
# else
generators.resize(1);
distributions.resize(1);
distributions[0] = std::normal_distribution<double>(0.0, sigma);
# endif
}
private:
unsigned num_tangential_coords;
unsigned num_axial_coords;
unsigned num_radial_coords;
unordered_to_ordered_det_pos_type input_index_to_det_pos;
det_pos_to_coord_type det_pos_to_coord;
std::map<stir::CartesianCoordinate3D<float>, stir::DetectionPosition<>>
detection_position_map_given_cartesian_coord_keys_3_decimal;
std::map<stir::CartesianCoordinate3D<float>, stir::DetectionPosition<>>
detection_position_map_given_cartesian_coord_keys_2_decimal;
const double sigma;
mutable std::vector<std::default_random_engine> generators;
mutable std::vector<std::normal_distribution<double>> distributions;
static det_pos_to_coord_type read_detectormap_from_file_help(const std::string& crystal_map_name);
};
END_NAMESPACE_STIR
#endif