STIR  6.2.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 */
16 #include "stir/VectorWithOffset.h"
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 
27 START_NAMESPACE_STIR
28 
29 static Succeeded
30 get_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 
58 static Coordinate4D<float>
59 lor_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 
69 static Coordinate4D<int>
70 bin_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 
80 static Bin
81 coords_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 
91 inline int
92 sign(float x)
93 {
94  return x >= 0 ? 1 : -1;
95 }
96 
97 inline Coordinate4D<int>
98 sign(const Coordinate4D<float>& c)
99 {
100  return Coordinate4D<int>(sign(c[1]), sign(c[2]), sign(c[3]), sign(c[4]));
101 }
102 
103 inline Coordinate4D<float>
104 abs(const Coordinate4D<float>& c)
105 {
106  return Coordinate4D<float>(fabs(c[1]), fabs(c[2]), fabs(c[3]), fabs(c[4]));
107 }
108 
109 inline void
110 add_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 
115 static bool
116 is_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 
132 static Bin
133 standardise(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 
158 static Succeeded
159 find_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 
177 static void
178 bin_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 
277 END_NAMESPACE_STIR
Declaration of class stir::Succeeded.
#define _PI
The constant pi to high precision.
Definition: common.h:134
defines various classes for specifying a line in 3 dimensions
Declaration of class stir::ProjDataInfoCylindricalNoArcCorr.
Import of std::shared_ptr, std::dynamic_pointer_cast and std::static_pointer_cast (or corresponding b...
Declaration of stir::error()
int view_num() const
get view number for const objects
Definition: ViewgramIndices.inl:36
Declaration of class stir::Bin.
defines the stir::VectorWithOffset class
int segment_num() const
get segment number for const objects
Definition: SegmentIndices.inl:32
Declaration of class stir::SegmentByView.
void error(const char *const s,...)
Print error with format string a la printf and throw exception.
Definition: error.cxx:42
Declaration of class stir::RigidObject3DTransformation.
defines the stir::Coordinate4D<coordT> class
Declaration of class stir::DetectionPositionPair.