Xmipp  v3.23.11-Nereus
art_zernike3d.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: David Herreros Calero dherreros@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 "art_zernike3d.h"
27 #include <core/transformations.h>
30 #include <data/projection.h>
31 #include <data/mask.h>
32 #include <numeric>
33 
34 // Empty constructor =======================================================
36 {
37  resume = false;
38  produces_a_metadata = true;
40  showOptimization = false;
41 }
42 
43 // Read arguments ==========================================================
45 {
47  fnVolR = getParam("--ref");
48  fnOutDir = getParam("--odir");
49  RmaxDef = getIntParam("--RDef");
50  phaseFlipped = checkParam("--phaseFlipped");
51  useCTF = checkParam("--useCTF");
52  Ts = getDoubleParam("--sampling");
53  L1 = getIntParam("--l1");
54  L2 = getIntParam("--l2");
55  useZernike = checkParam("--useZernike");
56  lambda = static_cast<float>(getDoubleParam("--regularization"));
57  resume = checkParam("--resume");
58  niter = getIntParam("--niter");
59  save_iter = getIntParam("--save_iter");
60  sort_last_N = getIntParam("--sort_last");
61  fnVolO = fnOutDir + "/Refined.vol";
62  keep_input_columns = true;
63 }
64 
65 // Show ====================================================================
67 {
68  if (!verbose)
69  return;
71  std::cout
72  << "Output directory: " << fnOutDir << std::endl
73  << "Reference volume: " << fnVolR << std::endl
74  << "Sampling: " << Ts << std::endl
75  << "Max. Radius Deform. " << RmaxDef << std::endl
76  << "Zernike Degree: " << L1 << std::endl
77  << "SH Degree: " << L2 << std::endl
78  << "Correct CTF: " << useCTF << std::endl
79  << "Correct heretogeneity: " << useZernike << std::endl
80  << "Phase flipped: " << phaseFlipped << std::endl
81  << "Regularization: " << lambda << std::endl
82  << "Number of iterations: " << niter << std::endl
83  << "Save every # iterations: " << save_iter << std::endl
84  ;
85 }
86 
87 // usage ===================================================================
89 {
90  addUsageLine("Template-based canonical volume reconstruction through Zernike3D coefficients");
91  defaultComments["-i"].clear();
92  defaultComments["-i"].addComment("Metadata with initial alignment");
93  defaultComments["-o"].clear();
94  defaultComments["-o"].addComment("Refined volume");
96  addParamsLine(" [--ref <volume=\"\">] : Reference volume");
97  addParamsLine(" [--odir <outputDir=\".\">] : Output directory");
98  addParamsLine(" [--sampling <Ts=1>] : Sampling rate (A/pixel)");
99  addParamsLine(" [--RDef <r=-1>] : Maximum radius of the deformation (px). -1=Half of volume size");
100  addParamsLine(" [--l1 <l1=3>] : Degree Zernike Polynomials=1,2,3,...");
101  addParamsLine(" [--l2 <l2=2>] : Harmonical depth of the deformation=1,2,3,...");
102  addParamsLine(" [--useZernike] : Correct heterogeneity with Zernike3D coefficients");
103  addParamsLine(" [--useCTF] : Correct CTF during ART reconstruction");
104  addParamsLine(" [--phaseFlipped] : Input images have been phase flipped");
105  addParamsLine(" [--regularization <l=0.01>] : ART regularization weight");
106  addParamsLine(" [--niter <n=1>] : Number of ART iterations");
107  addParamsLine(" [--save_iter <s=0>] : Save intermidiate volume after #save_iter iterations");
108  addParamsLine(" [--sort_last <N=2>] : The algorithm sorts projections in the most orthogonally possible way. ");
109  addParamsLine(" : The most orthogonal way is defined as choosing the projection which maximizes the ");
110  addParamsLine(" : dot product with the N previous inserted projections. Use -1 to sort with all ");
111  addParamsLine(" : previous projections");
112  addParamsLine(" [--resume] : Resume processing");
113  addExampleLine("A typical use is:",false);
114  addExampleLine("xmipp_art_zernike3d -i anglesFromContinuousAssignment.xmd --ref reference.vol -o assigned_anglesAndDeformations.xmd --l1 3 --l2 2");
115 }
116 
118 {
119 
120  // Check that metadata has all information neede
121  if (!getInputMd()->containsLabel(MDL_ANGLE_ROT) ||
122  !getInputMd()->containsLabel(MDL_ANGLE_TILT) ||
123  !getInputMd()->containsLabel(MDL_ANGLE_PSI))
124  {
125  REPORT_ERROR(ERR_MD_MISSINGLABEL,"Input metadata projection angles are missing. Exiting...");
126  }
127 
128  if (fnVolR != "")
129  {
130  V.read(fnVolR);
131  }
132  else
133  {
134  FileName fn_first_image;
135  Image<float> first_image;
136  getInputMd()->getRow(1)->getValue(MDL_IMAGE,fn_first_image);
137  first_image.read(fn_first_image);
138  int Xdim_first = static_cast<int>(XSIZE(first_image()));
139  V().initZeros(Xdim_first, Xdim_first, Xdim_first);
140 
141  }
142  V().setXmippOrigin();
143 
144  Xdim = static_cast<int>(XSIZE(V()));
145 
146  if (resume && fnVolO.exists()) {
148  } else {
149  Vrefined() = V();
150  }
151  Vrefined().setXmippOrigin();
152 
153  if (RmaxDef<0)
154  RmaxDef = Xdim/2;
155 
156  // Transformation matrix
157  A.initIdentity(3);
158 
159  // CTF Filter
162  FilterCTF.ctf.enable_CTFnoise = false;
163  FilterCTF.ctf.enable_CTF = true;
164 
165  // Area where Zernike3D basis is computed (and volume is updated)
166  Mask mask;
167  mask.type = BINARY_CIRCULAR_MASK;
168  mask.mode = INNER_MASK;
169  mask.R1 = RmaxDef;
170  mask.generate_mask(V());
171  Vmask = mask.get_binary_mask();
173 
174  // Area Zernike3D in 2D
175  mask.generate_mask(Xdim, Xdim);
176  mask2D = mask.get_binary_mask();
178 
179  vecSize = 0;
182 
183  initX = STARTINGX(Vrefined());
184  endX = FINISHINGX(Vrefined());
185  initY = STARTINGY(Vrefined());
186  endY = FINISHINGY(Vrefined());
187  initZ = STARTINGZ(Vrefined());
188  endZ = FINISHINGZ(Vrefined());
189 }
190 
191 void ProgArtZernike3D::finishProcessing() {
193 }
194 
195 // Predict =================================================================
196 void ProgArtZernike3D::processImage(const FileName &fnImg, const FileName &fnImgOut, const MDRow &rowIn, MDRow &rowOut)
197 {
198  rowOut=rowIn; // FIXME have a look if this is needed. I don't think so, or see how to do this automatically in xmipp_metadata_program.cpp
199  flagEnabled=1;
200 
201  rowIn.getValue(MDL_ANGLE_ROT,rot);
203  rowIn.getValue(MDL_ANGLE_PSI,psi);
206  std::vector<double> vectortemp;
207  if (useZernike) {
208  rowIn.getValue(MDL_SPH_COEFFICIENTS,vectortemp);
209  clnm.initZeros(vectortemp.size()-8);
210  for(int i=0; i < vectortemp.size()-8; i++){
211  VEC_ELEM(clnm,i) = static_cast<float>(vectortemp[i]);
212  }
213  removeOverdeformation();
214  }
215  rowIn.getValueOrDefault(MDL_FLIP,flip, false);
216 
218  {
219  hasCTF=true;
220  FilterCTF.ctf.readFromMdRow(rowIn, false);
221  FilterCTF.ctf.Tm = Ts;
223  }
224  else
225  hasCTF=false;
226  MAT_ELEM(A,0,2)=shiftX;
227  MAT_ELEM(A,1,2)=shiftY;
228  MAT_ELEM(A,0,0)=1;
229  MAT_ELEM(A,0,1)=0;
230  MAT_ELEM(A,1,0)=0;
231  MAT_ELEM(A,1,1)=1;
232 
233  if (verbose>=2)
234  std::cout << "Processing " << fnImg << std::endl;
235 
236  I.read(fnImg);
237  I().setXmippOrigin();
238 
239  // Forward Model
240  artModel<Direction::Forward>();
241 
242  // ART update
243  artModel<Direction::Backward>();
244 
245 }
246 
248 {
249  for (int h=0; h<=l2; h++)
250  {
251  int numSPH = 2*h+1;
252  int count=l1-h+1;
253  int numEven=(count>>1)+(count&1 && !(h&1));
254  if (h%2 == 0) {
255  vecSize += numSPH*numEven;
256  }
257  else {
258  vecSize += numSPH*(l1-h+1-numEven);
259  }
260  }
261 }
262 
264 {
265  int idx = 0;
270  for (int h=0; h<=l2; h++) {
271  int totalSPH = 2*h+1;
272  int aux = totalSPH/2;
273  for (int l=h; l<=l1; l+=2) {
274  for (int m=0; m<totalSPH; m++) {
275  VEC_ELEM(vL1,idx) = l;
276  VEC_ELEM(vN,idx) = h;
277  VEC_ELEM(vL2,idx) = h;
278  VEC_ELEM(vM,idx) = m-aux;
279  idx++;
280  }
281  }
282  }
283 }
284 
285 template<bool INTERPOLATE>
286 float ProgArtZernike3D::weightsInterpolation3D(float x, float y, float z, std::array<float, 8> &w) {
287  int x0 = FLOOR(x);
288  float fx0 = x - static_cast<float>(x0);
289  int x1 = x0 + 1;
290  float fx1 = static_cast<float>(x1) - x;
291 
292  int y0 = FLOOR(y);
293  float fy0 = y - static_cast<float>(y0);
294  int y1 = y0 + 1;
295  float fy1 = static_cast<float>(y1) - y;
296 
297  int z0 = FLOOR(z);
298  float fz0 = z - static_cast<float>(z0);
299  int z1 = z0 + 1;
300  float fz1 = static_cast<float>(z1) - z;
301 
302  w[0] = fx1 * fy1 * fz1; // w000 (x0,y0,z0)
303  w[1] = fx1 * fy1 * fz0; // w001 (x0,y0,z1)
304  w[2] = fx1 * fy0 * fz1; // w010 (x0,y1,z0)
305  w[3] = fx1 * fy0 * fz0; // w011 (x0,y1,z1)
306  w[4] = fx0 * fy1 * fz1; // w100 (x1,y0,z0)
307  w[5] = fx0 * fy1 * fz0; // w101 (x1,y0,z1)
308  w[6] = fx0 * fy0 * fz1; // w110 (x1,y1,z0)
309  w[7] = fx0 * fy0 * fz0; // w111 (x1,y1,z1)
310 
311  if (INTERPOLATE) {
312  const auto &mVr = Vrefined();
313  if (x0 < initX || y0 < initY || z0 < initZ || x1 > endX ||
314  y1 > endY || z1 > endZ) {
315  return NAN;
316  } else {
317  return A3D_ELEM(mVr, z0, y0, x0) * w[0] +
318  A3D_ELEM(mVr, z1, y0, x0) * w[1] +
319  A3D_ELEM(mVr, z0, y1, x0) * w[2] +
320  A3D_ELEM(mVr, z1, y1, x0) * w[3] +
321  A3D_ELEM(mVr, z0, y0, x1) * w[4] +
322  A3D_ELEM(mVr, z1, y0, x1) * w[5] +
323  A3D_ELEM(mVr, z0, y1, x1) * w[6] +
324  A3D_ELEM(mVr, z1, y1, x1) * w[7];
325  }
326  } else {
327  return NAN;
328  }
329 }
330 
331 void ProgArtZernike3D::removeOverdeformation() {
332  size_t idxY0=(VEC_XSIZE(clnm))/3;
333  size_t idxZ0=2*idxY0;
334 
335  Matrix2D<float> R, R_inv;
336  R.initIdentity(3);
337  R_inv.initIdentity(3);
338  Euler_angles2matrix(rot, tilt, psi, R, false);
339  R_inv = R.inv();
341  c.initZeros(3);
342  for (size_t idx=0; idx<idxY0; idx++) {
343  XX(c) = VEC_ELEM(clnm,idx); YY(c) = VEC_ELEM(clnm,idx+idxY0); ZZ(c) = VEC_ELEM(clnm,idx+idxZ0);
344  c = R * c;
345  ZZ(c) = 0.0f;
346  c = R_inv * c;
347  VEC_ELEM(clnm,idx) = XX(c); VEC_ELEM(clnm,idx+idxY0) = YY(c); VEC_ELEM(clnm,idx+idxZ0) = ZZ(c);
348  }
349 }
350 
351 void ProgArtZernike3D::run()
352 {
353  FileName fnImg, fnImgOut, fullBaseName;
354  getOutputMd().clear(); //this allows multiple runs of the same Program object
355 
356  //Perform particular preprocessing
357  preProcess();
358 
359  startProcessing();
360 
361  sortOrthogonal();
362 
363  if (!oroot.empty())
364  {
365  if (oext.empty())
367  oextBaseName = oext;
368  fullBaseName = oroot.removeFileFormat();
369  baseName = fullBaseName.getBaseName();
370  pathBaseName = fullBaseName.getDir();
371  }
372 
373  size_t objId;
374  size_t objIndex;
375  current_save_iter = 1;
376  num_images = 1;
378  std::cout << "Running iteration " << current_iter+1 << " with lambda=" << lambda << std::endl;
379  objId = 0;
380  objIndex = 0;
381  time_bar_done = 0;
383  {
384  objId = A1D_ELEM(ordered_list,i) + 1;
385  ++objIndex;
386  auto rowIn = getInputMd()->getRow(objId);
387  rowIn->getValue(image_label, fnImg);
388 
389  if (fnImg.empty())
390  break;
391 
392  fnImgOut = fnImg;
393 
394  MDRowVec rowOut;
395 
397  {
398  if (!oroot.empty()) // Compose out name to save as independent images
399  {
400  if (oext.empty()) // If oext is still empty, then use ext of indep input images
401  {
402  if (input_is_stack)
403  oextBaseName = "spi";
404  else
405  oextBaseName = fnImg.getFileFormat();
406  }
407 
408  if (!baseName.empty() )
409  fnImgOut.compose(fullBaseName, objIndex, oextBaseName);
410  else if (fnImg.isInStack())
411  fnImgOut.compose(pathBaseName + (fnImg.withoutExtension()).getDecomposedFileName(), objIndex, oextBaseName);
412  else
413  fnImgOut = pathBaseName + fnImg.withoutExtension()+ "." + oextBaseName;
414  }
415  else if (!fn_out.empty() )
416  {
417  if (single_image)
418  fnImgOut = fn_out;
419  else
420  fnImgOut.compose(objIndex, fn_out); // Compose out name to save as stacks
421  }
422  else
423  fnImgOut = fnImg;
424  setupRowOut(fnImg, *rowIn.get(), fnImgOut, rowOut);
425  }
426  else if (produces_a_metadata)
427  setupRowOut(fnImg, *rowIn.get(), fnImgOut, rowOut);
428 
429  processImage(fnImg, fnImgOut, *rowIn.get(), rowOut);
430 
432  getOutputMd().addRow(rowOut);
433 
434  checkPoint();
435  showProgress();
436 
437  // Save refined volume every num_images
438  if (current_save_iter == save_iter && save_iter > 0) {
439  Mask mask;
440  mask.type = BINARY_CIRCULAR_MASK;
441  mask.mode = INNER_MASK;
442  mask.R1 = RmaxDef - 2;
443  mask.generate_mask(Vrefined());
444  mask.apply_mask(Vrefined(), Vrefined());
446  current_save_iter = 1;
447  }
449  num_images++;
450  }
451  num_images = 1;
452  current_save_iter = 1;
453 
454  Mask mask;
455  mask.type = BINARY_CIRCULAR_MASK;
456  mask.mode = INNER_MASK;
457  mask.R1 = RmaxDef - 2;
458  mask.generate_mask(Vrefined());
459  mask.apply_mask(Vrefined(), Vrefined());
460  }
461  wait();
462 
463  /* Generate name to save mdOut when output are independent images. It uses as prefix
464  * the dirBaseName in order not overwriting files when repeating same command on
465  * different directories. If baseName is set it is used, otherwise, input name is used.
466  * Then, the suffix _oext is added.*/
467  if (fn_out.empty() )
468  {
469  if (!oroot.empty())
470  {
471  if (!baseName.empty() )
472  fn_out = findAndReplace(pathBaseName,"/","_") + baseName + "_" + oextBaseName + ".xmd";
473  else
474  fn_out = findAndReplace(pathBaseName,"/","_") + fn_in.getBaseName() + "_" + oextBaseName + ".xmd";
475  }
476  else if (input_is_metadata)
477  fn_out = fn_in;
478  }
479 
480  finishProcessing();
481 
482  postProcess();
483 
484  /* Reset the default values of the program in case
485  * to be reused.*/
486  init();
487 }
488 
489 void ProgArtZernike3D::sortOrthogonal() {
490  int i, j;
491  int numIMG = static_cast<int>(getInputMd()->size());
492  MultidimArray<short> chosen(numIMG);
493  chosen.initZeros(numIMG);
494  MultidimArray<double> product(numIMG);
495  product.initZeros(numIMG);
496  double min_prod = MAXFLOAT;;
497  int min_prod_proj = 0;
498  std::vector<double> rot_v;
499  std::vector<double> tilt_v;
500  Matrix2D<double> v(numIMG, 3);
501  v.initZeros(numIMG, 3);
502  Matrix2D<double> euler;
505 
506  // Initialization
507  ordered_list.resize(numIMG);
508  for (i = 0; i < numIMG; i++)
509  {
511  // Initially no image is chosen
512  A1D_ELEM(chosen, i) = 0;
513 
514  // Compute the Euler matrix for each image and keep only
515  // the third row of each one
516  Euler_angles2matrix(rot_v[i], tilt_v[i], 0., euler);
517  euler.getRow(2, z);
518  v.setRow(i, z);
519  }
520 
521  // Pick first projection as the first one to be presented
522  i = 0;
523  A1D_ELEM(chosen, i) = 1;
524  A1D_ELEM(ordered_list, 0) = i;
525 
526  // Choose the rest of projections
527  std::cout << "Sorting projections orthogonally...\n" << std::endl;
528  Matrix1D<double> rowj, rowi_1, rowi_N_1;
529  for (i = 1; i < numIMG; i++)
530  {
531  // Compute the product of not already chosen vectors with the just
532  // chosen one, and select that which has minimum product
533  min_prod = MAXFLOAT;
534  v.getRow(A1D_ELEM(ordered_list, i - 1),rowi_1);
535  if (sort_last_N != -1 && i > sort_last_N)
536  v.getRow(A1D_ELEM(ordered_list, i - sort_last_N - 1),rowi_N_1);
537  for (j = 0; j < numIMG; j++)
538  {
539  if (!A1D_ELEM(chosen, j))
540  {
541  v.getRow(j,rowj);
542  A1D_ELEM(product, j) += ABS(dotProduct(rowi_1,rowj));
543  if (sort_last_N != -1 && i > sort_last_N)
544  A1D_ELEM(product, j) -= ABS(dotProduct(rowi_N_1,rowj));
545  if (A1D_ELEM(product, j) < min_prod)
546  {
547  min_prod = A1D_ELEM(product, j);
548  min_prod_proj = j;
549  }
550  }
551  }
552 
553  // Store the chosen vector and mark it as chosen
554  A1D_ELEM(ordered_list, i) = min_prod_proj;
555  A1D_ELEM(chosen, min_prod_proj) = 1;
556 
557  }
558 }
559 
560 template <ProgArtZernike3D::Direction DIRECTION>
561 void ProgArtZernike3D::artModel()
562 {
563  if (DIRECTION == Direction::Forward)
564  {
565  Image<float> I_shifted;
566  P().initZeros((int)XSIZE(I()), (int)XSIZE(I()));
567  P().setXmippOrigin();
568  W().initZeros((int)XSIZE(I()), (int)XSIZE(I()));
569  W().setXmippOrigin();
570  Idiff().initZeros((int)XSIZE(I()), (int)XSIZE(I()));
571  Idiff().setXmippOrigin();
572  I_shifted().initZeros((int)XSIZE(I()), (int)XSIZE(I()));
573  I_shifted().setXmippOrigin();
574 
575  if (useZernike)
576  zernikeModel<true, Direction::Forward>();
577  else
578  zernikeModel<false, Direction::Forward>();
579 
580  if (hasCTF)
581  {
582  if (phaseFlipped)
586  }
587  if (flip)
588  {
589  MAT_ELEM(A, 0, 0) *= -1;
590  MAT_ELEM(A, 0, 1) *= -1;
591  MAT_ELEM(A, 0, 2) *= -1;
592  }
593 
594  applyGeometry(xmipp_transformation::LINEAR, I_shifted(), I(), A,
595  xmipp_transformation::IS_NOT_INV, xmipp_transformation::DONT_WRAP, 0.f);
596 
597  // Compute difference image and divide by weights
598  float error = 0.0f;
599  float N = 0.0f;
600  const auto &mP = P();
601  const auto &mW = W();
602  const auto &mIsh = I_shifted();
603  auto &mId = Idiff();
605  {
606  if (A2D_ELEM(mask2D, i, j) == 1)
607  {
608  auto diffVal = A2D_ELEM(mIsh, i, j) - A2D_ELEM(mP, i, j);
609  A2D_ELEM(mId, i, j) = lambda * diffVal / XMIPP_MAX(A2D_ELEM(mW, i, j), 1.0f);
610  error += diffVal * diffVal;
611  N++;
612  }
613  }
614  // Creo que Carlos no usa un RMSE si no un MSE
615  error = std::sqrt(error / N);
616  std::cout << "Error for image " << num_images << " in iteration " << current_iter+1 << " : " << error << std::endl;
617  }
618  else if (DIRECTION == Direction::Backward)
619  {
620  if (useZernike)
621  zernikeModel<true, Direction::Backward>();
622  else
623  zernikeModel<false, Direction::Backward>();
624  }
625 }
626 
627 template<bool USESZERNIKE, ProgArtZernike3D::Direction DIRECTION>
628 void ProgArtZernike3D::zernikeModel() {
629  const auto &mV = V();
630  const size_t idxY0 = USESZERNIKE ? (VEC_XSIZE(clnm) / 3) : 0;
631  const size_t idxZ0 = USESZERNIKE ? (2 * idxY0) : 0;
632  const float RmaxF = USESZERNIKE ? static_cast<float>(RmaxDef) : 0.f;
633  const float RmaxF2 = USESZERNIKE ? (RmaxF * RmaxF) : 0.f;
634  const float iRmaxF = USESZERNIKE ? (1.0f / RmaxF) : 0.f;
635  // Rotation Matrix
636  constexpr size_t matrixSize = 3;
637  const Matrix2D<float> R = [this](){
638  auto tmp = Matrix2D<float>();
639  tmp.initIdentity(matrixSize);
640  Euler_angles2matrix(rot, tilt, psi, tmp, false);
641  return tmp.inv();
642  }();
643 
644  const auto lastZ = FINISHINGZ(mV);
645  const auto lastY = FINISHINGY(mV);
646  const auto lastX = FINISHINGX(mV);
647  for (int k=STARTINGZ(mV); k<=lastZ; ++k)
648  {
649  for (int i=STARTINGY(mV); i<=lastY; ++i)
650  {
651  for (int j=STARTINGX(mV); j<=lastX; ++j)
652  {
653  if (A3D_ELEM(Vmask,k,i,j) != 1) { continue; }
654  auto pos = std::array<float, 3>{};
655  pos[0] = R.mdata[0] * static_cast<float>(j) + R.mdata[1] * static_cast<float>(i) + R.mdata[2] * static_cast<float>(k);
656  pos[1] = R.mdata[3] * static_cast<float>(j) + R.mdata[4] * static_cast<float>(i) + R.mdata[5] * static_cast<float>(k);
657  pos[2] = R.mdata[6] * static_cast<float>(j) + R.mdata[7] * static_cast<float>(i) + R.mdata[8] * static_cast<float>(k);
658 
659  float gx=0.0f, gy=0.0f, gz=0.0f;
660  if (USESZERNIKE)
661  {
662  auto k2 = pos[2] * pos[2];
663  auto kr = pos[2] * iRmaxF;
664  auto k2i2 = k2 + pos[1] * pos[1];
665  auto ir = pos[1] * iRmaxF;
666  auto r2 = k2i2 + pos[0] * pos[0];
667  auto jr = pos[0] * iRmaxF;
668  auto rr = sqrt(r2) * iRmaxF;
669  for (size_t idx = 0; idx < idxY0; idx++)
670  {
671  auto l1 = VEC_ELEM(vL1, idx);
672  auto n = VEC_ELEM(vN, idx);
673  auto l2 = VEC_ELEM(vL2, idx);
674  auto m = VEC_ELEM(vM, idx);
675  if (rr > 0 || l2 == 0)
676  {
677  float zsph = static_cast<float>(ZernikeSphericalHarmonics(l1, n, l2, m, jr, ir, kr, rr));
678  gx += VEC_ELEM(clnm, idx) * zsph;
679  gy += VEC_ELEM(clnm, idx + idxY0) * zsph;
680  gz += VEC_ELEM(clnm, idx + idxZ0) * zsph;
681  }
682  }
683  }
684  // }
685  auto r_x = pos[0] + gx;
686  auto r_y = pos[1] + gy;
687  auto r_z = pos[2] + gz;
688 
689  auto w = std::array<float, 8>{};
690  if (DIRECTION == Direction::Forward)
691  {
692  auto voxel = weightsInterpolation3D<true>(r_x, r_y, r_z, w);
693  if (!isnan(voxel))
694  {
695  A2D_ELEM(P(), i, j) += voxel;
696  A2D_ELEM(W(), i, j) += std::inner_product(w.begin(), w.end(), w.begin(), static_cast<float>(0));
697  }
698  }
699  else if (DIRECTION == Direction::Backward)
700  {
701  int x0 = FLOOR(r_x);
702  auto x1 = x0 + 1;
703  int y0 = FLOOR(r_y);
704  auto y1 = y0 + 1;
705  int z0 = FLOOR(r_z);
706  auto z1 = z0 + 1;
707  float Idiff_val = A2D_ELEM(Idiff(), i, j);
708  weightsInterpolation3D<false>(r_x, r_y, r_z, w);
709  if (!Vrefined().outside(z0, y0, x0))
710  A3D_ELEM(Vrefined(), z0, y0, x0) += Idiff_val * w[0];
711  if (!Vrefined().outside(z1, y0, x0))
712  A3D_ELEM(Vrefined(), z1, y0, x0) += Idiff_val * w[1];
713  if (!Vrefined().outside(z0, y1, x0))
714  A3D_ELEM(Vrefined(), z0, y1, x0) += Idiff_val * w[2];
715  if (!Vrefined().outside(z1, y1, x0))
716  A3D_ELEM(Vrefined(), z1, y1, x0) += Idiff_val * w[3];
717  if (!Vrefined().outside(z0, y0, x1))
718  A3D_ELEM(Vrefined(), z0, y0, x1) += Idiff_val * w[4];
719  if (!Vrefined().outside(z1, y0, x1))
720  A3D_ELEM(Vrefined(), z1, y0, x1) += Idiff_val * w[5];
721  if (!Vrefined().outside(z0, y1, x1))
722  A3D_ELEM(Vrefined(), z0, y1, x1) += Idiff_val * w[6];
723  if (!Vrefined().outside(z1, y1, x1))
724  A3D_ELEM(Vrefined(), z1, y1, x1) += Idiff_val * w[7];
725  }
726  }
727  }
728  }
729 }
Rotation angle of an image (double,degrees)
#define A2D_ELEM(v, i, j)
#define VEC_ELEM(v, i)
Definition: matrix1d.h:245
Defocus U (Angstroms)
void resize(size_t Ndim, size_t Zdim, size_t Ydim, size_t Xdim, bool copy=true)
#define XMIPP_MAX(x, y)
Definition: xmipp_macros.h:193
void show()
Show.
double getDoubleParam(const char *param, int arg=0)
Image< float > P
Definition: art_zernike3d.h:89
CTFDescription ctf
#define FINISHINGX(v)
#define CTFINV
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
FileName removeFileFormat() const
void defineParams()
Define parameters.
MultidimArray< int > mask2D
Definition: art_zernike3d.h:79
#define VEC_XSIZE(m)
Definition: matrix1d.h:77
void Euler_angles2matrix(T alpha, T beta, T gamma, Matrix2D< T > &A, bool homogeneous)
Definition: geometry.cpp:624
doublereal * c
void readParams()
Read argument from command line.
Definition: mask.h:360
void sqrt(Image< double > &op)
Tilting angle of an image (double,degrees)
static double * y
Matrix1D< int > vN
Definition: art_zernike3d.h:51
Shift for the image in the X axis (double)
void applyGeometry(int SplineDegree, MultidimArray< std::complex< double > > &V2, const MultidimArray< std::complex< double > > &V1, const Matrix2D< double > &A, bool inv, bool wrap, std::complex< double > outside, MultidimArray< double > *BcoeffsPtr)
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 A1D_ELEM(v, i)
void compose(const String &str, const size_t no, const String &ext="")
void inv(Matrix2D< T > &result) const
Definition: matrix2d.cpp:663
Special label to be used when gathering MDs in MpiMetadataPrograms.
doublereal * w
T * mdata
Definition: matrix2d.h:395
Name for the CTF Model (std::string)
bool single_image
Input is a single image.
FileName removeAllExtensions() const
#define z0
Image< double > I
Definition: art_zernike3d.h:85
#define FINISHINGZ(v)
bool input_is_stack
Input is a stack.
#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
FileName fnOutDir
Output directory.
Definition: art_zernike3d.h:47
size_t addRow(const MDRow &row) override
MultidimArray< size_t > ordered_list
#define FOR_ALL_ELEMENTS_IN_ARRAY2D(m)
Image< float > Idiff
Definition: art_zernike3d.h:93
bool enable_CTF
Enable CTF part.
Definition: ctf.h:275
#define STARTINGY(v)
#define MAT_ELEM(m, i, j)
Definition: matrix2d.h:116
#define A3D_ELEM(V, k, i, j)
void clear() override
Matrix1D< int > vL2
Definition: art_zernike3d.h:51
void apply_mask(const MultidimArray< T > &I, MultidimArray< T > &result, T subs_val=0, bool apply_geo=false)
Definition: mask.h:635
FourierFilter FilterCTF
T & getValue(MDLabel label)
#define FLOOR(x)
Definition: xmipp_macros.h:240
FileName fn_in
Filenames of input and output Metadata.
#define y0
const char * getParam(const char *param, int arg=0)
#define x0
#define XX(v)
Definition: matrix1d.h:85
Matrix1D< int > vM
Definition: art_zernike3d.h:51
MultidimArray< int > Vmask
Definition: art_zernike3d.h:87
virtual void wait()
Wait for the distributor to finish.
double * f
ProgArtZernike3D()
Empty constructor.
double R1
Definition: mask.h:413
void processImage(const FileName &fnImg, const FileName &fnImgOut, const MDRow &rowIn, MDRow &rowOut)
Flip the image? (bool)
String findAndReplace(const String &tInput, const String &tFind, const String &tReplace)
void setupRowOut(const FileName &fnImgIn, const MDRow &rowIn, const FileName &fnImgOut, MDRow &rowOut) const
Prepare rowout.
Matrix1D< float > clnm
#define XSIZE(v)
double Tm
Sampling rate (A/pixel)
Definition: ctf.h:240
Missing expected label.
Definition: xmipp_error.h:158
int type
Definition: mask.h:402
#define ABS(x)
Definition: xmipp_macros.h:142
double z
void addExampleLine(const char *example, bool verbatim=true)
Image< float > W
Definition: art_zernike3d.h:91
virtual std::unique_ptr< MDRow > getRow(size_t id)=0
Image< float > V
Definition: art_zernike3d.h:83
Image< float > Vrefined
Definition: art_zernike3d.h:83
void readFromMdRow(const MDRow &row, bool disable_if_not_K=true)
Definition: ctf.cpp:1172
int verbose
Verbosity level.
virtual size_t size() const =0
MDLabel image_label
MDLabel to be used to read/write images, usually will be MDL_IMAGE.
Matrix2D< float > A
Definition: art_zernike3d.h:95
bool exists() const
void initZeros()
Definition: matrix1d.h:592
std::vector< T > getColumnValues(const MDLabel label) const
#define MAXFLOAT
Definition: data_types.h:47
#define j
#define YY(v)
Definition: matrix1d.h:93
int m
const T & getValueOrDefault(MDLabel label, const T &def) const
virtual void checkPoint()
For very long programs, it may be needed to write checkpoints.
#define FINISHINGY(v)
void show() const override
#define FOR_ALL_ELEMENTS_IN_ARRAY1D(v)
void generate_mask(bool apply_geo=false)
Definition: mask.cpp:1577
void setRow(size_t i, const Matrix1D< T > &v)
Definition: matrix2d.cpp:910
virtual bool containsLabel(MDLabel label) const =0
FileName withoutExtension() const
T dotProduct(const Matrix1D< T > &v1, const Matrix1D< T > &v2)
Definition: matrix1d.h:1140
#define BINARY_CIRCULAR_MASK
Definition: mask.h:365
double ZernikeSphericalHarmonics(int n, int m, double xr, double yr, double zr, double r)
void produceSideInfo()
Produce Side information.
Definition: ctf.cpp:1392
Deformation coefficients.
void initZeros()
Definition: matrix2d.h:626
String getFileFormat() const
FileName getDir() const
bool keep_input_columns
Keep input metadata columns.
bool checkParam(const char *param)
int read(const FileName &name, DataMode datamode=DATA, size_t select_img=ALL_IMAGES, bool mapData=false, int mode=WRITE_READONLY)
float r2
Matrix1D< int > vL1
Definition: art_zernike3d.h:51
bool each_image_produces_an_output
Indicate that an output is produced for each image in the input.
void numCoefficients(int l1, int l2)
Length of coefficients vector.
std::string to_string(bond_type bondType)
Definition: compound.cpp:43
Shift for the image in the Y axis (double)
void addUsageLine(const char *line, bool verbatim=false)
void initZeros(const MultidimArray< T1 > &op)
bool enable_CTFnoise
Enable CTFnoise part.
Definition: ctf.h:273
const MultidimArray< int > & get_binary_mask() const
Definition: mask.h:707
int getIntParam(const char *param, int arg=0)
void generateMask(MultidimArray< double > &v)
void getRow(size_t i, Matrix1D< T > &v) const
Definition: matrix2d.cpp:871
bool input_is_metadata
Input is a metadata.
#define STARTINGZ(v)
FileName getBaseName() const
int * n
Name of an image (std::string)
#define ZZ(v)
Definition: matrix1d.h:101
bool produces_a_metadata
Indicate that the unique final output file is a Metadata.
void fillVectorTerms(int l1, int l2)
Zernike and SPH coefficients allocation.
void addParamsLine(const String &line)
int ir
void initIdentity()
Definition: matrix2d.h:673
int mode
Definition: mask.h:407
void applyMaskSpace(MultidimArray< double > &v)
bool isInStack() const
FileName oext
Output extension and root.
std::map< String, CommentList > defaultComments
Definition: xmipp_program.h:83
constexpr int INNER_MASK
Definition: mask.h:47