ImageToInterpolationCoefficients.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2015 Imperial College London
5  * Copyright 2013-2015 Andreas Schuh
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifndef MIRTK_ImageToInterpolationCoefficients_H
21 #define MIRTK_ImageToInterpolationCoefficients_H
22 
23 #include "mirtk/Math.h"
24 #include "mirtk/Voxel.h"
25 #include "mirtk/GenericImage.h"
26 #include "mirtk/Parallel.h"
27 #include "mirtk/Stream.h"
28 #include "mirtk/Queue.h"
29 
30 
31 namespace mirtk {
32 
33 
34 // -----------------------------------------------------------------------------
35 template <class TData, class TReal>
36 TData InitialAntiCausalCoefficient(TData c[], int n, TReal z)
37 {
38  // this initialization corresponds to mirror boundaries
39  return ((z / (z * z - TReal(1))) * (z * c[n - 2] + c[n - 1]));
40 }
41 
42 // -----------------------------------------------------------------------------
43 template <class TData, class TReal>
44 TData InitialCausalCoefficient(TData c[], int n, TReal z, TReal tol)
45 {
46  TData sum;
47  // this initialization corresponds to mirror boundaries
48  int m;
49  if (tol > 0) m = static_cast<int>(ceil(log(tol) / log(abs(z))));
50  else m = n;
51  // accelerated loop
52  if (m < n) {
53  TReal zn = z;
54  sum = c[0];
55  for (int i = 1; i < m; ++i) {
56  sum += zn * c[i];
57  zn *= z;
58  }
59  // full loop
60  } else {
61  const TReal iz = TReal(1) / z;
62  TReal zn = z;
63  TReal z2n = pow(z, TReal(n - 1));
64  sum = c[0] + z2n * c[n - 1];
65  z2n *= z2n * iz;
66  for (int i = 1; i <= n - 2; ++i) {
67  sum += (zn + z2n) * c[i];
68  zn *= z;
69  z2n *= iz;
70  }
71  sum /= (TReal(1) - zn * zn);
72  }
73  return sum;
74 }
75 
76 // -----------------------------------------------------------------------------
77 template <class TData, class TReal>
78 void ConvertToInterpolationCoefficients(TData *c, int n, const TReal *z, int npoles, TReal tol)
79 {
80  // special case required by mirror boundaries
81  if (n < 2) return;
82  // compute the overall gain
83  TReal lambda = TReal(1);
84  for (int k = 0; k < npoles; ++k) {
85  lambda *= (TReal(1) - z[k]) * (TReal(1) - TReal(1) / z[k]);
86  }
87  // apply the gain
88  for (int i = 0; i < n; ++i) c[i] *= lambda;
89  // loop over all poles
90  for (int k = 0; k < npoles; ++k) {
91  // causal initialization
92  c[0] = InitialCausalCoefficient(c, n, z[k], tol);
93  // causal recursion
94  for (int i = 1; i < n; ++i) c[i] += z[k] * c[i - 1];
95  // anticausal initialization
96  c[n - 1] = InitialAntiCausalCoefficient(c, n, z[k]);
97  // anticausal recursion
98  for (int i = n - 2; i >= 0; --i) c[i] = z[k] * (c[i + 1] - c[i]);
99  }
100 }
101 
102 // -----------------------------------------------------------------------------
103 template <class TData, class TReal>
104 struct ConvertToInterpolationCoefficientsBase
105 {
106  ConvertToInterpolationCoefficientsBase(GenericImage<TData> &image, const TReal *z, int npoles)
107  :
108  _image(image), _z(z), _npoles(npoles)
109  {}
110 
111  void Process(TData *data, int n) const
112  {
113  ConvertToInterpolationCoefficients(data, n, _z, _npoles, static_cast<TReal>(DBL_EPSILON));
114  }
115 
116 protected:
117  GenericImage<TData> &_image;
118  const TReal *_z;
119  int _npoles;
120 };
121 
122 // -----------------------------------------------------------------------------
123 template <class TData, class TReal>
124 struct ConvertToInterpolationCoefficientsXFunc : public ConvertToInterpolationCoefficientsBase<TData, TReal>
125 {
126  ConvertToInterpolationCoefficientsXFunc(GenericImage<TData> &image, const TReal *z, int npoles)
127  :
128  ConvertToInterpolationCoefficientsBase<TData, TReal>(image, z, npoles)
129  {}
130 
131  void operator()(const blocked_range3d<int> &re) const
132  {
133  TData *data = new TData[this->_image.X()];
134  for (int l = re.pages().begin(); l != re.pages().end(); ++l)
135  for (int k = re.rows ().begin(); k != re.rows ().end(); ++k)
136  for (int j = re.cols ().begin(); j != re.cols ().end(); ++j) {
137  for (int i = 0; i < this->_image.X(); ++i) {
138  data[i] = this->_image(i, j, k, l);
139  }
140  this->Process(data, this->_image.X());
141  for (int i = 0; i < this->_image.X(); ++i) {
142  this->_image(i, j, k, l) = data[i];
143  }
144  }
145  delete[] data;
146  }
147 
148  void operator()(int l = -1)
149  {
150  int L = this->_image.T();
151  if (0 <= l && l < this->_image.T()) L = l+1;
152  else l = 0;
153  blocked_range3d<int> re(l, L, 0, this->_image.Z(), 0, this->_image.Y());
154  parallel_for(re, *this);
155  }
156 
157  void operator()(int k, int l)
158  {
159  blocked_range3d<int> re(l, l+1, k, k+1, 0, this->_image.Y());
160  parallel_for(re, *this);
161  }
162 };
163 
164 // -----------------------------------------------------------------------------
165 template <class TData, class TReal>
166 struct ConvertToInterpolationCoefficientsYFunc : public ConvertToInterpolationCoefficientsBase<TData, TReal>
167 {
168  ConvertToInterpolationCoefficientsYFunc(GenericImage<TData> &image, const TReal *z, int npoles)
169  :
170  ConvertToInterpolationCoefficientsBase<TData, TReal>(image, z, npoles)
171  {}
172 
173  void operator()(const blocked_range3d<int> &re) const
174  {
175  TData *data = new TData[this->_image.Y()];
176  for (int l = re.pages().begin(); l != re.pages().end(); ++l)
177  for (int k = re.rows ().begin(); k != re.rows ().end(); ++k)
178  for (int i = re.cols ().begin(); i != re.cols ().end(); ++i) {
179  for (int j = 0; j < this->_image.Y(); ++j) {
180  data[j] = this->_image(i, j, k, l);
181  }
182  this->Process(data, this->_image.Y());
183  for (int j = 0; j < this->_image.Y(); ++j) {
184  this->_image(i, j, k, l) = data[j];
185  }
186  }
187  delete[] data;
188  }
189 
190  void operator()(int l = -1)
191  {
192  int L = this->_image.T();
193  if (0 <= l && l < this->_image.T()) L = l+1;
194  else l = 0;
195  blocked_range3d<int> re(l, L, 0, this->_image.Z(), 0, this->_image.X());
196  parallel_for(re, *this);
197  }
198 
199  void operator()(int k, int l)
200  {
201  blocked_range3d<int> re(l, l+1, k, k+1, 0, this->_image.X());
202  parallel_for(re, *this);
203  }
204 };
205 
206 // -----------------------------------------------------------------------------
207 template <class TData, class TReal>
208 struct ConvertToInterpolationCoefficientsZFunc : public ConvertToInterpolationCoefficientsBase<TData, TReal>
209 {
210  ConvertToInterpolationCoefficientsZFunc(GenericImage<TData> &image, const TReal *z, int npoles)
211  :
212  ConvertToInterpolationCoefficientsBase<TData, TReal>(image, z, npoles)
213  {}
214 
215  void operator()(const blocked_range3d<int> &re) const
216  {
217  TData *data = new TData[this->_image.Z()];
218  for (int l = re.pages().begin(); l != re.pages().end(); ++l)
219  for (int j = re.rows ().begin(); j != re.rows ().end(); ++j)
220  for (int i = re.cols ().begin(); i != re.cols ().end(); ++i) {
221  for (int k = 0; k < this->_image.Z(); ++k) {
222  data[k] = this->_image(i, j, k, l);
223  }
224  this->Process(data, this->_image.Z());
225  for (int k = 0; k < this->_image.Z(); ++k) {
226  this->_image(i, j, k, l) = data[k];
227  }
228  }
229  delete[] data;
230  }
231 
232  void operator()(int l = -1)
233  {
234  int L = this->_image.T();
235  if (0 <= l && l < this->_image.T()) L = l+1;
236  else l = 0;
237  blocked_range3d<int> re(l, L, 0, this->_image.Y(), 0, this->_image.X());
238  parallel_for(re, *this);
239  }
240 };
241 
242 // -----------------------------------------------------------------------------
243 template <class TData, class TReal>
244 struct ConvertToInterpolationCoefficientsTFunc : public ConvertToInterpolationCoefficientsBase<TData, TReal>
245 {
246  ConvertToInterpolationCoefficientsTFunc(GenericImage<TData> &image, const TReal *z, int npoles)
247  :
248  ConvertToInterpolationCoefficientsBase<TData, TReal>(image, z, npoles)
249  {}
250 
251  void operator()(const blocked_range3d<int> &re) const
252  {
253  TData *data = new TData[this->_image.T()];
254  for (int k = re.pages().begin(); k != re.pages().end(); ++k)
255  for (int j = re.rows ().begin(); j != re.rows ().end(); ++j)
256  for (int i = re.cols ().begin(); i != re.cols ().end(); ++i) {
257  for (int l = 0; l < this->_image.T(); ++l) {
258  data[l] = this->_image(i, j, k, l);
259  }
260  this->Process(data, this->_image.T());
261  for (int l = 0; l < this->_image.T(); ++l) {
262  this->_image(i, j, k, l) = data[l];
263  }
264  }
265  delete[] data;
266  }
267 
268  void operator()()
269  {
270  blocked_range3d<int> re(0, this->_image.Z(), 0, this->_image.Y(), 0, this->_image.X());
271  parallel_for(re, *this);
272  }
273 };
274 
275 // -----------------------------------------------------------------------------
276 template <class TData, class TReal>
277 void ConvertToInterpolationCoefficientsX(GenericImage<TData> &image, const TReal *z, int npoles)
278 {
279  ConvertToInterpolationCoefficientsXFunc<TData, TReal> convert(image, z, npoles);
280  convert();
281 }
282 
283 // -----------------------------------------------------------------------------
284 template <class TData, class TReal>
285 void ConvertToInterpolationCoefficientsY(GenericImage<TData> &image, const TReal *z, int npoles)
286 {
287  ConvertToInterpolationCoefficientsYFunc<TData, TReal> convert(image, z, npoles);
288  convert();
289 }
290 
291 // -----------------------------------------------------------------------------
292 template <class TData, class TReal>
293 void ConvertToInterpolationCoefficientsZ(GenericImage<TData> &image, const TReal *z, int npoles)
294 {
295  ConvertToInterpolationCoefficientsZFunc<TData, TReal> convert(image, z, npoles);
296  convert();
297 }
298 
299 // -----------------------------------------------------------------------------
300 template <class TData, class TReal>
301 void ConvertToInterpolationCoefficientsT(GenericImage<TData> &image, const TReal *z, int npoles)
302 {
303  ConvertToInterpolationCoefficientsTFunc<TData, TReal> convert(image, z, npoles);
304  convert();
305 }
306 
307 // -----------------------------------------------------------------------------
308 template <class TData, class TReal>
309 void ConvertToInterpolationCoefficients(GenericImage<TData> &image, const TReal *z, int npoles)
310 {
311  ConvertToInterpolationCoefficientsX(image, z, npoles);
312  ConvertToInterpolationCoefficientsY(image, z, npoles);
313  ConvertToInterpolationCoefficientsZ(image, z, npoles);
314  if (image.TSize() != .0 && image.T() > 1) {
315  ConvertToInterpolationCoefficientsT(image, z, npoles);
316  }
317 }
318 
319 // -----------------------------------------------------------------------------
320 template <class TData, class TReal>
321 void ConvertToInterpolationCoefficientsX(GenericImage<TData> &image, int l, const TReal *z, int npoles)
322 {
323  ConvertToInterpolationCoefficientsXFunc<TData, TReal> convert(image, z, npoles);
324  convert(l);
325 }
326 
327 // -----------------------------------------------------------------------------
328 template <class TData, class TReal>
329 void ConvertToInterpolationCoefficientsY(GenericImage<TData> &image, int l, const TReal *z, int npoles)
330 {
331  ConvertToInterpolationCoefficientsYFunc<TData, TReal> convert(image, z, npoles);
332  convert(l);
333 }
334 
335 // -----------------------------------------------------------------------------
336 template <class TData, class TReal>
337 void ConvertToInterpolationCoefficientsZ(GenericImage<TData> &image, int l, const TReal *z, int npoles)
338 {
339  ConvertToInterpolationCoefficientsZFunc<TData, TReal> convert(image, z, npoles);
340  convert(l);
341 }
342 
343 // -----------------------------------------------------------------------------
344 template <class TData, class TReal>
345 void ConvertToInterpolationCoefficients(GenericImage<TData> &image, int l, const TReal *z, int npoles)
346 {
347  ConvertToInterpolationCoefficientsX(image, l, z, npoles);
348  ConvertToInterpolationCoefficientsY(image, l, z, npoles);
349  ConvertToInterpolationCoefficientsZ(image, l, z, npoles);
350 }
351 
352 // -----------------------------------------------------------------------------
353 template <class TData, class TReal>
354 void ConvertToInterpolationCoefficientsX(GenericImage<TData> &image, int k, int l, const TReal *z, int npoles)
355 {
356  ConvertToInterpolationCoefficientsXFunc<TData, TReal> convert(image, z, npoles);
357  convert(k, l);
358 }
359 
360 // -----------------------------------------------------------------------------
361 template <class TData, class TReal>
362 void ConvertToInterpolationCoefficientsY(GenericImage<TData> &image, int k, int l, const TReal *z, int npoles)
363 {
364  ConvertToInterpolationCoefficientsYFunc<TData, TReal> convert(image, z, npoles);
365  convert(k, l);
366 }
367 
368 // -----------------------------------------------------------------------------
369 template <class TData, class TReal>
370 void ConvertToInterpolationCoefficients(GenericImage<TData> &image, int k, int l, const TReal *z, int npoles)
371 {
372  ConvertToInterpolationCoefficientsX(image, k, l, z, npoles);
373  ConvertToInterpolationCoefficientsY(image, k, l, z, npoles);
374 }
375 
376 // -----------------------------------------------------------------------------
377 /// Recover spline poles from a lookup table
378 template <class TReal>
379 void SplinePoles(int degree, TReal pole[2], int &npoles)
380 {
381  switch (degree) {
382  case 2:
383  npoles = 1;
384  pole[0] = TReal(sqrt(8.0) - 3.0);
385  break;
386  case 3:
387  npoles = 1;
388  pole[0] = TReal(sqrt(3.0) - 2.0);
389  break;
390  case 4:
391  npoles = 2;
392  pole[0] = TReal(sqrt(664.0 - sqrt(438976.0)) + sqrt(304.0) - 19.0);
393  pole[1] = TReal(sqrt(664.0 + sqrt(438976.0)) - sqrt(304.0) - 19.0);
394  break;
395  case 5:
396  npoles = 2;
397  pole[0] = TReal(sqrt(135.0 / 2.0 - sqrt(17745.0 / 4.0)) + sqrt(105.0 / 4.0) - 13.0 / 2.0);
398  pole[1] = TReal(sqrt(135.0 / 2.0 + sqrt(17745.0 / 4.0)) - sqrt(105.0 / 4.0) - 13.0 / 2.0);
399  break;
400  default:
401  cerr << "SplinePoles: Unsupported spline degree: " << degree << endl;
402  exit(1);
403  }
404 }
405 
406 // -----------------------------------------------------------------------------
407 /// Convert 2D floating point scalar or vector image to spline coefficients
408 template <class TData>
409 void ConvertToSplineCoefficients(int degree, GenericImage<TData> &image, int k, int l)
410 {
411  typename voxel_info<TData>::ScalarType poles[2];
412  int npoles;
413  SplinePoles(degree, poles, npoles);
414  ConvertToInterpolationCoefficients(image, k, l, poles, npoles);
415 }
416 
417 // -----------------------------------------------------------------------------
418 /// Convert 3D floating point scalar or vector image to spline coefficients
419 template <class TData>
420 void ConvertToSplineCoefficients(int degree, GenericImage<TData> &image, int l)
421 {
422  typename voxel_info<TData>::ScalarType poles[2];
423  int npoles;
424  SplinePoles(degree, poles, npoles);
425  ConvertToInterpolationCoefficients(image, l, poles, npoles);
426 }
427 
428 // -----------------------------------------------------------------------------
429 /// Convert 4D floating point scalar or vector image to spline coefficients
430 template <class TData>
432 {
433  typename voxel_info<TData>::ScalarType poles[2];
434  int npoles;
435  SplinePoles(degree, poles, npoles);
436  ConvertToInterpolationCoefficients(image, poles, npoles);
437 }
438 
439 // -----------------------------------------------------------------------------
440 /// Convert 3D floating point scalar or vector image to cubic spline coefficients
441 template <class TData>
443 {
444  ConvertToSplineCoefficients(3, image, l);
445 }
446 
447 // -----------------------------------------------------------------------------
448 /// Convert 4D floating point scalar or vector image to cubic spline coefficients
449 template <class TData>
451 {
452  ConvertToSplineCoefficients(3, image);
453 }
454 
455 // -----------------------------------------------------------------------------
456 /// Fill background by front propagation of foreground
457 template <class TData>
459 {
460  int idx, nbr, i, j, k, l;
461  Queue<int> active, next;
462  BinaryImage bg(image.Attributes());
463  for (idx = 0; idx < image.NumberOfVoxels(); ++idx) {
464  if (image.IsBackground(idx)) {
465  if (image.IsNextToForeground(idx)) {
466  active.push(idx);
467  }
468  bg(idx) = 1;
469  }
470  }
471  for (int gen = 0; gen < 3; ++gen) {
472  while (!active.empty()) {
473  idx = active.front();
474  active.pop();
475  if (bg(idx)) {
476  int count = 0;
477  TData value = voxel_cast<TData>(0);
478  image.IndexToVoxel(idx, i, j, k, l);
479  for (int nl = l - 1; nl <= l + 1; ++nl)
480  for (int nk = k - 1; nk <= k + 1; ++nk)
481  for (int nj = j - 1; nj <= j + 1; ++nj)
482  for (int ni = i - 1; ni <= i + 1; ++ni) {
483  nbr = image.VoxelToIndex(ni, nj, nk, nl);
484  if (nbr != idx && image.IsInside(nbr)) {
485  if (bg(nbr)) {
486  next.push(nbr);
487  } else {
488  value += image(nbr);
489  count += 1;
490  }
491  }
492  }
493  value /= static_cast<float>(count);
494  image.Put(idx, value);
495  bg(idx) = 0;
496  }
497  }
498  if (next.empty()) break;
499  active = move(next);
500  }
501 }
502 
503 
504 } // namespace mirtk
505 
506 #endif // MIRTK_ImageToInterpolationCoefficients_H
bool IsBackground(int) const
Whether voxel is within background without index-out-of-bounds check.
Definition: BaseImage.h:1431
void SplinePoles(int degree, TReal pole[2], int &npoles)
Recover spline poles from a lookup table.
int VoxelToIndex(int, int, int=0, int=0) const
Function to convert pixel to index.
Definition: BaseImage.h:1132
const ImageAttributes & Attributes() const
Gets the image attributes.
Definition: BaseImage.h:856
void Put(int, VoxelType)
Function for pixel put access.
Definition: GenericImage.h:545
void FillBackgroundBeforeConversionToSplineCoefficients(GenericImage< TData > &image)
Fill background by front propagation of foreground.
Definition: IOConfig.h:41
bool IsInside(int) const
Whether voxel index is within finite image domain.
Definition: BaseImage.h:1467
bool IsNextToForeground(int) const
Whether at least one neighboring voxel is inside the finite foreground region.
Definition: BaseImage.h:1696
int NumberOfVoxels() const
Returns the total number of voxels.
Definition: BaseImage.h:862
void ConvertToSplineCoefficients(int degree, GenericImage< TData > &image, int k, int l)
Convert 2D floating point scalar or vector image to spline coefficients.
void ConvertToCubicBSplineCoefficients(GenericImage< TData > &image, int l)
Convert 3D floating point scalar or vector image to cubic spline coefficients.
void IndexToVoxel(int, int &, int &) const
Function to convert index to pixel coordinates.
Definition: BaseImage.h:1138
void parallel_for(const Range &range, const Body &body)
parallel_for dummy template function which executes the body serially
Definition: Parallel.h:232