Xmipp  v3.23.11-Nereus
projection.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 "projection.h"
27 #include "core/geometry.h"
28 #include "core/metadata_vec.h"
29 #include "core/matrix2d.h"
30 #include "core/xmipp_image.h"
31 #include "core/xmipp_macros.h"
32 #include "core/xmipp_program.h"
33 #include "core/transformations.h"
35 #include "data/basis.h"
36 
37 #define x0 STARTINGX(IMGMATRIX(proj))
38 #define xF FINISHINGX(IMGMATRIX(proj))
39 #define y0 STARTINGY(IMGMATRIX(proj))
40 #define yF FINISHINGY(IMGMATRIX(proj))
41 #define xDim XSIZE(IMGMATRIX(proj))
42 #define yDim YSIZE(IMGMATRIX(proj))
43 
44 // These two structures are needed when projecting and backprojecting using
45 // threads. They make mutual exclusion and synchronization possible.
47 pthread_mutex_t project_mutex = PTHREAD_MUTEX_INITIALIZER;
49 
51 {
52  proj_Xdim = 0;
53  proj_Ydim = 0;
54 
55  axisRot = 0;
56  axisTilt = 0;
57  raxis.initZeros(3);
58 
59  tilt0 = 0;
60  tiltF = 0;
61  tiltStep = 0;
62 
63  Nangle_dev = 0;
64  Nangle_avg = 0;
65 
66  Npixel_dev = 0;
67  Npixel_avg = 0;
68 
69  Ncenter_dev = 0;
70  Ncenter_avg = 0;
71 }
72 
73 
75 {
76  program->addParamsLine(" -i <volume_file> : Volume file to be projected.");
77  program->addParamsLine(" alias --input;");
78  program->addParamsLine(" --oroot <rootname> : Output rootname");
79  program->addParamsLine(" requires --params;");
80  program->addParamsLine("or -o <image_file> : Output image");
81  program->addParamsLine(" alias --output;");
82  program->addParamsLine(" requires --angles;");
83  program->addParamsLine("== Generating a set of projections == ");
84  program->addParamsLine(" [--params <parameters_file>] : File containing projection parameters");
85  program->addParamsLine(" : Check the manual for a description of the parameters");
86  program->addParamsLine(" requires --oroot;");
87  program->addParamsLine("== Generating a single projection == ");
88  program->addParamsLine(" [--angles <tilt> <axisRot=90> <axisTilt=90>] : Tilt angle for a single projection.");
89  program->addParamsLine(" : (axisRot, axisTilt) is the direction of the rotation axis." );
90  program->addParamsLine(" requires -o;");
91  program->addParamsLine("==+ Global projection options== ");
92  program->addParamsLine("[--show_angles] : Print angles value for each projection.");
93  program->addParamsLine("[--only_create_angles] : Projections are not calculated, only the angles values.");
94 }
95 
96 // Read params from command line
98 {
99  fnPhantom = program->getParam("-i");
100 
101  singleProjection = program->checkParam("-o");
102 
103  if (!singleProjection)
104  {
105  fnRoot = program->getParam("--oroot");
106  read(program->getParam("--params"));
107  }
108  else
109  {
110  fnOut = program->getParam("-o");
111 
112  tilt0 = tiltF = program->getDoubleParam("--angles",0);
113  tiltStep = 1;
114 
115  axisRot = program->getDoubleParam("--angles",1);
116  axisTilt = program->getDoubleParam("--angles",2);
117 
118  Image<char> volTemp;
119  volTemp.read(fnPhantom, HEADER);
120  proj_Xdim = XSIZE(VOLMATRIX(volTemp));
121  proj_Ydim = YSIZE(VOLMATRIX(volTemp));
122  }
123 
124  show_angles = program->checkParam("--show_angles");
125  only_create_angles = program->checkParam("--only_create_angles");
126 }
127 
128 /* Read Projection Parameters ============================================== */
130 {
131  if (fn_proj_param.isMetaData())
132  {
133  MetaDataVec MD;
134  size_t objId;
135  MD.read(fn_proj_param);
136  objId = MD.firstRowId();
137  // MD.getValue(MDL_PRJ_VOL, fnPhantom, objId);
138  std::vector<double> vecD;
139  MD.getValue(MDL_PRJ_DIMENSIONS, vecD, objId);
140  proj_Xdim = (int)vecD[0];
141  proj_Ydim = (int)vecD[1];
142  MD.getValue(MDL_ANGLE_ROT, axisRot, objId);
143  MD.getValue(MDL_ANGLE_TILT, axisTilt, objId);
144 
145  raxis.resize(3);
146  if (!MD.getValue(MDL_SHIFT_X, XX(raxis), objId))
147  XX(raxis) = 0;
148  if (!MD.getValue(MDL_SHIFT_Y, YY(raxis), objId))
149  YY(raxis) = 0;
150  if (!MD.getValue(MDL_SHIFT_Z, ZZ(raxis), objId))
151  ZZ(raxis) = 0;
152 
153  MD.getValue(MDL_PRJ_TILT_RANGE, vecD, objId);
154  tilt0 = vecD[0];
155  tiltF = vecD[1];
156  tiltStep = vecD[2];
157 
158  if (MD.getValue(MDL_NOISE_ANGLES, vecD, objId))
159  {
160  Nangle_dev = vecD[0];
161  Nangle_avg = (vecD.size()>1)? vecD[1]: 0;
162  }
163  else
164  Nangle_dev = Nangle_avg = 0;
165 
166  if (MD.getValue(MDL_NOISE_PIXEL_LEVEL, vecD, objId))
167  {
168  Npixel_dev = vecD[0];
169  Npixel_avg = (vecD.size()>1)? vecD[1]: 0;
170  }
171  else
172  Npixel_dev = Npixel_avg = 0;
173 
174  if (MD.getValue(MDL_NOISE_PARTICLE_COORD, vecD, objId))
175  {
176  Ncenter_dev = vecD[0];
177  Ncenter_avg = (vecD.size()>1)? vecD[1]: 0;
178  }
179  else
180  Ncenter_dev = Ncenter_avg = 0;
181  }
182  else
183  {
184  FILE *fh_param;
185  char line[201];
186  int lineNo = 0;
187  char *auxstr;
188 
189  if ((fh_param = fopen(fn_proj_param.c_str(), "r")) == nullptr)
191  (std::string)"ParametersProjectionTomography::read: There is a problem "
192  "opening the file " + fn_proj_param);
193  while (fgets(line, 200, fh_param) != nullptr)
194  {
195  if (line[0] == 0)
196  continue;
197  if (line[0] == '#')
198  continue;
199  if (line[0] == '\n')
200  continue;
201  switch (lineNo)
202  {
203  case 0:
204  fnPhantom = firstWord(line);
205  lineNo = 1;
206  break;
207  case 1:
208  fnOut =
209  firstWord(line);
210  // Next two parameters are optional
211  auxstr = nextToken();
212  if (auxstr != nullptr)
213  starting =
214  textToInteger(auxstr);
216  lineNo = 2;
217  break;
218  case 2:
221  lineNo = 3;
222  break;
223  case 3:
224  axisRot = textToFloat(firstToken(line));
226  lineNo = 4;
227  break;
228  case 4:
229  raxis.resize(3);
230  XX(raxis) = textToFloat(firstToken(line));
233  lineNo = 5;
234  break;
235  case 5:
236  tilt0 = textToFloat(firstToken(line));
239  lineNo = 6;
240  break;
241  case 6:
243  auxstr = nextToken();
244  if (auxstr != nullptr)
245  Nangle_avg = textToFloat(auxstr);
246  else
247  Nangle_avg = 0;
248  lineNo = 7;
249  break;
250  case 7:
252  auxstr = nextToken();
253  if (auxstr != nullptr)
254  Npixel_avg = textToFloat(auxstr);
255  else
256  Npixel_avg = 0;
257  lineNo = 8;
258  break;
259  case 8:
261  auxstr = nextToken();
262  if (auxstr != nullptr)
263  Ncenter_avg = textToFloat(auxstr);
264  else
265  Ncenter_avg = 0;
266  lineNo = 9;
267  break;
268  } /* switch end */
269  } /* while end */
270  if (lineNo != 9)
271  REPORT_ERROR(ERR_ARG_MISSING, (std::string)"ParametersProjectionTomography::read: I "
272  "couldn't read all parameters from file " + fn_proj_param);
273  fclose(fh_param);
274  }
275 }
276 
278  const Matrix1D<double> &sinplane)
279 {
280  // Find Euler rotation matrix
283  Matrix2D<double> Raxis;
284  Matrix2D<double> Rinplane;
285  rotation3DMatrix(angle,axis,Raxis,false);
286  rotation3DMatrix(inplaneRot,'Z',Rinplane,false);
287  double rot;
288  double tilt;
289  double psi;
290  Euler_matrix2angles(Rinplane*Raxis, rot, tilt, psi);
291 
292 
298  if (angle * tilt < 0)
299  Euler_another_set(rot, tilt, psi, rot, tilt, psi);
300 
301  rot = realWRAP(rot,-180,180);
302  if (XMIPP_EQUAL_ZERO(rot))
303  rot = 0.;
304  tilt = realWRAP(tilt,-180,180);
305  if (XMIPP_EQUAL_ZERO(tilt))
306  tilt = 0.;
307  psi = realWRAP(psi,-180,180);
308  if (XMIPP_EQUAL_ZERO(psi))
309  psi = 0.;
310 
311  P.setAngles(rot, tilt, psi);
312 
313  // Find displacement because of axis offset and inplane shift
314  Matrix1D<double> roffset = Rinplane*(raxis-Raxis*raxis) + sinplane;
315 
316  P.setShifts(XX(roffset), YY(roffset), ZZ(roffset));
317 
318 #ifdef DEBUG
319 
320  std::cout << "axisRot=" << axisRot << " axisTilt=" << axisTilt
321  << " axis=" << axis.transpose() << std::endl
322  << "angle=" << angle << std::endl
323  << "Raxis\n" << Raxis
324  << "Rinplane\n" << Rinplane
325  << "Raxis*Rinplane\n" << Raxis*Rinplane
326  << "rot=" << rot << " tilt=" << tilt << " psi=" << psi
327  << std::endl;
329  Euler_angles2matrix(rot,tilt,psi,E);
330  std::cout << "E\n" << E << std::endl;
331 #endif
332 }
333 
334 // Projection from a voxel volume ==========================================
335 /* Project a voxel volume -------------------------------------------------- */
336 //#define DEBUG
337 void projectVolume(MultidimArray<double> &V, Projection &P, int Ydim, int Xdim,
338  double rot, double tilt, double psi,
339  const Matrix1D<double> *roffset)
340 {
342 
343  // Initialise projection
344  P.reset(Ydim, Xdim);
345  P.setAngles(rot, tilt, psi);
346 
347  // Compute the distance for this line crossing one voxel
348  int x_0 = STARTINGX(V);
349  int x_F = FINISHINGX(V);
350  int y_0 = STARTINGY(V);
351  int y_F = FINISHINGY(V);
352  int z_0 = STARTINGZ(V);
353  int z_F = FINISHINGZ(V);
354 
355  // Distances in X and Y between the center of the projection pixel begin
356  // computed and each computed ray
357  double step = 1.0 / 3.0;
358 
359  // Avoids divisions by zero and allows orthogonal rays computation
360  if (XX(P.direction) == 0)
362  if (YY(P.direction) == 0)
364  if (ZZ(P.direction) == 0)
366 
367  // Some precalculated variables
368  int x_sign = SGN(XX(P.direction));
369  int y_sign = SGN(YY(P.direction));
370  int z_sign = SGN(ZZ(P.direction));
371  double half_x_sign = 0.5 * x_sign;
372  double half_y_sign = 0.5 * y_sign;
373  double half_z_sign = 0.5 * z_sign;
374  double iXXP_direction=1.0/XX(P.direction);
375  double iYYP_direction=1.0/YY(P.direction);
376  double iZZP_direction=1.0/ZZ(P.direction);
377 
378  MultidimArray<double> &mP = P();
379  Matrix1D<double> v(3);
380  Matrix1D<double> r_p(3); // r_p are the coordinates of the
381  // pixel being projected in the
382  // coordinate system attached to the
383  // projection
384  Matrix1D<double> p1(3); // coordinates of the pixel in the
385  // universal space
386  Matrix1D<double> p1_shifted(3); // shifted half a pixel
388  {
389  double ray_sum = 0.0; // Line integral value
390 
391  // Computes 4 different rays for each pixel.
392  for (int rays_per_pixel = 0; rays_per_pixel < 4; rays_per_pixel++)
393  {
394  // universal coordinate system
395  switch (rays_per_pixel)
396  {
397  case 0:
398  VECTOR_R3(r_p, j - step, i - step, 0);
399  break;
400  case 1:
401  VECTOR_R3(r_p, j - step, i + step, 0);
402  break;
403  case 2:
404  VECTOR_R3(r_p, j + step, i - step, 0);
405  break;
406  case 3:
407  VECTOR_R3(r_p, j + step, i + step, 0);
408  break;
409  }
410 
411  // Express r_p in the universal coordinate system
412  if (roffset!=nullptr)
413  r_p-=*roffset;
414  M3x3_BY_V3x1(p1, P.eulert, r_p);
415  XX(p1_shifted)=XX(p1)-half_x_sign;
416  YY(p1_shifted)=YY(p1)-half_y_sign;
417  ZZ(p1_shifted)=ZZ(p1)-half_z_sign;
418 
419  // Compute the minimum and maximum alpha for the ray
420  // intersecting the given volume
421  double alpha_xmin = (x_0 - 0.5 - XX(p1))* iXXP_direction;
422  double alpha_xmax = (x_F + 0.5 - XX(p1))* iXXP_direction;
423  double alpha_ymin = (y_0 - 0.5 - YY(p1))* iYYP_direction;
424  double alpha_ymax = (y_F + 0.5 - YY(p1))* iYYP_direction;
425  double alpha_zmin = (z_0 - 0.5 - ZZ(p1))* iZZP_direction;
426  double alpha_zmax = (z_F + 0.5 - ZZ(p1))* iZZP_direction;
427 
428  double auxMin;
429  double auxMax;
430  if (alpha_xmin<alpha_xmax)
431  {
432  auxMin=alpha_xmin;
433  auxMax=alpha_xmax;
434  }
435  else
436  {
437  auxMin=alpha_xmax;
438  auxMax=alpha_xmin;
439  }
440  double alpha_min=auxMin;
441  double alpha_max=auxMax;
442  if (alpha_ymin<alpha_ymax)
443  {
444  auxMin=alpha_ymin;
445  auxMax=alpha_ymax;
446  }
447  else
448  {
449  auxMin=alpha_ymax;
450  auxMax=alpha_ymin;
451  }
452  alpha_min=fmax(auxMin,alpha_min);
453  alpha_max=fmin(auxMax,alpha_max);
454  if (alpha_zmin<alpha_zmax)
455  {
456  auxMin=alpha_zmin;
457  auxMax=alpha_zmax;
458  }
459  else
460  {
461  auxMin=alpha_zmax;
462  auxMax=alpha_zmin;
463  }
464  alpha_min=fmax(auxMin,alpha_min);
465  alpha_max=fmin(auxMax,alpha_max);
466  if (alpha_max - alpha_min < XMIPP_EQUAL_ACCURACY)
467  continue;
468 
469 #ifdef DEBUG
470 
471  std::cout << "Pixel: " << r_p.transpose() << std::endl
472  << "Univ: " << p1.transpose() << std::endl
473  << "Dir: " << P.direction.transpose() << std::endl
474  << "Alpha x:" << alpha_xmin << " " << alpha_xmax << std::endl
475  << " " << (p1 + alpha_xmin*P.direction).transpose() << std::endl
476  << " " << (p1 + alpha_xmax*P.direction).transpose() << std::endl
477  << "Alpha y:" << alpha_ymin << " " << alpha_ymax << std::endl
478  << " " << (p1 + alpha_ymin*P.direction).transpose() << std::endl
479  << " " << (p1 + alpha_ymax*P.direction).transpose() << std::endl
480  << "Alpha z:" << alpha_zmin << " " << alpha_zmax << std::endl
481  << " " << (p1 + alpha_zmin*P.direction).transpose() << std::endl
482  << " " << (p1 + alpha_zmax*P.direction).transpose() << std::endl
483  << "alpha :" << alpha_min << " " << alpha_max << std::endl
484  << std::endl;
485 #endif
486 
487  // Compute the first point in the volume intersecting the ray
488  double zz_idxd;
489  double yy_idxd;
490  double xx_idxd;
491  int zz_idx;
492  int yy_idx;
493  int xx_idx;
494  V3_BY_CT(v, P.direction, alpha_min);
495  V3_PLUS_V3(v, p1, v);
496 
497  // Compute the index of the first voxel
498  xx_idx = ROUND(XX(v));
499  yy_idx = ROUND(YY(v));
500  zz_idx = ROUND(ZZ(v));
501 
502  xx_idxd = xx_idx = CLIP(xx_idx, x_0, x_F);
503  yy_idxd = yy_idx = CLIP(yy_idx, y_0, y_F);
504  zz_idxd = zz_idx = CLIP(zz_idx, z_0, z_F);
505 
506 #ifdef DEBUG
507 
508  std::cout << "First voxel: " << v.transpose() << std::endl;
509  std::cout << " First index: " << idx.transpose() << std::endl;
510  std::cout << " Alpha_min: " << alpha_min << std::endl;
511 #endif
512 
513  // Follow the ray
514  double alpha = alpha_min;
515  do
516  {
517 #ifdef DEBUG
518  std::cout << " \n\nCurrent Value: " << V(zz_idx, yy_idx, xx_idx) << std::endl;
519 #endif
520 
521  double alpha_x = (xx_idxd - XX(p1_shifted))* iXXP_direction;
522  double alpha_y = (yy_idxd - YY(p1_shifted))* iYYP_direction;
523  double alpha_z = (zz_idxd - ZZ(p1_shifted))* iZZP_direction;
524 
525  // Which dimension will ray move next step into?, it isn't necessary to be only
526  // one.
527  double diffx = fabs(alpha-alpha_x);
528  double diffy = fabs(alpha-alpha_y);
529  double diffz = fabs(alpha-alpha_z);
530  int diff_source=0;
531  double diff_alpha=diffx;
532  if (diffy<diff_alpha)
533  {
534  diff_source=1;
535  diff_alpha=diffy;
536  }
537  if (diffz<diff_alpha)
538  {
539  diff_source=2;
540  diff_alpha=diffz;
541  }
542  ray_sum += diff_alpha * A3D_ELEM(V, zz_idx, yy_idx, xx_idx);
543 
544  switch (diff_source)
545  {
546  case 0:
547  alpha = alpha_x;
548  xx_idx += x_sign;
549  xx_idxd = xx_idx;
550  break;
551  case 1:
552  alpha = alpha_y;
553  yy_idx += y_sign;
554  yy_idxd = yy_idx;
555  break;
556  default:
557  alpha = alpha_z;
558  zz_idx += z_sign;
559  zz_idxd = zz_idx;
560  }
561 
562 #ifdef DEBUG
563  std::cout << "Alpha x,y,z: " << alpha_x << " " << alpha_y
564  << " " << alpha_z << " ---> " << alpha << std::endl;
565 
566  XX(v) += diff_alpha * XX(P.direction);
567  YY(v) += diff_alpha * YY(P.direction);
568  ZZ(v) += diff_alpha * ZZ(P.direction);
569 
570  std::cout << " Next entry point: " << v.transpose() << std::endl
571  << " Index: " << idx.transpose() << std::endl
572  << " diff_alpha: " << diff_alpha << std::endl
573  << " ray_sum: " << ray_sum << std::endl
574  << " Alfa tot: " << alpha << "alpha_max: " << alpha_max <<
575  std::endl;
576 #endif
577 
578  }
579  while ((alpha_max - alpha) > XMIPP_EQUAL_ACCURACY);
580  } // for
581 
582  A2D_ELEM(IMGMATRIX(P), i, j) = ray_sum * 0.25;
583 #ifdef DEBUG
584 
585  std::cout << "Assigning P(" << i << "," << j << ")=" << ray_sum << std::endl;
586 #endif
587 
588  }
589 }
590 #undef DEBUG
591 
592 /* Project a voxel volume with respect to an offcentered axis -------------- */
593 //#define DEBUG
595  int Ydim, int Xdim)
596 {
597  Matrix1D<double> roffset(3);
598  P.getShifts(XX(roffset), YY(roffset), ZZ(roffset));
599 
600  projectVolume(V, P, Ydim, Xdim, P.rot(), P.tilt(), P.psi(), &roffset);
601 }
602 
603 // Perform a backprojection ================================================
604 /* Backproject a single projection ----------------------------------------- */
605 //#define DEBUG
606 
607 // Sjors, 16 May 2005
608 // This routine may give volumes with spurious high frequencies.....
610 {
612 
613  // Compute the distance for this line crossing one voxel
614  int x_0 = STARTINGX(V);
615  int x_F = FINISHINGX(V);
616  int y_0 = STARTINGY(V);
617  int y_F = FINISHINGY(V);
618  int z_0 = STARTINGZ(V);
619  int z_F = FINISHINGZ(V);
620 
621  // Avoids divisions by zero and allows orthogonal rays computation
622  if (XX(P.direction) == 0)
624  if (YY(P.direction) == 0)
626  if (ZZ(P.direction) == 0)
628 
629  // Some precalculated variables
630  int x_sign = SGN(XX(P.direction));
631  int y_sign = SGN(YY(P.direction));
632  int z_sign = SGN(ZZ(P.direction));
633  double half_x_sign = 0.5 * x_sign;
634  double half_y_sign = 0.5 * y_sign;
635  double half_z_sign = 0.5 * z_sign;
636 
637  MultidimArray<double> &mP = P();
638  Matrix1D<double> r_p(3); // r_p are the coordinates of the
639  // pixel being projected in the
640  // coordinate system attached to the
641  // projection
642  Matrix1D<double> p1(3); // coordinates of the pixel in the
643  Matrix1D<double> v(3);
644  Matrix1D<int> idx(3);
646  {
647  // Computes 4 different rays for each pixel.
648  VECTOR_R3(r_p, j, i, 0);
649 
650  // Express r_p in the universal coordinate system
651  M3x3_BY_V3x1(p1, P.eulert, r_p);
652 
653  // Compute the minimum and maximum alpha for the ray
654  // intersecting the given volume
655  double alpha_xmin = (x_0 - 0.5 - XX(p1)) / XX(P.direction);
656  double alpha_xmax = (x_F + 0.5 - XX(p1)) / XX(P.direction);
657  double alpha_ymin = (y_0 - 0.5 - YY(p1)) / YY(P.direction);
658  double alpha_ymax = (y_F + 0.5 - YY(p1)) / YY(P.direction);
659  double alpha_zmin = (z_0 - 0.5 - ZZ(p1)) / ZZ(P.direction);
660  double alpha_zmax = (z_F + 0.5 - ZZ(p1)) / ZZ(P.direction);
661 
662  double alpha_min = fmax(fmin(alpha_xmin, alpha_xmax),
663  fmin(alpha_ymin, alpha_ymax));
664  alpha_min = fmax(alpha_min, fmin(alpha_zmin, alpha_zmax));
665  double alpha_max = fmin(fmax(alpha_xmin, alpha_xmax),
666  fmax(alpha_ymin, alpha_ymax));
667  alpha_max = fmin(alpha_max, fmax(alpha_zmin, alpha_zmax));
668  if (alpha_max - alpha_min < XMIPP_EQUAL_ACCURACY)
669  continue;
670 
671  // Compute the first point in the volume intersecting the ray
672  V3_BY_CT(v, P.direction, alpha_min);
673  V3_PLUS_V3(v, p1, v);
674 
675  // Compute the index of the first voxel
676  XX(idx) = CLIP(ROUND(XX(v)), x_0, x_F);
677  YY(idx) = CLIP(ROUND(YY(v)), y_0, y_F);
678  ZZ(idx) = CLIP(ROUND(ZZ(v)), z_0, z_F);
679 
680 
681 #ifdef DEBUG
682 
683  std::cout << "First voxel: " << v.transpose() << std::endl;
684  std::cout << " First index: " << idx.transpose() << std::endl;
685  std::cout << " Alpha_min: " << alpha_min << std::endl;
686 #endif
687 
688  // Follow the ray
689  double alpha = alpha_min;
690  do
691  {
692 #ifdef DEBUG
693  std::cout << " \n\nCurrent Value: " << V(ZZ(idx), YY(idx), XX(idx)) << std::endl;
694 #endif
695 
696  double alpha_x = (XX(idx) + half_x_sign - XX(p1)) / XX(P.direction);
697  double alpha_y = (YY(idx) + half_y_sign - YY(p1)) / YY(P.direction);
698  double alpha_z = (ZZ(idx) + half_z_sign - ZZ(p1)) / ZZ(P.direction);
699 
700  // Which dimension will ray move next step into?, it isn't necessary to be only
701  // one.
702  double diffx = ABS(alpha - alpha_x);
703  double diffy = ABS(alpha - alpha_y);
704  double diffz = ABS(alpha - alpha_z);
705 
706  double diff_alpha = fmin(fmin(diffx, diffy), diffz);
707 
708  A3D_ELEM(V, ZZ(idx), YY(idx), XX(idx)) += diff_alpha * A2D_ELEM(P(), i, j);
709 
710  if (ABS(diff_alpha - diffx) <= XMIPP_EQUAL_ACCURACY)
711  {
712  alpha = alpha_x;
713  XX(idx) += x_sign;
714  }
715  if (ABS(diff_alpha - diffy) <= XMIPP_EQUAL_ACCURACY)
716  {
717  alpha = alpha_y;
718  YY(idx) += y_sign;
719  }
720  if (ABS(diff_alpha - diffz) <= XMIPP_EQUAL_ACCURACY)
721  {
722  alpha = alpha_z;
723  ZZ(idx) += z_sign;
724  }
725 
726  }
727  while ((alpha_max - alpha) > XMIPP_EQUAL_ACCURACY);
728 #ifdef DEBUG
729 
730  std::cout << "Assigning P(" << i << "," << j << ")=" << ray_sum << std::endl;
731 #endif
732 
733  }
734 }
735 #undef DEBUG
736 
737 // Projections from crystals particles #####################################
738 // The projection is not precleaned (set to 0) before projecting and its
739 // angles are supposed to be already written (and all Euler matrices
740 // precalculated
741 // The projection plane is supposed to pass through the Universal coordinate
742 // origin
743 
744 /* Algorithm
745 Compute Eg, proj(ai), proj(bi) and A
746 Compute prjX, prjY, prjZ and prjO which are the projections of the origin
747  and grid axes
748 Compute the blob footprint size in the deformed image space
749  (=deffootprintsize)
750 For each blob in the grid
751  if it is within the unit cell mask
752  // compute actual deformed projection position
753  defactprj=A*(k*projZ+i*projY+j*projX+projO)
754  // compute corners in the deformed image
755  corner1=defactprj-deffootprintsize;
756  corner2=defactprj+ deffootprintsize;
757 
758  for each point (r) in the deformed projection space between (corner1, corner2)
759  compute position (rc) in the undeformed projection space
760  compute position within footprint corresponding to rc (=foot)
761  if it is inside footprint
762  rw=wrap(r);
763  update projection at rw with the data at foot
764 */
765 
766 //#define DEBUG_LITTLE
767 //#define DEBUG
768 //#define DEBUG_INTERMIDIATE
769 #define wrap_as_Crystal(x,y,xw,yw) \
770  xw=(int) intWRAP(x,x0,xF); \
771  yw=(int) intWRAP(y,y0,yF);
772 
774  const Basis &basis,
775  Projection &proj, Projection &norm_proj,
776  const Matrix1D<double> &shift,
777  const Matrix1D<double> &aint, const Matrix1D<double> &bint,
778  const Matrix2D<double> &D, const Matrix2D<double> &Dinv,
779  const MultidimArray<int> &mask, int FORW, int eq_mode)
780 {
781  Matrix1D<double> prjX(3); // Coordinate: Projection of the
782  Matrix1D<double> prjY(3); // 3 grid vectors
783  Matrix1D<double> prjZ(3);
784  Matrix1D<double> prjOrigin(3); // Coordinate: Where in the 2D
785  // projection plane the origin of
786  // the grid projects
787  Matrix1D<double> prjaint(3); // Coordinate: Projection of the
788  Matrix1D<double> prjbint(3); // 2 deformed lattice vectors
789  Matrix1D<double> prjDir; // Direction of projection
790  // in the deformed space
791 
792  Matrix1D<double> actprj(3); // Coord: Actual position inside
793  // the projection plane
794  Matrix1D<double> defactprj(3); // Coord: Actual position inside
795  // the deformed projection plane
796  Matrix1D<double> beginZ(3); // Coord: Plane coordinates of the
797  // projection of the 3D point
798  // (z0,YY(lowest),XX(lowest))
799  Matrix1D<double> beginY(3); // Coord: Plane coordinates of the
800  // projection of the 3D point
801  // (z0,y0,XX(lowest))
802  Matrix1D<double> footprint_size(2); // The footprint is supposed
803  // to be defined between
804  // (-vmax,+vmax) in the Y axis,
805  // and (-umax,+umax) in the X axis
806  // This footprint size is the
807  // R2 vector (umax,vmax).
808  Matrix1D<double> deffootprint_size(2); // The footprint size
809  // in the deformed space
810  int XX_corner2;
811  int XX_corner1; // Coord: Corners of the
812  int YY_corner2;
813  int YY_corner1; // footprint when it is projected
814  // onto the projection plane
815  Matrix1D<double> rc(2);
816  Matrix1D<double> r(2); // Position vector which will
817  // move from corner1 to corner2.
818  // In rc the wrapping is not
819  // considered, while it is in r
820  int foot_V;
821  int foot_U; // Img Coord: coordinate
822  // corresponding to the blobprint
823  // point which matches with this
824  // pixel position
825  double vol_corr=0.; // Correction for a volume element
826  int N_eq; // Number of equations in which
827  // a blob is involved
828  int i;
829  int j;
830  int k; // volume element indexes
831  SPEED_UP_temps01; // Auxiliary variables for
832  // fast multiplications
833 
834  // Check that it is a blob volume .......................................
835  if (basis.type != Basis::blobs)
836  REPORT_ERROR(ERR_VALUE_INCORRECT, "project_Crystal_SimpleGrid: Cannot project other than "
837  "blob volumes");
838 
839  // Compute the deformed direction of projection .........................
840  Matrix2D<double> Eulerg;
841  Eulerg = proj.euler * D;
842 
843  // Compute deformation in the projection space ..........................
844  // The following two vectors are defined in the deformed volume space
845  VECTOR_R3(actprj, XX(aint), YY(aint), 0);
846  grid.Gdir_project_to_plane(actprj, Eulerg, prjaint);
847  VECTOR_R3(actprj, XX(bint), YY(bint), 0);
848  grid.Gdir_project_to_plane(actprj, Eulerg, prjbint);
849  //#define DEBUG_LITTLE
850 #ifdef DEBUG_LITTLE
851 
852  double rot, tilt, psi;
853  Euler_matrix2angles(proj.euler, rot, tilt, psi);
854  std::cout << "rot= " << rot << " tilt= " << tilt
855  << " psi= " << psi << std::endl;
856  std::cout << "D\n" << D << std::endl;
857  std::cout << "Eulerf\n" << proj.euler << std::endl;
858  std::cout << "Eulerg\n" << Eulerg << std::endl;
859  std::cout << "aint " << aint.transpose() << std::endl;
860  std::cout << "bint " << bint.transpose() << std::endl;
861  std::cout << "prjaint " << prjaint.transpose() << std::endl;
862  std::cout << "prjbint " << prjbint.transpose() << std::endl;
863  std::cout.flush();
864 #endif
865  // Project grid axis ....................................................
866  // These vectors ((1,0,0),(0,1,0),...) are referred to the grid
867  // coord. system and the result is a 2D vector in the image plane
868  // The unit size within the image plane is 1, ie, the same as for
869  // the universal grid.
870  // Be careful that these grid vectors are defined in the deformed
871  // volume space, and the projection are defined in the deformed
872  // projections,
873  VECTOR_R3(actprj, 1, 0, 0);
874  grid.Gdir_project_to_plane(actprj, Eulerg, prjX);
875  VECTOR_R3(actprj, 0, 1, 0);
876  grid.Gdir_project_to_plane(actprj, Eulerg, prjY);
877  VECTOR_R3(actprj, 0, 0, 1);
878  grid.Gdir_project_to_plane(actprj, Eulerg, prjZ);
879 
880  // This time the origin of the grid is in the universal coord system
881  // but in the deformed space
882  Uproject_to_plane(grid.origin, Eulerg, prjOrigin);
883 
884  // This is a correction used by the crystallographic symmetries
885  prjOrigin += XX(shift) * prjaint + YY(shift) * prjbint;
886 
887 #ifdef DEBUG_LITTLE
888 
889  std::cout << "prjX " << prjX.transpose() << std::endl;
890  std::cout << "prjY " << prjY.transpose() << std::endl;
891  std::cout << "prjZ " << prjZ.transpose() << std::endl;
892  std::cout << "prjOrigin " << prjOrigin.transpose() << std::endl;
893  std::cout.flush();
894 #endif
895 
896  // Now I will impose that prja becomes (Xdim,0) and prjb, (0,Ydim)
897  // A is a matrix such that
898  // A*prjaint=(Xdim,0)'
899  // A*prjbint=(0,Ydim)'
900  Matrix2D<double> A(2, 2);
901  Matrix2D<double> Ainv(2, 2);
902  A(0, 0) = YY(prjbint) * xDim;
903  A(0, 1) = -XX(prjbint) * xDim;
904  A(1, 0) = -YY(prjaint) * yDim;
905  A(1, 1) = XX(prjaint) * yDim;
906  double nor = 1 / (XX(prjaint) * YY(prjbint) - XX(prjbint) * YY(prjaint));
907  M2x2_BY_CT(A, A, nor);
908  M2x2_INV(Ainv, A);
909 
910 #ifdef DEBUG_LITTLE
911 
912  std::cout << "A\n" << A << std::endl;
913  std::cout << "Ainv\n" << Ainv << std::endl;
914  std::cout << "Check that A*prjaint=(Xdim,0) "
915  << (A*vectorR2(XX(prjaint), YY(prjaint))).transpose() << std::endl;
916  std::cout << "Check that A*prjbint=(0,Ydim) "
917  << (A*vectorR2(XX(prjbint), YY(prjbint))).transpose() << std::endl;
918  std::cout << "Check that Ainv*(Xdim,0)=prjaint "
919  << (Ainv*vectorR2(xDim, 0)).transpose() << std::endl;
920  std::cout << "Check that Ainv*(0,Ydim)=prjbint "
921  << (Ainv*vectorR2(0, yDim)).transpose() << std::endl;
922  std::cout.flush();
923 #endif
924 
925  // Footprint size .......................................................
926  // The following vectors are integer valued vectors, but they are
927  // stored as real ones to make easier operations with other vectors.
928  // Look out that this footprint size is in the deformed projection,
929  // that is why it is not a square footprint but a parallelogram
930  // and we have to look for the smaller rectangle which surrounds it
931  XX(footprint_size) = basis.blobprint.umax();
932  YY(footprint_size) = basis.blobprint.vmax();
933  N_eq = (2 * basis.blobprint.umax() + 1) * (2 * basis.blobprint.vmax() + 1);
934  Matrix1D<double> c1(3);
935  Matrix1D<double> c2(3);
936  XX(c1) = XX(footprint_size);
937  YY(c1) = YY(footprint_size);
938  XX(c2) = -XX(c1);
939  YY(c2) = YY(c1);
940  M2x2_BY_V2x1(c1, A, c1);
941  M2x2_BY_V2x1(c2, A, c2);
942  XX(deffootprint_size) = fmax(fabs(XX(c1)), fabs(XX(c2)));
943  YY(deffootprint_size) = fmax(fabs(YY(c1)), fabs(YY(c2)));
944 
945 #ifdef DEBUG_LITTLE
946 
947  std::cout << "Footprint_size " << footprint_size.transpose() << std::endl;
948  std::cout << "c1: " << c1.transpose() << std::endl;
949  std::cout << "c2: " << c2.transpose() << std::endl;
950  std::cout << "Deformed Footprint_size " << deffootprint_size.transpose()
951  << std::endl;
952  std::cout.flush();
953 #endif
954 
955  // This type conversion gives more speed
956  auto ZZ_lowest = (int) ZZ(grid.lowest);
957  int YY_lowest = XMIPP_MAX((int) YY(grid.lowest), STARTINGY(mask));
958  int XX_lowest = XMIPP_MAX((int) XX(grid.lowest), STARTINGX(mask));
959  auto ZZ_highest = (int) ZZ(grid.highest);
960  int YY_highest = XMIPP_MIN((int) YY(grid.highest), FINISHINGY(mask));
961  int XX_highest = XMIPP_MIN((int) XX(grid.highest), FINISHINGX(mask));
962 
963  // Project the whole grid ...............................................
964  // Corner of the plane defined by Z. These coordinates try to be within
965  // the valid indexes of the projection (defined between STARTING and
966  // FINISHING values, but it could be that they may lie outside.
967  // These coordinates need not to be integer, in general, they are
968  // real vectors.
969  // The vectors returned by the projection routines are R3 but we
970  // are only interested in their first 2 components, ie, in the
971  // in-plane components
972  beginZ = (double)XX_lowest * prjX + (double)YY_lowest * prjY + (double)ZZ_lowest * prjZ + prjOrigin;
973 
974 #ifdef DEBUG_LITTLE
975 
976  std::cout << "BeginZ " << beginZ.transpose() << std::endl;
977  std::cout << "Mask ";
978  mask.printShape();
979  std::cout << std::endl;
980  std::cout << "Vol ";
981  vol().printShape();
982  std::cout << std::endl;
983  std::cout << "Proj ";
984  proj().printShape();
985  std::cout << std::endl;
986  std::cout << "Norm Proj ";
987  norm_proj().printShape();
988  std::cout << std::endl;
989  //std::cout << "Footprint ";
990  //footprint().printShape();
991  //std::cout << std::endl;
992  //std::cout << "Footprint2 ";
993  //footprint2().printShape();
994  //std::cout << std::endl;
995 #endif
996 
997  Matrix1D<double> grid_index(3);
998  for (k = ZZ_lowest; k <= ZZ_highest; k++)
999  {
1000  // Corner of the row defined by Y
1001  beginY = beginZ;
1002  for (i = YY_lowest; i <= YY_highest; i++)
1003  {
1004  // First point in the row
1005  actprj = beginY;
1006  for (j = XX_lowest; j <= XX_highest; j++)
1007  {
1008  VECTOR_R3(grid_index, j, i, k);
1009 #ifdef DEBUG
1010 
1011  std::cout << "Visiting " << i << " " << j << std::endl;
1012 #endif
1013 
1014  // Be careful that you cannot skip any blob, although its
1015  // value be 0, because it is useful for norm_proj
1016  // unless it doesn't belong to the reconstruction mask
1017  if (A2D_ELEM(mask, i, j) && grid.is_interesting(grid_index))
1018  {
1019  // Look for the position in the deformed projection
1020  M2x2_BY_V2x1(defactprj, A, actprj);
1021 
1022  // Search for integer corners for this blob
1023  XX_corner1 = CEIL(XX(defactprj) - XX(deffootprint_size));
1024  YY_corner1 = CEIL(YY(defactprj) - YY(deffootprint_size));
1025  XX_corner2 = FLOOR(XX(defactprj) + XX(deffootprint_size));
1026  YY_corner2 = FLOOR(YY(defactprj) + YY(deffootprint_size));
1027 
1028 #ifdef DEBUG
1029 
1030  std::cout << " k= " << k << " i= " << i << " j= " << j << std::endl;
1031  std::cout << " Actual position: " << actprj.transpose() << std::endl;
1032  std::cout << " Deformed position: " << defactprj.transpose() << std::endl;
1033  std::cout << " Blob corners: (" << XX_corner1 << "," << YY_corner1
1034  << ") (" << XX_corner2 << "," << YY_corner2 << ")\n";
1035  std::cout.flush();
1036 #endif
1037 
1038  // Now there is no way that both corners collapse into a line,
1039  // since the projection points are wrapped
1040 
1041  if (!FORW)
1042  vol_corr = 0;
1043 
1044  // Effectively project this blob
1045  // (xc,yc) is the position of the considered pixel
1046  // in the crystal undeformed projection
1047  // When wrapping and deformation are considered then x and
1048  // y are used
1049 #define xc XX(rc)
1050 #define yc YY(rc)
1051 #define x XX(r)
1052 #define y YY(r)
1053 
1054  for (y = YY_corner1; y <= YY_corner2; y++)
1055  for (x = XX_corner1; x <= XX_corner2; x++)
1056  {
1057  // Compute position in undeformed space and
1058  // corresponding sample in the blob footprint
1059  M2x2_BY_V2x1(rc, Ainv, r);
1060  OVER2IMG(basis.blobprint, yc - YY(actprj), xc - XX(actprj),
1061  foot_V, foot_U);
1062 
1063 #ifdef DEBUG
1064 
1065  std::cout << " Studying: " << r.transpose()
1066  << "--> " << rc.transpose()
1067  << "dist (" << xc - XX(actprj)
1068  << "," << yc - YY(actprj) << ") --> "
1069  << foot_U << " " << foot_V << std::endl;
1070  std::cout.flush();
1071 #endif
1072 
1073  if (IMGMATRIX(basis.blobprint).outside(foot_V, foot_U))
1074  continue;
1075 
1076  // Wrap positions
1077  int yw;
1078  int xw;
1079  wrap_as_Crystal(x, y, xw, yw);
1080 #ifdef DEBUG
1081 
1082  std::cout << " After wrapping " << xw << " " << yw << std::endl;
1083  std::cout << " Value added = " << VOLVOXEL(vol, k, i, j) *
1084  IMGPIXEL(basis.blobprint, foot_V, foot_U) << " Blob value = "
1085  << IMGPIXEL(basis.blobprint, foot_V, foot_U)
1086  << " Blob^2 " << IMGPIXEL(basis.blobprint2, foot_V, foot_U)
1087  << std::endl;
1088  std::cout.flush();
1089 #endif
1090 
1091  if (FORW)
1092  {
1093  IMGPIXEL(proj, yw, xw) += VOLVOXEL(vol, k, i, j) *
1094  IMGPIXEL(basis.blobprint, foot_V, foot_U);
1095  switch (eq_mode)
1096  {
1097  case CAVARTK:
1098  case ARTK:
1099  IMGPIXEL(norm_proj, yw, xw) +=
1100  IMGPIXEL(basis.blobprint2, foot_V, foot_U);
1101  break;
1102  }
1103  }
1104  else
1105  {
1106  vol_corr += IMGPIXEL(norm_proj, yw, xw) *
1107  IMGPIXEL(basis.blobprint, foot_V, foot_U);
1108  }
1109 
1110  }
1111 
1112 #ifdef DEBUG_INTERMIDIATE
1113  proj.write("inter.xmp");
1114  norm_proj.write("inter_norm.xmp");
1115  std::cout << "Press any key\n";
1116  char c;
1117  std::cin >> c;
1118 #endif
1119 
1120  if (!FORW)
1121  switch (eq_mode)
1122  {
1123  case ARTK:
1124  VOLVOXEL(vol, k, i, j) += vol_corr;
1125  break;
1126  case CAVARTK:
1127  VOLVOXEL(vol, k, i, j) += vol_corr / N_eq;
1128  break;
1129  }
1130  }
1131 
1132  // Prepare for next iteration
1133  V2_PLUS_V2(actprj, actprj, prjX);
1134  }
1135  V2_PLUS_V2(beginY, beginY, prjY);
1136  }
1137  V2_PLUS_V2(beginZ, beginZ, prjZ);
1138  }
1139  //#define DEBUG_AT_THE_END
1140 #ifdef DEBUG_AT_THE_END
1141  proj.write("inter.xmp");
1142  norm_proj.write("inter_norm.xmp");
1143  std::cout << "Press any key\n";
1144  char c;
1145  std::cin >> c;
1146 #endif
1147 
1148 #undef xc
1149 #undef yc
1150 #undef x
1151 #undef y
1152 #undef wrap_as_Crystal
1153 }
1154 
1155 /* Project a Grid Volume --------------------------------------------------- */
1156 //#define DEBUG
1158  GridVolume &vol, // Volume
1159  const Basis &basis, // Basis
1160  Projection &proj, // Projection
1161  Projection &norm_proj, // Projection of a unitary volume
1162  int Ydim, // Dimensions of the projection
1163  int Xdim,
1164  double rot, double tilt, double psi, // Euler angles
1165  const Matrix1D<double> &shift, // Shift to apply to projections
1166  const Matrix1D<double> &aint, // First lattice vector (2x1) in voxels
1167  const Matrix1D<double> &bint, // Second lattice vector (2x1) in voxels
1168  const Matrix2D<double> &D, // volume deformation matrix
1169  const Matrix2D<double> &Dinv, // volume deformation matrix
1170  const MultidimArray<int> &mask, // volume mask
1171  int FORW, // 1 if we are projecting a volume
1172  // norm_proj is calculated
1173  // 0 if we are backprojecting
1174  // norm_proj must be valid
1175  int eq_mode) // ARTK, CAVARTK, CAVK or CAV
1176 {
1177  // If projecting forward initialise projections
1178  if (FORW)
1179  {
1180  proj.reset(Ydim, Xdim);
1181  proj.setAngles(rot, tilt, psi);
1182  norm_proj().resize(proj());
1183  }
1184 
1185  // Project each subvolume
1186  for (size_t i = 0; i < vol.VolumesNo(); i++)
1187  {
1188  project_Crystal_SimpleGrid(vol(i), vol.grid(i), basis,
1189  proj, norm_proj, shift, aint, bint, D, Dinv, mask, FORW, eq_mode);
1190 
1191 #ifdef DEBUG
1192 
1193  Image<double> save;
1194  save = norm_proj;
1195  if (FORW)
1196  save.write((std::string)"PPPnorm_FORW" + (char)(48 + i));
1197  else
1198  save.write((std::string)"PPPnorm_BACK" + (char)(48 + i));
1199 #endif
1200 
1201  }
1202 }
1203 #undef DEBUG
1204 
1205 /* Count equations in a grid volume --------------------------------------- */
1207  const Basis &basis, Projection &read_proj)
1208 {
1209  for (size_t i = 0; i < GVNeq.VolumesNo(); i++)
1210  project_SimpleGrid(&(GVNeq(i)), &(GVNeq.grid(i)), &basis,
1211  &read_proj, &read_proj, FORWARD, COUNT_EQ, NULL, NULL);
1212 }
1213 
1214 template <class T>
1215 void *project_SimpleGridThread( void * params )
1216 {
1217  auto * thread_data = (project_thread_params *)params;
1218 
1219  Image<T> * vol;
1220  const SimpleGrid * grid;
1221 
1222  int thread_id = thread_data->thread_id;
1223  int threads_count = thread_data->threads_count;
1224 
1225  const Basis * basis;
1226 
1227  Projection * proj;
1228  Projection * norm_proj;
1229 
1230  auto * forw_proj = new Projection();
1231  auto * forw_norm_proj = new Projection();
1232 
1233  Projection * global_proj;
1234  Projection * global_norm_proj;
1235 
1236  int FORW;
1237  int eq_mode;
1238  const Image<int> *VNeq=NULL;
1239  Matrix2D<double> *M=NULL;
1240  const MultidimArray<int> *mask=NULL;
1241  double ray_length;
1242 
1243  double rot;
1244  double tilt;
1245  double psi;
1246 
1247  do
1248  {
1249  barrier_wait( &project_barrier );
1250 
1251  if( thread_data->destroy == true )
1252  break;
1253 
1254  vol = thread_data->vol;
1255  grid = thread_data->grid;
1256  basis = thread_data->basis;
1257  FORW = thread_data->FORW;
1258  eq_mode = thread_data->eq_mode;
1259  VNeq = thread_data->VNeq;
1260  M = thread_data->M;
1261  mask = thread_data->mask;
1262  ray_length = thread_data->ray_length;
1263  global_proj = thread_data->global_proj;
1264  global_norm_proj = thread_data->global_norm_proj;
1265 
1266  rot = thread_data->rot;
1267  tilt = thread_data->tilt;
1268  psi = thread_data->psi;
1269 
1270  if( FORW )
1271  {
1272  proj = forw_proj;
1273  norm_proj = forw_norm_proj;
1274 
1275  proj->reset(YSIZE( (*global_proj)() ), XSIZE( (*global_proj)() ));
1276  proj->setAngles(rot, tilt, psi);
1277  (*norm_proj)().initZeros((*proj)());
1278  }
1279  else
1280  {
1281  proj = global_proj;
1282  norm_proj = global_norm_proj;
1283  }
1284 
1285  project_SimpleGrid( vol, grid,
1286  basis,
1287  proj,
1288  norm_proj, FORW, eq_mode,
1289  VNeq, M, mask,
1290  ray_length,
1291  thread_id,
1292  threads_count
1293  );
1294 
1295  if( FORW )
1296  {
1297 
1298  pthread_mutex_lock( &project_mutex );
1299 
1300  (*global_proj)() = (*global_proj)() + (*proj)();
1301  (*global_norm_proj)() = (*global_norm_proj)() + (*norm_proj)();
1302 
1303  pthread_mutex_unlock( &project_mutex );
1304  }
1305 
1306  barrier_wait( &project_barrier );
1307  }
1308  while(1);
1309 
1310  return (void *)NULL;
1311 }
1312 
1313 template <class T>
1314 void project_SimpleGrid(Image<T> *vol, const SimpleGrid *grid,
1315  const Basis *basis,
1316  Projection *proj, Projection *norm_proj, int FORW, int eq_mode,
1317  const Image<int> *VNeq, Matrix2D<double> *M,
1318  const MultidimArray<int> *mask,
1319  double ray_length,
1320  int thread_id, int numthreads)
1321 {
1322  Matrix1D<double> zero(3); // Origin (0,0,0)
1323  Matrix1D<double> prjPix(3); // Position of the pixel within the projection
1324  Matrix1D<double> prjX(3); // Coordinate: Projection of the
1325  Matrix1D<double> prjY(3); // 3 grid vectors
1326  Matrix1D<double> prjZ(3);
1327  Matrix1D<double> prjOrigin(3); // Coordinate: Where in the 2D
1328  // projection plane the origin of
1329  // the grid projects
1330  Matrix1D<double> prjDir(3); // Projection direction
1331 
1332  Matrix1D<double> actprj(3); // Coord: Actual position inside
1333  // the projection plane
1334  Matrix1D<double> beginZ(3); // Coord: Plane coordinates of the
1335  // projection of the 3D point
1336  // (z0,YY(lowest),XX(lowest))
1337  Matrix1D<double> univ_beginY(3); // Coord: coordinates of the
1338  // grid point
1339  // (z0,y0,XX(lowest))
1340  Matrix1D<double> univ_beginZ(3); // Coord: coordinates of the
1341  // grid point
1342  // (z0,YY(lowest),XX(lowest))
1343  Matrix1D<double> beginY(3); // Coord: Plane coordinates of the
1344  // projection of the 3D point
1345  // (z0,y0,XX(lowest))
1346  double XX_footprint_size=0.; // The footprint is supposed
1347  double YY_footprint_size=0.; // to be defined between
1348  double ZZ_footprint_size=0.;
1349  // (-vmax,+vmax) in the Y axis,
1350  // and (-umax,+umax) in the X axis
1351  // This footprint size is the
1352  // R2 vector (umax,vmax).
1353 
1354  int XX_corner2;
1355  int XX_corner1; // Coord: Corners of the
1356  int YY_corner2;
1357  int YY_corner1; // footprint when it is projected
1358  // onto the projection plane
1359  int foot_V1=0;
1360  int foot_U1=0; // Img Coord: coordinate (in
1361  // an image fashion, not in an
1362  // oversampled image fashion)
1363  // inside the blobprint of the
1364  // corner1
1365  int foot_V;
1366  int foot_U; // Img Coord: coordinate
1367  int foot_W = 0;
1368  // corresponding to the blobprint
1369  // point which matches with this
1370  // pixel position
1371  int Vsampling=0;
1372  int Usampling=0; // Sampling rate in Y and X
1373  // directions respectively
1374  // inside the blobprint
1375  double vol_corr=0.; // Correction for a volume element
1376  int N_eq; // Number of equations in which
1377  // a blob is involved
1378  int i;
1379  int j;
1380  int k; // volume element indexes
1381  bool isVolPSF = false; // Blob footprint is VolumePSF
1382 
1383  // Prepare system matrix for printing ...................................
1384  if (M != NULL)
1385  M->initZeros(YSIZE((*proj)())*XSIZE((*proj)()), grid->get_number_of_samples());
1386 
1387  // Project grid axis ....................................................
1388  // These vectors ((1,0,0),(0,1,0),...) are referred to the grid
1389  // coord. system and the result is a 2D vector in the image plane
1390  // The unit size within the image plane is 1, ie, the same as for
1391  // the universal grid.
1392  // actprj is reused with a different purpose
1393  VECTOR_R3(actprj, 1, 0, 0);
1394  grid->Gdir_project_to_plane(actprj, proj->euler, prjX);
1395  VECTOR_R3(actprj, 0, 1, 0);
1396  grid->Gdir_project_to_plane(actprj, proj->euler, prjY);
1397  VECTOR_R3(actprj, 0, 0, 1);
1398  grid->Gdir_project_to_plane(actprj, proj->euler, prjZ);
1399 
1400  // This time the origin of the grid is in the universal coord system
1401  Uproject_to_plane(grid->origin, proj->euler, prjOrigin);
1402 
1403  // Get the projection direction .........................................
1404  proj->euler.getRow(2, prjDir);
1405 
1406  // Footprint size .......................................................
1407  // The following vectors are integer valued vectors, but they are
1408  // stored as real ones to make easier operations with other vectors
1409  if (basis->type == Basis::blobs)
1410  {
1411  XX_footprint_size = basis->blobprint.umax();
1412  YY_footprint_size = basis->blobprint.vmax();
1413  Usampling = basis->blobprint.Ustep();
1414  Vsampling = basis->blobprint.Vstep();
1415 
1416  // Set the limit for grid points out of PSF
1417  if (basis->VolPSF != NULL)
1418  {
1419  isVolPSF = true;
1420  ZZ_footprint_size = basis->blobprint.wmax();
1421  }
1422  }
1423  else if (basis->type == Basis::voxels || basis->type == Basis::splines)
1424  {
1425  YY_footprint_size = XX_footprint_size = CEIL(basis->maxLength());
1426  Usampling = Vsampling = 0;
1427  }
1428  XX_footprint_size += XMIPP_EQUAL_ACCURACY;
1429  YY_footprint_size += XMIPP_EQUAL_ACCURACY;
1430 
1431  // Project the whole grid ...............................................
1432  // Corner of the plane defined by Z. These coordinates try to be within
1433  // the valid indexes of the projection (defined between STARTING and
1434  // FINISHING values, but it could be that they may lie outside.
1435  // These coordinates need not to be integer, in general, they are
1436  // real vectors.
1437  // The vectors returned by the projection routines are R3 but we
1438  // are only interested in their first 2 components, ie, in the
1439  // in-plane components
1440 
1441  // This type conversion gives more speed
1442 
1443  auto ZZ_lowest = (int) ZZ(grid->lowest);
1444 
1445  if( thread_id != -1 )
1446  ZZ_lowest += thread_id;
1447 
1448  auto YY_lowest = (int) YY(grid->lowest);
1449  auto XX_lowest = (int) XX(grid->lowest);
1450  auto ZZ_highest = (int) ZZ(grid->highest);
1451  auto YY_highest = (int) YY(grid->highest);
1452  auto XX_highest = (int) XX(grid->highest);
1453 
1454  beginZ = (double)XX_lowest * prjX + (double)YY_lowest * prjY + (double)ZZ_lowest * prjZ + prjOrigin;
1455 
1456  // Check if in VSSNR
1457  bool VSSNR_mode = (ray_length == basis->maxLength());
1458 
1459 #ifdef DEBUG_LITTLE
1460 
1461  int condition;
1462  condition = thread_id==1;
1463  if (condition || numthreads==1)
1464  {
1465  std::cout << "Equation mode " << eq_mode << std::endl;
1466  std::cout << "Footprint size " << YY_footprint_size << "x"
1467  << XX_footprint_size << std::endl;
1468  std::cout << "rot=" << proj->rot() << " tilt=" << proj->tilt()
1469  << " psi=" << proj->psi() << std::endl;
1470  std::cout << "Euler matrix " << proj->euler;
1471  std::cout << "Projection direction " << prjDir << std::endl;
1472  std::cout << *grid;
1473  std::cout << "image limits (" << x0 << "," << y0 << ") (" << xF << ","
1474  << yF << ")\n";
1475  std::cout << "prjX " << prjX.transpose() << std::endl;
1476  std::cout << "prjY " << prjY.transpose() << std::endl;
1477  std::cout << "prjZ " << prjZ.transpose() << std::endl;
1478  std::cout << "prjOrigin " << prjOrigin.transpose() << std::endl;
1479  std::cout << "beginZ(coord) " << beginZ.transpose() << std::endl;
1480  std::cout << "lowest " << XX_lowest << " " << YY_lowest
1481  << " " << XX_lowest << std::endl;
1482  std::cout << "highest " << XX_highest << " " << YY_highest
1483  << " " << XX_highest << std::endl;
1484  std::cout << "Stats of input basis volume ";
1485  (*vol)().printStats();
1486  std::cout << std::endl;
1487  std::cout.flush();
1488  }
1489 #endif
1490 
1491  // Compute the grid lattice vectors in space ............................
1492  Matrix2D<double> grid_basis(3, 3);
1493  grid_basis = grid->basis * grid->relative_size;
1494  Matrix1D<double> gridX(3); // Direction of the grid lattice vectors
1495  Matrix1D<double> gridY(3); // in universal coordinates
1496  Matrix1D<double> gridZ(3);
1497  Matrix1D<double> univ_position(3);
1498 
1499  grid_basis.getCol(0, gridX);
1500  grid_basis.getCol(1, gridY);
1501  grid_basis.getCol(2, gridZ);
1502 
1503  univ_beginZ = (double)XX_lowest * gridX + (double)YY_lowest * gridY + (double)ZZ_lowest * gridZ + grid->origin;
1504 
1505  int number_of_basis = 0;
1506 
1507  for (k = ZZ_lowest; k <= ZZ_highest; k += numthreads)
1508  {
1509  // Corner of the row defined by Y
1510  beginY = beginZ;
1511  univ_beginY = univ_beginZ;
1512  for (i = YY_lowest; i <= YY_highest; i++)
1513  {
1514  // First point in the row
1515  actprj = beginY;
1516  univ_position = univ_beginY;
1517  for (j = XX_lowest; j <= XX_highest; j++)
1518  {
1519  // Ray length interesting
1520  bool ray_length_interesting = true;
1521  double zCenterDist;
1522  double z = 0; // z = 0 standard value for non 3D blobprints
1523 
1524  if (ray_length != -1 || isVolPSF)
1525  {
1526  zCenterDist = point_plane_distance_3D(univ_position, zero,
1527  proj->direction);
1528  if (ray_length != -1)
1529  ray_length_interesting = (ABS(zCenterDist) <= ray_length);
1530 
1531  // Points out of 3DPSF
1532  if (isVolPSF && ray_length_interesting)
1533  {
1534  ray_length_interesting = (ABS(zCenterDist) <= ZZ_footprint_size);
1535  // There is still missing the shift of the volume from focal plane
1536  z = zCenterDist; // + shiftZ
1537  }
1538  }
1539 
1540  if (grid->is_interesting(univ_position) &&
1541  ray_length_interesting)
1542  {
1543  // Be careful that you cannot skip any basis, although its
1544  // value be 0, because it is useful for norm_proj
1545 #ifdef DEBUG
1546  condition = thread_id == 1;
1547  if (condition)
1548  {
1549  printf("\nProjecting grid coord (%d,%d,%d) ", j, i, k);
1550  std::cout << "Vol there = " << VOLVOXEL(*vol, k, i, j) << std::endl;
1551  printf(" 3D universal position (%f,%f,%f) \n",
1552  XX(univ_position), YY(univ_position), ZZ(univ_position));
1553  std::cout << " Center of the basis proj (2D) " << XX(actprj) << "," << YY(actprj) << std::endl;
1554  Matrix1D<double> aux;
1555  Uproject_to_plane(univ_position, proj->euler, aux);
1556  std::cout << " Center of the basis proj (more accurate) " << aux.transpose() << std::endl;
1557  }
1558 #endif
1559 
1560  // Search for integer corners for this basis
1561  XX_corner1 = CEIL(XMIPP_MAX(STARTINGX(IMGMATRIX(*proj)), XX(actprj) - XX_footprint_size));
1562  YY_corner1 = CEIL(XMIPP_MAX(STARTINGY(IMGMATRIX(*proj)), YY(actprj) - YY_footprint_size));
1563  XX_corner2 = FLOOR(XMIPP_MIN(FINISHINGX(IMGMATRIX(*proj)), XX(actprj) + XX_footprint_size));
1564  YY_corner2 = FLOOR(XMIPP_MIN(FINISHINGY(IMGMATRIX(*proj)), YY(actprj) + YY_footprint_size));
1565 
1566 #ifdef DEBUG
1567 
1568  if (condition)
1569  {
1570  std::cout << "Clipped and rounded Corner 1 " << XX_corner1
1571  << " " << YY_corner1 << " " << std::endl;
1572  std::cout << "Clipped and rounded Corner 2 " << XX_corner2
1573  << " " << YY_corner2 << " " << std::endl;
1574  }
1575 #endif
1576 
1577  // Check if the basis falls outside the projection plane
1578  // COSS: I have changed here
1579  if (XX_corner1 <= XX_corner2 && YY_corner1 <= YY_corner2)
1580  {
1581  // Compute the index of the basis for corner1
1582  if (basis->type == Basis::blobs)
1583  {
1584  OVER2IMG(basis->blobprint, (double)YY_corner1 - YY(actprj),
1585  (double)XX_corner1 - XX(actprj), foot_V1, foot_U1);
1586  if (isVolPSF != false)
1587  OVER2IMG_Z(basis->blobprint, z, foot_W);
1588  }
1589 
1590  if (!FORW)
1591  vol_corr = 0;
1592 
1593  // Effectively project this basis
1594  // N_eq=(YY_corner2-YY_corner1+1)*(XX_corner2-XX_corner1+1);
1595  N_eq = 0;
1596  foot_V = foot_V1;
1597  for (int y = YY_corner1; y <= YY_corner2; y++)
1598  {
1599  foot_U = foot_U1;
1600  for (int x = XX_corner1; x <= XX_corner2; x++)
1601  {
1602  if (!((mask != NULL) && A2D_ELEM(*mask,y,x)<0.5))
1603  {
1604 #ifdef DEBUG
1605  if (condition)
1606  {
1607  std::cout << "Position in projection (" << x << ","
1608  << y << ") ";
1609  double y, x;
1610  if (basis->type == Basis::blobs)
1611  {
1612  std::cout << "in footprint ("
1613  << foot_U << "," << foot_V << ")";
1614  IMG2OVER(basis->blobprint, foot_V, foot_U, y, x);
1615  std::cout << " (d= " << sqrt(y*y + x*x) << ") ";
1616  fflush(stdout);
1617  }
1618  }
1619 #endif
1620  double a;
1621  double a2;
1622  // Check if volumetric interpolation (i.e., SSNR)
1623  if (VSSNR_mode)
1624  {
1625  // This is the VSSNR case
1626  // Get the pixel position in the universal coordinate
1627  // system
1629  VECTOR_R3(prjPix, x, y, z);
1630  M3x3_BY_V3x1(prjPix, proj->eulert, prjPix);
1631  V3_MINUS_V3(prjPix, prjPix, univ_position);
1632  a = basis->valueAt(prjPix);
1633  a2 = a * a;
1634  }
1635  else
1636  {
1637  // This is normal reconstruction from projections
1638  if (basis->type == Basis::blobs)
1639  {
1640  // Projection of a blob
1641  a = VOLVOXEL(basis->blobprint, foot_W, foot_V, foot_U);
1642  a2 = VOLVOXEL(basis->blobprint2, foot_W, foot_V, foot_U);
1643 
1644  }
1645  else
1646  {
1647  // Projection of other bases
1648  // If the basis is big enough, then
1649  // it is not necessary to integrate at several
1650  // places. Big enough is being greater than
1651  // 1.41 which is the maximum separation
1652  // between two pixels
1653  if (XX_footprint_size > 1.41)
1654  {
1655  // Get the pixel in universal coordinates
1657  VECTOR_R3(prjPix, x, y, 0);
1658  // Express the point in a local coordinate system
1659  M3x3_BY_V3x1(prjPix, proj->eulert, prjPix);
1660 #ifdef DEBUG
1661 
1662  if (condition)
1663  std::cout << " in volume coord ("
1664  << prjPix.transpose() << ")";
1665 #endif
1666 
1667  V3_MINUS_V3(prjPix, prjPix, univ_position);
1668 #ifdef DEBUG
1669 
1670  if (condition)
1671  std::cout << " in voxel coord ("
1672  << prjPix.transpose() << ")";
1673 #endif
1674 
1675  a = basis->projectionAt(prjDir, prjPix);
1676  a2 = a * a;
1677  }
1678  else
1679  {
1680  // If the basis is too small (of the
1681  // range of the voxel), then it is
1682  // necessary to sample in a few places
1683  const double p0 = 1.0 / (2 * ART_PIXEL_SUBSAMPLING) - 0.5;
1684  const double pStep = 1.0 / ART_PIXEL_SUBSAMPLING;
1685  const double pAvg = 1.0 / (ART_PIXEL_SUBSAMPLING * ART_PIXEL_SUBSAMPLING);
1686  int ii;
1687  int jj;
1688  double px;
1689  double py;
1690  a = 0;
1691 #ifdef DEBUG
1692 
1693  if (condition)
1694  std::cout << std::endl;
1695 #endif
1696 
1697  for (ii = 0, px = p0; ii < ART_PIXEL_SUBSAMPLING; ii++, px += pStep)
1698  for (jj = 0, py = p0; jj < ART_PIXEL_SUBSAMPLING; jj++, py += pStep)
1699  {
1700 #ifdef DEBUG
1701  if (condition)
1702  std::cout << " subsampling (" << ii << ","
1703  << jj << ") ";
1704 #endif
1705 
1707  // Get the pixel in universal coordinates
1708  VECTOR_R3(prjPix, x + px, y + py, 0);
1709  // Express the point in a local coordinate system
1710  M3x3_BY_V3x1(prjPix, proj->eulert, prjPix);
1711 #ifdef DEBUG
1712 
1713  if (condition)
1714  std::cout << " in volume coord ("
1715  << prjPix.transpose() << ")";
1716 #endif
1717 
1718  V3_MINUS_V3(prjPix, prjPix, univ_position);
1719 #ifdef DEBUG
1720 
1721  if (condition)
1722  std::cout << " in voxel coord ("
1723  << prjPix.transpose() << ")";
1724 #endif
1725 
1726  a += basis->projectionAt(prjDir, prjPix);
1727 #ifdef DEBUG
1728 
1729  if (condition)
1730  std::cout << " partial a="
1731  << basis->projectionAt(prjDir, prjPix)
1732  << std::endl;
1733 #endif
1734 
1735  }
1736  a *= pAvg;
1737  a2 = a * a;
1738 #ifdef DEBUG
1739 
1740  if (condition)
1741  std::cout << " Finally ";
1742 #endif
1743 
1744  }
1745  }
1746  }
1747 #ifdef DEBUG
1748  if (condition)
1749  std::cout << "=" << a << " , " << a2;
1750 #endif
1751 
1752  if (FORW)
1753  {
1754  switch (eq_mode)
1755  {
1756  case CAVARTK:
1757  case ARTK:
1758  IMGPIXEL(*proj, y, x) += VOLVOXEL(*vol, k, i, j) * a;
1759  IMGPIXEL(*norm_proj, y, x) += a2;
1760  if (M != NULL)
1761  {
1762  int py;
1763  int px;
1764  (*proj)().toPhysical(y, x, py, px);
1765  int number_of_pixel = py * XSIZE((*proj)()) + px;
1766  dMij(*M, number_of_pixel, number_of_basis) = a;
1767  }
1768  break;
1769  case CAVK:
1770  IMGPIXEL(*proj, y, x) += VOLVOXEL(*vol, k, i, j) * a;
1771  IMGPIXEL(*norm_proj, y, x) += a2 * N_eq;
1772  break;
1773  case COUNT_EQ:
1774  VOLVOXEL(*vol, k, i, j)++;
1775  break;
1776  case CAV:
1777  IMGPIXEL(*proj, y, x) += VOLVOXEL(*vol, k, i, j) * a;
1778  IMGPIXEL(*norm_proj, y, x) += a2 *
1779  VOLVOXEL(*VNeq, k, i, j);
1780  break;
1781  }
1782 
1783 #ifdef DEBUG
1784  if (condition)
1785  {
1786  std::cout << " proj= " << IMGPIXEL(*proj, y, x)
1787  << " norm_proj=" << IMGPIXEL(*norm_proj, y, x) << std::endl;
1788  std::cout.flush();
1789  }
1790 #endif
1791 
1792  }
1793  else
1794  {
1795  vol_corr += IMGPIXEL(*norm_proj, y, x) * a;
1796  if (a != 0)
1797  N_eq++;
1798 #ifdef DEBUG
1799 
1800  if (condition)
1801  {
1802  std::cout << " corr_img= " << IMGPIXEL(*norm_proj, y, x)
1803  << " correction=" << vol_corr << std::endl;
1804  std::cout.flush();
1805  }
1806 #endif
1807 
1808  }
1809  }
1810  // Prepare for next operation
1811  foot_U += Usampling;
1812  }
1813  foot_V += Vsampling;
1814  } // Project this basis
1815 
1816  if (!FORW)
1817  {
1818  T correction = 0;
1819  switch (eq_mode)
1820  {
1821  case ARTK:
1822  correction = (T) vol_corr;
1823  break;
1824  case CAVARTK:
1825  if (N_eq != 0)
1826  correction = (T)(vol_corr / N_eq);
1827  break;
1828  case CAVK:
1829  case CAV:
1830  correction = (T) vol_corr;
1831  break;
1832  }
1833  VOLVOXEL(*vol, k, i, j) += correction;
1834 
1835 #ifdef DEBUG
1836 
1837  if (condition)
1838  {
1839  printf("\nFinal value at (%d,%d,%d) ", j, i, k);
1840  std::cout << " = " << VOLVOXEL(*vol, k, i, j) << std::endl;
1841  std::cout.flush();
1842  }
1843 #endif
1844 
1845  }
1846  } // If not collapsed
1847  number_of_basis++;
1848  } // If interesting
1849 
1850  // Prepare for next iteration
1851  V2_PLUS_V2(actprj, actprj, prjX);
1852  V3_PLUS_V3(univ_position, univ_position, gridX);
1853  }
1854  V2_PLUS_V2(beginY, beginY, prjY);
1855  V3_PLUS_V3(univ_beginY, univ_beginY, gridY);
1856  }
1857  V2_PLUS_V2(beginZ, beginZ, prjZ * numthreads );
1858  V3_PLUS_V3(univ_beginZ, univ_beginZ, gridZ * numthreads);
1859  }
1860 }
1861 
1862 template <class T>
1864  GridVolumeT<T> &vol, // Volume
1865  const Basis &basis, // Basis
1866  Projection &proj, // Projection
1867  Projection &norm_proj, // Projection of a unitary volume
1868  int Ydim, // Dimensions of the projection
1869  int Xdim,
1870  double rot, double tilt, double psi, // Euler angles
1871  int FORW, // 1 if we are projecting a volume
1872  // norm_proj is calculated
1873  // 0 if we are backprojecting
1874  // norm_proj must be valid
1875  int eq_mode, // ARTK, CAVARTK, CAVK or CAV
1876  GridVolumeT<int> *GVNeq, // Number of equations per blob
1877  Matrix2D<double> *M, // System matrix
1878  const MultidimArray<int> *mask, // mask(i,j)=0 => do not update this pixel
1879  double ray_length, // Ray length of the projection
1880  int threads)
1881 {
1882 
1883  // If projecting forward initialize projections
1884  if (FORW)
1885  {
1886  proj.reset(Ydim, Xdim);
1887  proj.setAngles(rot, tilt, psi);
1888  norm_proj().initZeros(proj());
1889  }
1890 
1891  if( threads > 1 )
1892  {
1893  for( int c = 0 ; c < threads ; c++ )
1894  {
1895  project_threads[c].global_proj = &proj;
1896  project_threads[c].global_norm_proj = &norm_proj;
1897  project_threads[c].FORW = FORW;
1898  project_threads[c].eq_mode = eq_mode;
1899  project_threads[c].basis = &basis;
1900  project_threads[c].M = M;
1901  project_threads[c].rot = rot;
1902  project_threads[c].tilt = tilt;
1903  project_threads[c].psi = psi;
1904  project_threads[c].ray_length = ray_length;
1905  }
1906  }
1907 
1908 
1909 #ifdef DEBUG_LITTLE
1910  if (FORW)
1911  {
1912  std::cout << "Number of volumes: " << vol.VolumesNo() << std::endl
1913  << "YdimxXdim: " << Ydim << "x" << Xdim << std::endl;
1914  for (int i = 0; i < vol.VolumesNo(); i++)
1915  std::cout << "Volume " << i << std::endl << vol.grid(i) << std::endl;
1916  }
1917 
1918 #endif
1919 
1920  // Project each subvolume
1921  for (size_t i = 0; i < vol.VolumesNo(); i++)
1922  {
1923  Image<int> *VNeq;
1924  if (GVNeq != NULL)
1925  VNeq = &((*GVNeq)(i));
1926  else
1927  VNeq = NULL;
1928 
1929  if( threads > 1 )
1930  {
1931  for( int c = 0 ; c < threads ; c++ )
1932  {
1933  project_threads[c].vol = &(vol(i));
1934  project_threads[c].grid = &(vol.grid(i));
1935  project_threads[c].VNeq = VNeq;
1936  project_threads[c].mask = mask;
1937  }
1938 
1939  barrier_wait( &project_barrier );
1940 
1941  // Here is being processed the volume by the threads
1942 
1943  barrier_wait( &project_barrier );
1944  }
1945  else
1946  {
1947  // create no thread to do the job
1948  project_SimpleGrid(&(vol(i)), &(vol.grid(i)), &basis,
1949  &proj, &norm_proj, FORW, eq_mode,
1950  VNeq, M, mask, ray_length);
1951  }
1952 
1953 #ifdef DEBUG
1954  Image<double> save;
1955  save = norm_proj;
1956  if (FORW)
1957  save.write((std::string)"PPPnorm_FORW" + (char)(48 + i));
1958  else
1959  save.write((std::string)"PPPnorm_BACK" + (char)(48 + i));
1960 #endif
1961 
1962  }
1963 }
1964 
1965 // explicit instantiation
1966 template void* project_SimpleGridThread<double>(void*);
1967 template void project_GridVolume<double>(GridVolumeT<double>&, Basis const&, Projection&, Projection&, int, int, double, double, double, int, int, GridVolumeT<int>*, Matrix2D<double>*, MultidimArray<int> const*, double, int);
Argument missing.
Definition: xmipp_error.h:114
const MultidimArray< int > * mask
Definition: projection.h:150
bool only_create_angles
Only create angles, do not project.
Definition: projection.h:81
Matrix2D< double > eulert
void defineParams(XmippProgram *program)
Definition: projection.cpp:74
template void * project_SimpleGridThread< double >(void *)
#define yc
Rotation angle of an image (double,degrees)
char * firstWord(char *str)
#define YSIZE(v)
#define A2D_ELEM(v, i, j)
double Npixel_dev
Standard deviation of the noise to be added to each pixel grey value.
Definition: projection.h:101
#define yDim
Definition: projection.cpp:42
void reset(int Ydim, int Xdim)
#define VOLVOXEL(V, k, i, j)
#define XMIPP_MAX(x, y)
Definition: xmipp_macros.h:193
Matrix1D< double > highest
Definition: grids.h:161
FileName fnOut
Output filename (used for a singleProjection)
Definition: projection.h:67
double getDoubleParam(const char *param, int arg=0)
void read(const FileName &inFile, const std::vector< MDLabel > *desiredLabels=nullptr, bool decomposeStack=true) override
#define FINISHINGX(v)
std::string fn_projection_extension
Extension for projection filenames. This is optional.
Definition: projection.h:73
constexpr int COUNT_EQ
Definition: projection.h:179
void printShape(std::ostream &out=std::cout) const
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
double psi(const size_t n=0) const
#define xDim
Definition: projection.cpp:41
void Euler_angles2matrix(T alpha, T beta, T gamma, Matrix2D< T > &A, bool homogeneous)
Definition: geometry.cpp:624
doublereal * c
void Euler_direction(double alpha, double beta, double gamma, Matrix1D< double > &v)
Definition: geometry.cpp:721
Projection * global_norm_proj
Definition: projection.h:145
< Type of randomness for Tilt (std::string)
double projectionAt(const Matrix1D< double > &u, const Matrix1D< double > &r) const
Definition: basis.cpp:367
void project_Crystal_SimpleGrid(Image< double > &vol, const SimpleGrid &grid, const Basis &basis, Projection &proj, Projection &norm_proj, const Matrix1D< double > &shift, const Matrix1D< double > &aint, const Matrix1D< double > &bint, const Matrix2D< double > &D, const Matrix2D< double > &Dinv, const MultidimArray< int > &mask, int FORW, int eq_mode)
Definition: projection.cpp:773
#define VOLMATRIX(V)
const SimpleGrid * grid
Definition: projection.h:142
double tilt0
Minimum tilt around this axis.
Definition: projection.h:92
void Euler_another_set(double rot, double tilt, double psi, double &newrot, double &newtilt, double &newpsi)
Definition: geometry.cpp:1002
void sqrt(Image< double > &op)
Tilting angle of an image (double,degrees)
Shift for the image in the X axis (double)
Matrix2D< double > euler
void write(const FileName &name="", size_t select_img=ALL_IMAGES, bool isStack=false, int mode=WRITE_OVERWRITE, CastWriteMode castMode=CW_CAST, int _swapWrite=0)
#define V3_MINUS_V3(a, b, c)
Definition: matrix1d.h:202
void * project_SimpleGridThread(void *params)
int umax() const
constexpr int ARTK
Definition: projection.h:177
void readParams(XmippProgram *program)
Definition: projection.cpp:97
Noise description for projected angles.
tBasisFunction type
Basis function to use.
Definition: basis.h:52
#define x
double rot(const size_t n=0) const
double maxLength() const
Definition: basis.cpp:242
ImageOver blobprint2
Square of the footprint.
Definition: basis.h:74
void singleWBP(MultidimArray< double > &V, Projection &P)
Definition: projection.cpp:609
#define FINISHINGZ(v)
bool is_interesting(const Matrix1D< double > &uv) const
Definition: grids.h:361
#define IMGMATRIX(I)
Matrix1D< double > lowest
Definition: grids.h:158
int Vstep() const
#define xF
Definition: projection.cpp:38
int Ustep() const
#define V2_PLUS_V2(a, b, c)
Definition: matrix1d.h:134
Matrix2D< double > basis
Definition: grids.h:148
#define STARTINGX(v)
double tiltF
Maximum tilt around this axis.
Definition: projection.h:94
#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
#define FOR_ALL_ELEMENTS_IN_ARRAY2D(m)
Matrix1D< T > transpose() const
Definition: matrix1d.cpp:644
void rotation3DMatrix(double ang, char axis, Matrix2D< double > &result, bool homogeneous)
double tilt(const size_t n=0) const
#define STARTINGY(v)
#define CLIP(x, x0, xF)
Definition: xmipp_macros.h:260
const Image< int > * VNeq
Definition: projection.h:148
Matrix1D< double > raxis
Offset of the tilt axis.
Definition: projection.h:90
#define A3D_ELEM(V, k, i, j)
void setShifts(double xoff, double yoff, double zoff=0., const size_t n=0)
double Npixel_avg
Bias to be applied to each pixel grey value */.
Definition: projection.h:99
int proj_Ydim
Projection Ydim.
Definition: projection.h:78
const int ART_PIXEL_SUBSAMPLING
Definition: projection.h:296
#define V3_BY_CT(a, b, c)
Definition: matrix1d.h:238
int vmax() const
size_t VolumesNo() const
Definition: grids.h:1003
#define FLOOR(x)
Definition: xmipp_macros.h:240
void project_SimpleGrid(Image< T > *vol, const SimpleGrid *grid, const Basis *basis, Projection *proj, Projection *norm_proj, int FORW, int eq_mode, const Image< int > *VNeq, Matrix2D< double > *M, const MultidimArray< int > *mask, double ray_length, int thread_id, int numthreads)
char axis
const char * getParam(const char *param, int arg=0)
#define XX(v)
Definition: matrix1d.h:85
MultidimArray< double > * VolPSF
Footprint is convolved with a volume PSF // At this moment only used with blobs.
Definition: basis.h:55
#define M2x2_BY_V2x1(a, M, b)
Definition: matrix2d.h:225
void transpose(double *array, int size)
double point_plane_distance_3D(const Matrix1D< double > &p, const Matrix1D< double > &a, const Matrix1D< double > &v)
Definition: geometry.h:171
double Ncenter_avg
Bias to apply to the image center.
Definition: projection.h:104
#define CEIL(x)
Definition: xmipp_macros.h:225
float textToFloat(const char *str)
void projectVolume(MultidimArray< double > &V, Projection &P, int Ydim, int Xdim, double rot, double tilt, double psi, const Matrix1D< double > *roffset)
Definition: projection.cpp:337
double Ncenter_dev
Standard deviation of the image center.
Definition: projection.h:106
void project_GridVolume(GridVolumeT< T > &vol, const Basis &basis, Projection &proj, Projection &norm_proj, int Ydim, int Xdim, double rot, double tilt, double psi, int FORW, int eq_mode, GridVolumeT< int > *GVNeq, Matrix2D< double > *M, const MultidimArray< int > *mask, double ray_length, int threads)
Definition: basis.h:45
#define dMij(m, i, j)
Definition: matrix2d.h:139
size_t firstRowId() const override
pthread_mutex_t project_mutex
Definition: projection.cpp:47
#define XMIPP_EQUAL_ACCURACY
Definition: xmipp_macros.h:119
#define IMG2OVER(IO, iv, iu, v, u)
void resize(size_t Xdim, bool copy=true)
Definition: matrix1d.h:410
< Number of non-redundant projections directions (size_t)
#define XSIZE(v)
#define SPEED_UP_temps01
Definition: xmipp_macros.h:398
#define ABS(x)
Definition: xmipp_macros.h:142
#define yF
Definition: projection.cpp:40
double z
Noise description for pixels&#39; gray level (when projecting)
double Nangle_dev
Standard deviation of the angles.
Definition: projection.h:111
#define ROUND(x)
Definition: xmipp_macros.h:210
Matrix1D< double > vectorR2(double x, double y)
Definition: matrix1d.cpp:884
#define XMIPP_EQUAL_ZERO(x)
Definition: xmipp_macros.h:123
int proj_Xdim
Projection Xdim.
Definition: projection.h:76
for(j=1;j<=i__1;++j)
void project_Crystal_Volume(GridVolume &vol, const Basis &basis, Projection &proj, Projection &norm_proj, int Ydim, int Xdim, double rot, double tilt, double psi, const Matrix1D< double > &shift, const Matrix1D< double > &aint, const Matrix1D< double > &bint, const Matrix2D< double > &D, const Matrix2D< double > &Dinv, const MultidimArray< int > &mask, int FORW, int eq_mode)
void calculateProjectionAngles(Projection &P, double angle, double inplaneRot, const Matrix1D< double > &sinplane)
Definition: projection.cpp:277
void initZeros()
Definition: matrix1d.h:592
double relative_size
Measuring unit in the grid coordinate system.
Definition: grids.h:163
double axisRot
Rotational angle of the tilt axis.
Definition: projection.h:86
Matrix1D< double > direction
#define XMIPP_MIN(x, y)
Definition: xmipp_macros.h:181
template void project_GridVolume< double >(GridVolumeT< double > &, Basis const &, Projection &, Projection &, int, int, double, double, double, int, int, GridVolumeT< int > *, Matrix2D< double > *, MultidimArray< int > const *, double, int)
FileName fnRoot
Root filename (used for a stack)
Definition: projection.h:65
double valueAt(const Matrix1D< double > &r) const
Definition: basis.cpp:332
#define M2x2_BY_CT(M2, M1, k)
Definition: matrix2d.h:237
#define j
#define FORWARD
Definition: blobs.cpp:1091
double axisTilt
Tilt angle of the tilt axis.
Definition: projection.h:88
#define M3x3_BY_V3x1(a, M, b)
Definition: matrix2d.h:170
#define YY(v)
Definition: matrix1d.h:93
void getCol(size_t j, Matrix1D< T > &v) const
Definition: matrix2d.cpp:890
#define x0
Definition: projection.cpp:37
bool getValue(MDObject &mdValueOut, size_t id) const override
constexpr int CAV
Definition: projection.h:180
File cannot be open.
Definition: xmipp_error.h:137
barrier_t project_barrier
Definition: projection.cpp:46
#define FINISHINGY(v)
constexpr int CAVARTK
Definition: projection.h:181
Image< double > * vol
Definition: projection.h:141
bool isMetaData(bool failIfNotExists=true) const
Matrix2D< double > * M
Definition: projection.h:149
bool singleProjection
Only project a single image.
Definition: projection.h:69
#define y
Matrix1D< double > origin
Origin of the grid in the Universal coordinate system.
Definition: grids.h:165
constexpr int CAVK
Definition: projection.h:178
const SimpleGrid & grid(size_t n) const
Definition: grids.h:978
double psi(const double x)
void Euler_matrix2angles(const Matrix2D< double > &A, double &alpha, double &beta, double &gamma, bool homogeneous)
Definition: geometry.cpp:839
#define VECTOR_R3(v, x, y, z)
Definition: matrix1d.h:124
project_thread_params * project_threads
Definition: projection.cpp:48
int get_number_of_samples() const
Definition: grids.cpp:69
#define OVER2IMG(IO, v, u, iv, iu)
Shift for the image in the Z axis (double)
void initZeros()
Definition: matrix2d.h:626
int textToInteger(const char *str)
#define realWRAP(x, x0, xF)
Definition: xmipp_macros.h:304
char * firstToken(const char *str)
Projection * global_proj
Definition: projection.h:144
bool checkParam(const char *param)
void read(const FileName &fn_proj_param)
Definition: projection.cpp:129
int read(const FileName &name, DataMode datamode=DATA, size_t select_img=ALL_IMAGES, bool mapData=false, int mode=WRITE_READONLY)
double tiltStep
Step in tilt.
Definition: projection.h:96
void Gdir_project_to_plane(const Matrix1D< double > &gr, double rot, double tilt, double psi, Matrix1D< double > &result) const
Definition: grids.h:432
#define wrap_as_Crystal(x, y, xw, yw)
Definition: projection.cpp:769
void projectVolumeOffCentered(MultidimArray< double > &V, Projection &P, int Ydim, int Xdim)
Definition: projection.cpp:594
Shift for the image in the Y axis (double)
void setAngles(double _rot, double _tilt, double _psi)
#define M2x2_INV(Ainv, A)
Definition: matrix2d.h:286
int barrier_wait(barrier_t *barrier)
String nextToken(const String &str, size_t &i)
Incorrect value received.
Definition: xmipp_error.h:195
void getRow(size_t i, Matrix1D< T > &v) const
Definition: matrix2d.cpp:871
void Uproject_to_plane(const Matrix1D< double > &point, const Matrix1D< double > &direction, double distance, Matrix1D< double > &result)
Definition: geometry.cpp:39
void count_eqs_in_projection(GridVolumeT< int > &GVNeq, const Basis &basis, Projection &read_proj)
double fmax
#define SGN(x)
Definition: xmipp_macros.h:155
#define STARTINGZ(v)
#define ZZ(v)
Definition: matrix1d.h:101
doublereal * a
int starting
First projection number. By default, 1.
Definition: projection.h:71
void addParamsLine(const String &line)
double Nangle_avg
Bias to apply to the angles.
Definition: projection.h:109
ql0001_ & zero(ctemp+1),(cvec+1),(a+1),(b+1),(bl+1),(bu+1),(x+1),(w+1), &iout, ifail, &zero,(w+3), &lwar2,(iw+1), &leniw, &glob_grd.epsmac
const Basis * basis
Definition: projection.h:143
#define y0
Definition: projection.cpp:39
#define V3_PLUS_V3(a, b, c)
Definition: matrix1d.h:190
#define IMGPIXEL(I, i, j)
void getShifts(double &xoff, double &yoff, double &zoff, const size_t n=0) const
#define SPEED_UP_temps012
Definition: xmipp_macros.h:403
ImageOver blobprint
Blob footprint.
Definition: basis.h:71
Noise description for particle&#39;s center coordenates (when projecting)
int wmax() const
#define OVER2IMG_Z(IO, w, iw)
#define xc