STIR 6.4.0
bin_interpolate.h
Go to the documentation of this file.
1//
2//
3/*
4 Copyright (C) 2003- 2005, Hammersmith Imanet Ltd
5 For internal GE use only.
6*/
17#include "stir/SegmentByView.h"
18#include "stir/Bin.h"
19#include "stir/shared_ptr.h"
20#include "stir/Succeeded.h"
22#include "stir/Coordinate4D.h"
23#include "stir/LORCoordinates.h"
25#include "stir/error.h"
26
27START_NAMESPACE_STIR
28
29static Succeeded
30get_transformed_LOR(LORInAxialAndNoArcCorrSinogramCoordinates<float>& out_lor,
31 const RigidObject3DTransformation& transformation,
32 const Bin& bin,
33 const ProjDataInfo& in_proj_data_info)
34{
35 LORInAxialAndNoArcCorrSinogramCoordinates<float> lor;
36 in_proj_data_info.get_LOR(lor, bin);
37 LORAs2Points<float> lor_as_points;
38 lor.get_intersections_with_cylinder(lor_as_points, lor.radius());
39 // TODO origin
40 // currently, the origin used for proj_data_info is in the centre of the scanner,
41 // while for standard images it is in the centre of the first ring.
42 // This is pretty horrible though, as the transform_point function has no clue
43 // where the origin is
44 // Note that the present shift will make this version compatible with the
45 // version above, as find_bin_given_cartesian_coordinates_of_detection
46 // also uses an origin in the centre of the first ring
47 const float z_shift = (in_proj_data_info.get_scanner_ptr()->get_num_rings() - 1) / 2.F
48 * in_proj_data_info.get_scanner_ptr()->get_ring_spacing();
49 lor_as_points.p1().z() += z_shift;
50 lor_as_points.p2().z() += z_shift;
51 LORAs2Points<float> transformed_lor_as_points(transformation.transform_point(lor_as_points.p1()),
52 transformation.transform_point(lor_as_points.p2()));
53 transformed_lor_as_points.p1().z() -= z_shift;
54 transformed_lor_as_points.p2().z() -= z_shift;
55 return transformed_lor_as_points.change_representation(out_lor, lor.radius());
56}
57
58static Coordinate4D<float>
59lor_to_coords(const LORInAxialAndNoArcCorrSinogramCoordinates<float>& lor)
60{
61 Coordinate4D<float> coord;
62 coord[1] = lor.z2() - lor.z1();
63 coord[2] = (lor.z2() + lor.z1()) / 2;
64 coord[3] = lor.phi();
65 coord[4] = lor.beta();
66 return coord;
67}
68
69static Coordinate4D<int>
70bin_to_coords(const Bin& bin)
71{
72 Coordinate4D<int> coord;
73 coord[1] = bin.segment_num();
74 coord[2] = bin.axial_pos_num();
75 coord[3] = bin.view_num();
76 coord[4] = bin.tangential_pos_num();
77 return coord;
78}
79
80static Bin
81coords_to_bin(const Coordinate4D<int>& coord)
82{
83 Bin bin;
84 bin.segment_num() = coord[1];
85 bin.axial_pos_num() = coord[2];
86 bin.view_num() = coord[3];
87 bin.tangential_pos_num() = coord[4];
88 return bin;
89}
90
91inline int
92sign(float x)
93{
94 return x >= 0 ? 1 : -1;
95}
96
97inline Coordinate4D<int>
98sign(const Coordinate4D<float>& c)
99{
100 return Coordinate4D<int>(sign(c[1]), sign(c[2]), sign(c[3]), sign(c[4]));
101}
102
103inline Coordinate4D<float>
104abs(const Coordinate4D<float>& c)
105{
106 return Coordinate4D<float>(fabs(c[1]), fabs(c[2]), fabs(c[3]), fabs(c[4]));
107}
108
109inline void
110add_to_bin(VectorWithOffset<shared_ptr<SegmentByView<float>>>& segments, const Bin& bin, const float value)
111{
112 (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += value;
113}
114
115static bool
116is_in_range(const Bin& bin, const ProjDataInfo& proj_data_info)
117{
118 if (bin.segment_num() >= proj_data_info.get_min_segment_num() && bin.segment_num() <= proj_data_info.get_max_segment_num()
119 && bin.tangential_pos_num() >= proj_data_info.get_min_tangential_pos_num()
120 && bin.tangential_pos_num() <= proj_data_info.get_max_tangential_pos_num()
121 && bin.axial_pos_num() >= proj_data_info.get_min_axial_pos_num(bin.segment_num())
122 && bin.axial_pos_num() <= proj_data_info.get_max_axial_pos_num(bin.segment_num()))
123 {
124 assert(bin.view_num() >= proj_data_info.get_min_view_num());
125 assert(bin.view_num() <= proj_data_info.get_max_view_num());
126 return true;
127 }
128 else
129 return false;
130}
131
132static Bin
133standardise(const Bin& in_bin, const ProjDataInfo& proj_data_info)
134{
135 Bin bin = in_bin;
136 bool swap_direction = false;
137 if (bin.view_num() < proj_data_info.get_min_view_num())
138 {
139 swap_direction = true;
140 bin.view_num() += proj_data_info.get_num_views();
141 }
142 else if (bin.view_num() > proj_data_info.get_max_view_num())
143 {
144 swap_direction = true;
145 bin.view_num() -= proj_data_info.get_num_views();
146 }
147 assert(bin.view_num() >= proj_data_info.get_min_view_num());
148 assert(bin.view_num() <= proj_data_info.get_max_view_num());
149
150 if (swap_direction)
151 {
152 bin.tangential_pos_num() *= -1;
153 bin.segment_num() *= -1;
154 }
155 return bin;
156}
157
158static Succeeded
159find_sampling(Coordinate4D<float>& sampling, const Bin& bin, const ProjDataInfo& proj_data_info)
160{
161 LORInAxialAndNoArcCorrSinogramCoordinates<float> tmp_lor;
162 LORInAxialAndNoArcCorrSinogramCoordinates<float> lor;
163 proj_data_info.get_LOR(lor, bin);
164 for (int d = 1; d <= 4; ++d)
165 {
166 Coordinate4D<int> neighbour_coords = bin_to_coords(bin);
167 neighbour_coords[d] += 1;
168 const Bin neighbour = standardise(coords_to_bin(neighbour_coords), proj_data_info);
169 if (!is_in_range(neighbour, proj_data_info))
170 return Succeeded::no;
171 proj_data_info.get_LOR(tmp_lor, neighbour);
172 sampling[d] = (lor_to_coords(tmp_lor) - lor_to_coords(lor))[d];
173 }
174 return Succeeded::yes;
175}
176
177static void
178bin_interpolate(VectorWithOffset<shared_ptr<SegmentByView<float>>>& seg_ptr,
179 const LORInAxialAndNoArcCorrSinogramCoordinates<float>& lor,
180 const ProjDataInfo& out_proj_data_info,
181 const ProjDataInfo& proj_data_info,
182 const float value)
183{
184 Coordinate4D<float> sampling;
185 // warning assuming uniform sampling to avoid problem of neighbour dropping of at the edge
186 if (find_sampling(sampling, Bin(0, 0, 0, 0), proj_data_info) != Succeeded::yes)
187 error("error in finding sampling");
188
189 const Bin central_bin = proj_data_info.get_bin(lor);
190 if (central_bin.get_bin_value() < 0)
191 return;
192 LORInAxialAndNoArcCorrSinogramCoordinates<float> central_lor;
193 proj_data_info.get_LOR(central_lor, central_bin);
194 const Coordinate4D<float> central_lor_coords = lor_to_coords(central_lor);
195 const Coordinate4D<float> lor_coords = lor_to_coords(lor);
196 const Coordinate4D<int> central_bin_coords = bin_to_coords(central_bin);
197 const Coordinate4D<float> diff = (lor_coords - central_lor_coords) / sampling;
198 assert(diff[1] <= 1.001 && diff[1] >= -1.001);
199 assert(diff[2] <= .5001 && diff[2] >= -.5001);
200 assert(diff[3] <= .5001 && diff[3] >= -.5001);
201 assert(diff[4] <= .5001 && diff[4] >= -.5001);
202 const Coordinate4D<int> bin_inc = sign(sampling);
203 assert(bin_inc == Coordinate4D<int>(1, 1, 1, 1));
204 const Coordinate4D<int> inc = sign(diff);
205 Coordinate4D<int> offset;
206
207#if 0
208 for (offset[1]=0; offset[1]!=2*inc[1]; offset[1]+=inc[1])
209 for (offset[2]=0; offset[2]!=2*inc[2]; offset[2]+=inc[2])
210 for (offset[3]=0; offset[3]!=2*inc[3]; offset[3]+=inc[3])
211 for (offset[4]=0; offset[4]!=2*inc[4]; offset[4]+=inc[4])
212#else
213 for (offset[1] = -1; offset[1] != 2; offset[1]++)
214 for (offset[2] = -1; offset[2] != 2; offset[2]++)
215 for (offset[3] = -1; offset[3] != 2; offset[3]++)
216 for (offset[4] = -1; offset[4] != 2; offset[4]++)
217#endif
218 {
219 const Bin target_bin = standardise(coords_to_bin(central_bin_coords + offset), proj_data_info);
220 if (is_in_range(target_bin, proj_data_info))
221 {
222
223 // const BasicCoordinate<4,float> float_offset(offset);
224 // Coordinate4D<float> weights = abs(diff - float_offset);
225
226 LORInAxialAndNoArcCorrSinogramCoordinates<float> new_lor;
227 proj_data_info.get_LOR(new_lor, target_bin);
228 Coordinate4D<float> new_lor_coords = lor_to_coords(new_lor);
229 Coordinate4D<float> new_diff = (lor_coords - new_lor_coords) / sampling;
230 if (fabs(new_diff[3]) > 2)
231 {
232 new_lor_coords[1] *= -1;
233 new_lor_coords[3] += _PI * sign(new_diff[3]);
234 new_lor_coords[4] *= -1;
235 new_diff = (lor_coords - new_lor_coords) / sampling;
236 }
237
238#if 0
239 assert(new_diff[1]<=1.001 && new_diff[1]>=-1.001);
240 assert(new_diff[2]<=1.101 && new_diff[2]>=-1.101);
241 assert(new_diff[3]<=1.001 && new_diff[3]>=-1.001);
242 assert(new_diff[4]<=1.001 && new_diff[4]>=-1.001);
243#endif
244 // assert(norm(new_diff - (diff - float_offset))<.001);
245 Coordinate4D<float> weights = abs(new_diff);
246 if (weights[4] > 1 || weights[3] > 1 || weights[2] > 1 || weights[1] > 1)
247 continue;
248 const float weight = (1 - weights[1]) * (1 - weights[2]) * (1 - weights[3]) * (1 - weights[4]);
249 if (weight < 0.001)
250 continue;
251#if 0
252 const Bin out_bin = target_bin;
253#else
254# if 0
255 const Bin out_bin = out_proj_data_info.get_bin(new_lor);
256 if (out_bin.get_bin_value()<0)
257 continue;
258# else
259 DetectionPositionPair<> detection_positions;
260 dynamic_cast<const ProjDataInfoCylindricalNoArcCorr&>(proj_data_info)
261 .get_det_pos_pair_for_bin(detection_positions, target_bin);
262 Bin out_bin;
263 if (dynamic_cast<const ProjDataInfoCylindricalNoArcCorr&>(out_proj_data_info)
264 .get_bin_for_det_pos_pair(out_bin, detection_positions)
265 == Succeeded::no)
266 continue;
267 if (!is_in_range(out_bin, out_proj_data_info))
268 continue;
269# endif
270#endif
271
272 add_to_bin(seg_ptr, out_bin, value * weight);
273 }
274 }
275}
276
277END_NAMESPACE_STIR
Declaration of class stir::Bin.
defines the stir::Coordinate4D<coordT> class
Declaration of class stir::DetectionPositionPair.
defines various classes for specifying a line in 3 dimensions
Declaration of class stir::ProjDataInfoCylindricalNoArcCorr.
Declaration of class stir::RigidObject3DTransformation.
Declaration of class stir::SegmentByView.
Declaration of class stir::Succeeded.
defines the stir::VectorWithOffset class
int segment_num() const
get segment number for const objects
Definition SegmentIndices.inl:32
Declaration of stir::error()
#define _PI
The constant pi to high precision.
Definition common.h:141
Import of std::shared_ptr, std::dynamic_pointer_cast and std::static_pointer_cast into the stir names...