Xmipp  v3.23.11-Nereus
splines.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Carlos Oscar S. Sorzano (coss@cnb.csic.es)
4  *
5  * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20  * 02111-1307 USA
21  *
22  * All comments concerning this program package may be sent to the
23  * e-mail address 'xmipp@cnb.csic.es'
24  ***************************************************************************/
25 
26 #include "splines.h"
27 #include "integration.h"
28 
29 /* Bspline03 by a LUT ------------------------------------------------------ */
30 double Bspline03LUT(double x)
31 {
32  static bool firstCall = true;
34  static const double deltax = 2.0 / BSPLINE03_SUBSAMPLING;
35  static const double ideltax = 1.0 / deltax;
36  if (firstCall)
37  {
39  table(i) = Bspline03(i * deltax);
40  firstCall = false;
41  }
42  auto i = (size_t)round(fabs(x) * ideltax);
43  if (i >= XSIZE(table)) return 0;
44  else return table(i);
45 }
46 
47 /* Sum spline on a grid ---------------------------------------------------- */
49 {
50  Matrix1D<double> gr(3), ur(3), corner1(3), corner2(3);
51  int i, j, k;
52  double sum = 0.0;
53 
54 // Compute the limits of the spline in the grid coordinate system
55  grid.universe2grid(vectorR3(-2.0, -2.0, -2.0), corner1);
56  grid.universe2grid(vectorR3(2.0, 2.0, 2.0), corner2);
57 
58 // Compute the sum in the points inside the grid
59 // The integer part of the vectors is taken for not picking points
60 // just in the border of the spline, which we know they are 0.
61  for (i = (int)XX(corner1); i <= (int)XX(corner2); i++)
62  for (j = (int)YY(corner1); j <= (int)YY(corner2); j++)
63  for (k = (int)ZZ(corner1); k <= (int)ZZ(corner2); k++)
64  {
65  VECTOR_R3(gr, i, j, k);
66  grid.grid2universe(gr, ur);
67  sum += spatial_Bspline03(ur);
68  }
69  return sum;
70 }
71 
72 double sum_spatial_Bspline03_Grid(const Grid &grid)
73 {
74  double sum = 0;
75  for (size_t i = 0; i < grid.GridsNo(); i++)
76  sum += sum_spatial_Bspline03_SimpleGrid(grid(i));
77  return sum;
78 }
79 
80 /* Line integral through a spline ------------------------------------------ */
81 static Matrix1D<double> global_r;
82 static Matrix1D<double> global_u;
83 static Matrix1D<double> global_aux(3);
84 double spatial_Bspline03_integralf(double alpha)
85 {
86  XX(global_aux) = XX(global_r) + alpha * XX(global_u);
87  YY(global_aux) = YY(global_r) + alpha * YY(global_u);
88  ZZ(global_aux) = ZZ(global_r) + alpha * ZZ(global_u);
89  return spatial_Bspline03LUT(global_aux);
90 }
91 
93  const Matrix1D<double> &u, double alpha0, double alphaF)
94 {
95  global_r = r;
96  global_u = u;
97  return integrateNewtonCotes(&spatial_Bspline03_integralf, alpha0, alphaF, 9);
98 }
99 
100 /* This is very similar to the projection of a voxel volume from -2 to 2.
101  The code is taken from the function project_Volume of Src/projection.cc */
102 //#define DEBUG
104  const Matrix1D<double> &r, const Matrix1D<double> &u)
105 {
106  // Avoids divisions by zero and allows orthogonal rays computation
107  static Matrix1D<double> ur(3);
108  if (XX(u) == 0) XX(ur) = XMIPP_EQUAL_ACCURACY;
109  else XX(ur) = XX(u);
110  if (YY(u) == 0) YY(ur) = XMIPP_EQUAL_ACCURACY;
111  else YY(ur) = YY(u);
112  if (ZZ(u) == 0) ZZ(ur) = XMIPP_EQUAL_ACCURACY;
113  else ZZ(ur) = ZZ(u);
114 
115  // Some precalculated variables
116  double x_sign = SGN(XX(ur));
117  double y_sign = SGN(YY(ur));
118  double z_sign = SGN(ZZ(ur));
119 
120  // Compute the minimum and maximum alpha for the ray
121  double alpha_xmin = (-2 - XX(r)) / XX(ur);
122  double alpha_xmax = (2 - XX(r)) / XX(ur);
123  double alpha_ymin = (-2 - YY(r)) / YY(ur);
124  double alpha_ymax = (2 - YY(r)) / YY(ur);
125  double alpha_zmin = (-2 - ZZ(r)) / ZZ(ur);
126  double alpha_zmax = (2 - ZZ(r)) / ZZ(ur);
127 
128  double alpha_min = XMIPP_MAX(XMIPP_MIN(alpha_xmin, alpha_xmax),
129  XMIPP_MIN(alpha_ymin, alpha_ymax));
130  alpha_min = XMIPP_MAX(alpha_min, XMIPP_MIN(alpha_zmin, alpha_zmax));
131  double alpha_max = XMIPP_MIN(XMIPP_MAX(alpha_xmin, alpha_xmax),
132  XMIPP_MAX(alpha_ymin, alpha_ymax));
133  alpha_max = XMIPP_MIN(alpha_max, XMIPP_MAX(alpha_zmin, alpha_zmax));
134  if (alpha_max - alpha_min < XMIPP_EQUAL_ACCURACY) return 0.0;
135 
136 #ifdef DEBUG
137  std::cout << "Pixel: " << r.transpose() << std::endl
138  << "Dir: " << ur.transpose() << std::endl
139  << "Alpha x:" << alpha_xmin << " " << alpha_xmax << std::endl
140  << " " << (r + alpha_xmin*ur).transpose() << std::endl
141  << " " << (r + alpha_xmax*ur).transpose() << std::endl
142  << "Alpha y:" << alpha_ymin << " " << alpha_ymax << std::endl
143  << " " << (r + alpha_ymin*ur).transpose() << std::endl
144  << " " << (r + alpha_ymax*ur).transpose() << std::endl
145  << "Alpha z:" << alpha_zmin << " " << alpha_zmax << std::endl
146  << " " << (r + alpha_zmin*ur).transpose() << std::endl
147  << " " << (r + alpha_zmax*ur).transpose() << std::endl
148  << "alpha :" << alpha_min << " " << alpha_max << std::endl
149  << std::endl;
150 #endif
151 
152  // Compute the first point in the volume intersecting the ray
153  static Matrix1D<double> v(3);
154  V3_BY_CT(v, ur, alpha_min);
155  V3_PLUS_V3(v, r, v);
156 
157 #ifdef DEBUG
158  std::cout << "First entry point: " << v.transpose() << std::endl;
159  std::cout << " Alpha_min: " << alpha_min << std::endl;
160 #endif
161 
162  // Follow the ray
163  double alpha = alpha_min;
164  double ray_sum = 0;
165  do
166  {
167  double alpha_x = (XX(v) + x_sign - XX(r)) / XX(ur);
168  double alpha_y = (YY(v) + y_sign - YY(r)) / YY(ur);
169  double alpha_z = (ZZ(v) + z_sign - ZZ(r)) / ZZ(ur);
170 
171  // Which dimension will ray move next step into?, it isn't necessary to be only
172  // one.
173  double diffx = ABS(alpha - alpha_x);
174  double diffy = ABS(alpha - alpha_y);
175  double diffz = ABS(alpha - alpha_z);
176  double diff_alpha = XMIPP_MIN(XMIPP_MIN(diffx, diffy), diffz);
177  ray_sum += spatial_Bspline03_integral(r, ur, alpha, alpha + diff_alpha);
178 
179  // Update alpha and the next entry point
180  if (ABS(diff_alpha - diffx) <= XMIPP_EQUAL_ACCURACY) alpha = alpha_x;
181  if (ABS(diff_alpha - diffy) <= XMIPP_EQUAL_ACCURACY) alpha = alpha_y;
182  if (ABS(diff_alpha - diffz) <= XMIPP_EQUAL_ACCURACY) alpha = alpha_z;
183  XX(v) += diff_alpha * XX(ur);
184  YY(v) += diff_alpha * YY(ur);
185  ZZ(v) += diff_alpha * ZZ(ur);
186 
187 #ifdef DEBUG
188  std::cout << "Alpha x,y,z: " << alpha_x << " " << alpha_y
189  << " " << alpha_z << " ---> " << alpha << std::endl;
190 
191  std::cout << " Next entry point: " << v.transpose() << std::endl
192  << " diff_alpha: " << diff_alpha << std::endl
193  << " ray_sum: " << ray_sum << std::endl
194  << " Alfa tot: " << alpha << "alpha_max: " << alpha_max <<
195  std::endl;
196 
197 #endif
198  }
199  while ((alpha_max - alpha) > XMIPP_EQUAL_ACCURACY);
200  return ray_sum;
201 }
202 #undef DEBUG
203 
204 /* Splines -> Voxels for a SimpleGrid -------------------------------------- */
206  const SimpleGrid &grid,
207  MultidimArray<double> *vol_voxels,
208  const MultidimArray<double> *vol_mask = nullptr)
209 {
210  Matrix1D<double> act_coord(3); // Coord: Actual position inside
211  // the voxel volume without deforming
212  Matrix1D<double> beginZ(3); // Coord: Voxel coordinates of the
213  // blob at the 3D point
214  // (z0,YY(lowest),XX(lowest))
215  Matrix1D<double> beginY(3); // Coord: Voxel coordinates of the
216  // blob at the 3D point
217  // (z0,y0,XX(lowest))
218  Matrix1D<int> corner2(3), corner1(3); // Coord: Corners of the blob in the voxel volume
219  Matrix1D<double> gcurrent(3); // Position in g of current point
220  int i, j, k; // Index within the blob volume
221  bool process; // True if this blob has to be
222  // processed
223  double spline_radius = 2 * sqrt(3.0);
224 
225  // Some aliases
226 #define x0 STARTINGX(*vol_voxels)
227 #define xF FINISHINGX(*vol_voxels)
228 #define y0 STARTINGY(*vol_voxels)
229 #define yF FINISHINGY(*vol_voxels)
230 #define z0 STARTINGZ(*vol_voxels)
231 #define zF FINISHINGZ(*vol_voxels)
232 
233 #ifdef DEBUG
234  bool condition = true;
235  (*vol_voxels)().printShape();
236  std::cout << std::endl;
237  std::cout << "x0= " << x0 << " xF= " << xF << std::endl;
238  std::cout << "y0= " << y0 << " yF= " << yF << std::endl;
239  std::cout << "z0= " << z0 << " zF= " << zF << std::endl;
240  std::cout << grid;
241 #endif
242 
243  // Convert the whole grid ...............................................
244  // Corner of the plane defined by Z. These coordinates are in the
245  // universal coord. system
246  grid.grid2universe(grid.lowest, beginZ);
247 
248  Matrix1D<double> grid_index(3);
249  for (k = (int) ZZ(grid.lowest); k <= (int) ZZ(grid.highest); k++)
250  {
251  // Corner of the row defined by Y
252  beginY = beginZ;
253  for (i = (int) YY(grid.lowest); i <= (int) YY(grid.highest); i++)
254  {
255  // First point in the row
256  act_coord = beginY;
257  for (j = (int) XX(grid.lowest); j <= (int) XX(grid.highest); j++)
258  {
259  VECTOR_R3(grid_index, j, i, k);
260 #ifdef DEBUG
261  if (condition)
262  {
263  printf("Dealing spline at (%d,%d,%d) = %f\n", j, i, k, A3D_ELEM(vol_splines, k, i, j));
264  std::cout << "Center of the blob "
265  << act_coord.transpose() << std::endl;
266  }
267 #endif
268 
269  // These two corners are also real valued
270  process = true;
271  if (XX(act_coord) >= xF) process = false;
272  if (YY(act_coord) >= yF) process = false;
273  if (ZZ(act_coord) >= zF) process = false;
274  if (XX(act_coord) <= x0) process = false;
275  if (YY(act_coord) <= y0) process = false;
276  if (ZZ(act_coord) <= z0) process = false;
277 #ifdef DEBUG
278  if (!process && condition) std::cout << " It is outside output volume\n";
279 #endif
280  if (!grid.is_interesting(act_coord))
281  {
282 #ifdef DEBUG
283  if (process && condition) std::cout << " It is not interesting\n";
284 #endif
285  process = false;
286  }
287 
288  if (process)
289  {
290  V3_PLUS_CT(corner1, act_coord, -spline_radius);
291  V3_PLUS_CT(corner2, act_coord, spline_radius);
292 #ifdef DEBUG
293  if (condition)
294  {
295  std::cout << "Corner 1 for this point " << corner1.transpose() << std::endl;
296  std::cout << "Corner 2 for this point " << corner2.transpose() << std::endl;
297  }
298 #endif
299 
300  // Clip the corners to the volume borders
301  XX(corner1) = ROUND(CLIP(XX(corner1), x0, xF));
302  YY(corner1) = ROUND(CLIP(YY(corner1), y0, yF));
303  ZZ(corner1) = ROUND(CLIP(ZZ(corner1), z0, zF));
304  XX(corner2) = ROUND(CLIP(XX(corner2), x0, xF));
305  YY(corner2) = ROUND(CLIP(YY(corner2), y0, yF));
306  ZZ(corner2) = ROUND(CLIP(ZZ(corner2), z0, zF));
307 #ifdef DEBUG
308  if (condition)
309  {
310  std::cout << "Clipped and rounded Corner 1 " << corner1.transpose() << std::endl;
311  std::cout << "Clipped and rounded Corner 2 " << corner2.transpose() << std::endl;
312  }
313 #endif
314 
315  // Effectively convert
316  for (int iz = ZZ(corner1); iz <= ZZ(corner2); iz++)
317  {
318  double intz=iz;
319  for (int iy = YY(corner1); iy <= YY(corner2); iy++)
320  {
321  double inty=iy;
322  for (int ix = XX(corner1); ix <= XX(corner2); ix++)
323  {
324  if (vol_mask != nullptr)
325  if (!A3D_ELEM(*vol_mask, iz, iy, ix)) continue;
326  double intx=ix;
327 
328  // Compute the spline value at this point
329  VECTOR_R3(gcurrent, static_cast<double>(intx),
330  static_cast<double>(inty), static_cast<double>(intz));
331  V3_MINUS_V3(gcurrent, act_coord, gcurrent);
332  double spline_value = spatial_Bspline03(gcurrent);
333 #ifdef DEBUG_MORE
334  if (condition)
335  {
336  std::cout << "At (" << intx << ","
337  << inty << "," << intz << ") value="
338  << spline_value;
339  std::cout.flush();
340  }
341 #endif
342 
343  // Add at that position the corresponding spline value
344  A3D_ELEM(*vol_voxels, iz, iy, ix) +=
345  A3D_ELEM(vol_splines, k, i, j) * spline_value;
346 #ifdef DEBUG_MORE
347  if (condition)
348  {
349  std::cout << " adding " << A3D_ELEM(vol_splines, k, i, j)
350  << " * " << value_spline << " = "
351  << A3D_ELEM(vol_splines, k, i, j)*
352  value_spline << std::endl;
353  std::cout.flush();
354  }
355 #endif
356  }
357  }
358  }
359  }
360 
361  // Prepare for next iteration
362  XX(act_coord) = XX(act_coord) + grid.relative_size * grid.basis(0, 0);
363  YY(act_coord) = YY(act_coord) + grid.relative_size * grid.basis(1, 0);
364  ZZ(act_coord) = ZZ(act_coord) + grid.relative_size * grid.basis(2, 0);
365  }
366  XX(beginY) = XX(beginY) + grid.relative_size * grid.basis(0, 1);
367  YY(beginY) = YY(beginY) + grid.relative_size * grid.basis(1, 1);
368  ZZ(beginY) = ZZ(beginY) + grid.relative_size * grid.basis(2, 1);
369  }
370  XX(beginZ) = XX(beginZ) + grid.relative_size * grid.basis(0, 2);
371  YY(beginZ) = YY(beginZ) + grid.relative_size * grid.basis(1, 2);
372  ZZ(beginZ) = ZZ(beginZ) + grid.relative_size * grid.basis(2, 2);
373  }
374 }
375 #undef x0
376 #undef y0
377 #undef z0
378 #undef xF
379 #undef yF
380 #undef zF
381 #undef DEBUG
382 #undef DEBUG_MORE
383 
384 /* Splines -> Voxels for a Grid -------------------------------------------- */
385 //#define DEBUG
386 void spatial_Bspline032voxels(const GridVolume &vol_splines,
387  MultidimArray<double> *vol_voxels, int Zdim, int Ydim, int Xdim)
388 {
389  // Resize and set starting corner .......................................
390  if (Zdim == 0 || Ydim == 0 || Xdim == 0)
391  {
392  Matrix1D<double> size = vol_splines.grid(0).highest -
393  vol_splines.grid(0).lowest;
394  Matrix1D<double> corner = vol_splines.grid(0).lowest;
395  (*vol_voxels).initZeros(CEIL(ZZ(size)), CEIL(YY(size)), CEIL(XX(size)));
396  STARTINGX(*vol_voxels) = FLOOR(XX(corner));
397  STARTINGY(*vol_voxels) = FLOOR(YY(corner));
398  STARTINGZ(*vol_voxels) = FLOOR(ZZ(corner));
399  }
400  else
401  {
402  (*vol_voxels).initZeros(Zdim, Ydim, Xdim);
403  (*vol_voxels).setXmippOrigin();
404  }
405 
406  // Convert each subvolume ...............................................
407  for (size_t i = 0; i < vol_splines.VolumesNo(); i++)
408  {
409  spatial_Bspline032voxels_SimpleGrid(vol_splines(i)(), vol_splines.grid(i),
410  vol_voxels);
411 #ifdef DEBUG
412  std::cout << "Spline grid no " << i << " stats: ";
413  vol_splines(i)().printStats();
414  std::cout << std::endl;
415  std::cout << "So far vol stats: ";
416  (*vol_voxels).printStats();
417  std::cout << std::endl;
418  VolumeXmipp save;
419  save() = *vol_voxels;
420  save.write((std::string)"PPPvoxels" + integerToString(i));
421 #endif
422  }
423 
424  // Now normalise the resulting volume ..................................
425  double inorm = 1.0 / sum_spatial_Bspline03_Grid(vol_splines.grid());
426  FOR_ALL_ELEMENTS_IN_ARRAY3D(*vol_voxels)
427  A3D_ELEM(*vol_voxels, k, i, j) *= inorm;
428 
429  // Set voxels outside interest region to minimum value .................
430  double R = vol_splines.grid(0).get_interest_radius();
431  if (R != -1)
432  {
433  double R2 = (R - 6) * (R - 6);
434 
435  // Compute minimum value within sphere
436  double min_val = A3D_ELEM(*vol_voxels, 0, 0, 0);
437  FOR_ALL_ELEMENTS_IN_ARRAY3D(*vol_voxels)
438  if (j*j + i*i + k*k <= R2 - 4)
439  min_val = XMIPP_MIN(min_val, A3D_ELEM(*vol_voxels, k, i, j));
440 
441  // Substitute minimum value
442  R2 = (R - 2) * (R - 2);
443  FOR_ALL_ELEMENTS_IN_ARRAY3D(*vol_voxels)
444  if (j*j + i*i + k*k >= R2)
445  A3D_ELEM(*vol_voxels, k, i, j) = min_val;
446  }
447 }
448 #undef DEBUG
449 
void universe2grid(const Matrix1D< double > &uv, Matrix1D< double > &gv) const
Definition: grids.h:349
#define XMIPP_MAX(x, y)
Definition: xmipp_macros.h:193
Matrix1D< double > highest
Definition: grids.h:161
double spatial_Bspline03_integralf(double alpha)
Definition: splines.cpp:84
#define zF
#define V3_PLUS_CT(a, b, c)
Definition: matrix1d.h:220
void grid2universe(const Matrix1D< double > &gv, Matrix1D< double > &uv) const
Definition: grids.h:318
#define y0
void sqrt(Image< double > &op)
size_t GridsNo() const
Definition: grids.h:536
#define xF
Matrix1D< double > vectorR3(double x, double y, double z)
Definition: matrix1d.cpp:892
double sum_spatial_Bspline03_SimpleGrid(const SimpleGrid &grid)
Definition: splines.cpp:48
#define V3_MINUS_V3(a, b, c)
Definition: matrix1d.h:202
double spatial_Bspline03LUT(const Matrix1D< double > &r)
Definition: splines.h:60
double spatial_Bspline03(const Matrix1D< double > &r)
Definition: splines.h:44
#define z0
double spatial_Bspline03_integral(const Matrix1D< double > &r, const Matrix1D< double > &u, double alpha0, double alphaF)
Definition: splines.cpp:92
String integerToString(int I, int _width, char fill_with)
Definition: grids.h:479
Matrix1D< double > lowest
Definition: grids.h:158
#define STARTINGX(v)
doublereal * x
#define i
ql0001_ & k(htemp+1),(cvec+1),(atemp+1),(bj+1),(bl+1),(bu+1),(x+1),(clamda+1), &iout, infoqp, &zero,(w+1), &lenw,(iw+1), &leniw, &glob_grd.epsmac
Matrix1D< T > transpose() const
Definition: matrix1d.cpp:644
#define STARTINGY(v)
double integrateNewtonCotes(double(*f)(double), double a, double b, int N)
Definition: integration.cpp:32
#define CLIP(x, x0, xF)
Definition: xmipp_macros.h:260
#define A3D_ELEM(V, k, i, j)
#define FOR_ALL_ELEMENTS_IN_ARRAY3D(V)
#define V3_BY_CT(a, b, c)
Definition: matrix1d.h:238
size_t VolumesNo() const
Definition: grids.h:1003
#define FLOOR(x)
Definition: xmipp_macros.h:240
#define XX(v)
Definition: matrix1d.h:85
void transpose(double *array, int size)
#define CEIL(x)
Definition: xmipp_macros.h:225
#define XMIPP_EQUAL_ACCURACY
Definition: xmipp_macros.h:119
#define XSIZE(v)
void write(const FileName &fn) const
double Bspline03(double Argument)
#define ABS(x)
Definition: xmipp_macros.h:142
#define ROUND(x)
Definition: xmipp_macros.h:210
void initZeros()
Definition: matrix1d.h:592
#define XMIPP_MIN(x, y)
Definition: xmipp_macros.h:181
void spatial_Bspline032voxels_SimpleGrid(const MultidimArray< double > &vol_splines, const SimpleGrid &grid, MultidimArray< double > *vol_voxels, const MultidimArray< double > *vol_mask=nullptr)
Definition: splines.cpp:205
#define j
#define YY(v)
Definition: matrix1d.h:93
const int BSPLINE03_SUBSAMPLING
Definition: splines.h:53
#define FOR_ALL_ELEMENTS_IN_ARRAY1D(v)
#define x0
int round(double x)
Definition: ap.cpp:7245
void spatial_Bspline032voxels(const GridVolume &vol_splines, MultidimArray< double > *vol_voxels, int Zdim, int Ydim, int Xdim)
Definition: splines.cpp:386
const SimpleGrid & grid(size_t n) const
Definition: grids.h:978
#define VECTOR_R3(v, x, y, z)
Definition: matrix1d.h:124
double sum_spatial_Bspline03_Grid(const Grid &grid)
Definition: splines.cpp:72
doublereal * u
double spatial_Bspline03_proj(const Matrix1D< double > &r, const Matrix1D< double > &u)
Definition: splines.cpp:103
double get_interest_radius() const
Get reconstruction radius.
Definition: grids.h:268
double Bspline03LUT(double x)
Definition: splines.cpp:30
#define SGN(x)
Definition: xmipp_macros.h:155
#define STARTINGZ(v)
#define yF
#define ZZ(v)
Definition: matrix1d.h:101
#define V3_PLUS_V3(a, b, c)
Definition: matrix1d.h:190