Xmipp  v3.23.11-Nereus
forward_zernike_volume.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Carlos Oscar coss@cnb.csic.es
4  * David Herreros Calero dherreros@cnb.csic.es
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19  * 02111-1307 USA
20  *
21  * All comments concerning this program package may be sent to the
22  * e-mail address 'xmipp@cnb.uam.es'
23  ***************************************************************************/
24 
25 /***************************************************************************
26 
27 MatLab code to compute symbolic expression (in C format) for any degree/order
28 of the bases (normalized Zernikes + Spherical Harmonics)
29 
30 clear, clc;
31 
32 N=15; L=15;
33 
34 % R_vec = ZernPoly(L,N,1);
35 % vpa(poly2sym(flip(R_vec)), 4)
36 
37 if rem(L, 2) == 0
38  start = 0;
39 else
40  start = 1;
41 end
42 
43 syms r
44 for l=start:2:N
45  R_vec = ZernPoly(l,N,1);
46  R = ccode(vpa(poly2sym(flip(R_vec), r), 4))
47 end
48 
49 for m = -L:1:L
50  S = ccode(realSphericalHarmonic(L,m))
51 end
52 
53 
54 
55 
56 function plm = assocLegendre(l,m)
57  % get symbolic associated legendre function P_lm(x) based on
58  % legendre function P_l(x)
59 
60  syms costh; %% x represents the cos(theta)
61  % get symbolic form of Legendre function P_l(x)
62  leg = legendreP(l,costh);
63  % differentiate it m times
64  legDiff = diff(leg,costh,m);
65  % calculate associated legendre function P_lm(x)
66  plm = ((-1)^m)*((1 - costh^2)^(m/2))*legDiff;
67 end
68 
69 function ylm = sphericalHarmonic(l,m)
70  % get symbolic spherical harmonic Y_lm(x) based on
71  % associated legendre function P_lm(x)
72 
73  a1 = (2*l+1)/(4*pi);
74  a2 = factorial(l-abs(m))/factorial(l+abs(m));
75  n = sqrt(a1*a2); %Normalization Lengendre Polynomials
76  ylm = vpa(n * assocLegendre(l,m), 4);
77 end
78 
79 function rylm = realSphericalHarmonic(l,m)
80  % get symbolic real spherical harmonic Yr_lm(x) based on
81  % associated legendre function P_lm(x)
82 
83  syms sinth %% y represents the sin(|m|*phi)
84  syms cosph %% z represents the cos(m*phi)
85 
86  if m < 0
87  a1 = (2*l+1)/(4*pi);
88  a2 = factorial(l-abs(m))/factorial(l+abs(m));
89  n = sqrt(a1*a2); %Normalization Lengendre Polynomials
90  rylm = ((-1)^m)* sqrt(2) * n * assocLegendre(l,abs(m)) * sinth;
91  elseif m == 0
92  a1 = (2*l+1)/(4*pi);
93  n = sqrt(a1);
94  rylm = n * assocLegendre(l,m);
95  else
96  a1 = (2*l+1)/(4*pi);
97  a2 = factorial(l-abs(m))/factorial(l+abs(m));
98  n = sqrt(a1*a2); %Normalization Lengendre Polynomials
99  rylm = ((-1)^m)* sqrt(2) * n * assocLegendre(l,m) * cosph;
100  end
101 
102  rylm = vpa(rylm, 4);
103 
104 end
105 
106  ***************************************************************************/
107 
108 #include <fstream>
109 #include <iterator>
110 #include <numeric>
111 #include "forward_zernike_volume.h"
112 #include "data/fourier_filter.h"
113 #include "data/normalize.h"
114 #include "data/mask.h"
115 
116 // Params definition =======================================================
117 // -i ---> V2 (paper) / -r --> V1 (paper)
119  addUsageLine("Compute the deformation that properly fits two volumes using spherical harmonics");
120  addParamsLine(" -i <volume> : Volume to deform");
121  addParamsLine(" -r <volume> : Reference volume");
122  addParamsLine(" [-o <volume=\"\">] : Output volume which is the deformed input volume");
123  addParamsLine(" [--maski <m=\"\">] : Input volume mask");
124  addParamsLine(" [--maskr <m=\"\">] : Reference volume mask");
125  addParamsLine(" [--oroot <rootname=\"Volumes\">] : Root name for output files");
126  addParamsLine(" : By default, the input file is rewritten");
127  addParamsLine(" [--analyzeStrain] : Save the deformation of each voxel for local strain and rotation analysis");
128  addParamsLine(" [--optimizeRadius] : Optimize the radius of each spherical harmonic");
129  addParamsLine(" [--l1 <l1=3>] : Degree Zernike Polynomials=1,2,3,...");
130  addParamsLine(" [--l2 <l2=2>] : Harmonical depth of the deformation=1,2,3,...");
131  addParamsLine(" [--regularization <l=0.00025>] : Regularization weight");
132  addParamsLine(" [--Rmax <r=-1>] : Maximum radius for the transformation");
133  addParamsLine(" [--blobr <b=4>] : Blob radius for forward mapping splatting");
134  addParamsLine(" [--step <step=1>] : Voxel index step");
135  addParamsLine(" [--clnm <metadata_file=\"\">] : List of deformation coefficients");
136  addExampleLine("xmipp_forward_zernike_volume -i vol1.vol -r vol2.vol -o vol1DeformedTo2.vol");
137 }
138 
139 // Read arguments ==========================================================
141  std::string aux;
142  fnVolI = getParam("-i");
143  fnVolR = getParam("-r");
144  fnMaskR = getParam("--maskr");
145  fnMaskI = getParam("--maski");
146  L1 = getIntParam("--l1");
147  L2 = getIntParam("--l2");
148  fnRoot = getParam("--oroot");
149 
150  VI.read(fnVolI);
151  VR.read(fnVolR);
152  VI().setXmippOrigin();
153  VR().setXmippOrigin();
154 
155  VR2().initZeros(VR());
156  VR2().setXmippOrigin();
157 
158  fnVolOut = getParam("-o");
159  if (fnVolOut=="")
161  analyzeStrain=checkParam("--analyzeStrain");
162  optimizeRadius=checkParam("--optimizeRadius");
163  lambda = getDoubleParam("--regularization");
164  Rmax = getDoubleParam("--Rmax");
165  if (Rmax<0)
166  Rmax=XSIZE(VI())/2;
167  applyTransformation = false;
168 
169  // Read Reference mask if avalaible (otherwise sphere of radius RmaxDef is used)
170  Mask mask;
171  mask.type = BINARY_CIRCULAR_MASK;
172  mask.mode = INNER_MASK;
173  if (fnMaskI != "") {
174  Image<double> auxi, auxr;
175  auxi.read(fnMaskI);
176  typeCast(auxi(), V_maski);
178  double Rmax2 = Rmax*Rmax;
179  for (int k=STARTINGZ(V_maski); k<=FINISHINGZ(V_maski); k++) {
180  for (int i=STARTINGY(V_maski); i<=FINISHINGY(V_maski); i++) {
181  for (int j=STARTINGX(V_maski); j<=FINISHINGX(V_maski); j++) {
182  double r2 = k*k + i*i + j*j;
183  if (r2>=Rmax2)
184  {
185  A3D_ELEM(V_maski,k,i,j) = 0;
186  }
187  }
188  }
189  }
190  }
191  else {
192  mask.R1 = Rmax;
193  mask.generate_mask(VR());
194  V_maski = mask.get_binary_mask();
196  }
197 
198  if (fnMaskR != "") {
199  Image<double> auxr;
200  auxr.read(fnMaskR);
201  typeCast(auxr(), V_maskr);
203  double Rmax2 = Rmax*Rmax;
204  for (int k=STARTINGZ(V_maskr); k<=FINISHINGZ(V_maskr); k++) {
205  for (int i=STARTINGY(V_maskr); i<=FINISHINGY(V_maskr); i++) {
206  for (int j=STARTINGX(V_maskr); j<=FINISHINGX(V_maskr); j++) {
207  double r2 = k*k + i*i + j*j;
208  if (r2>=Rmax2)
209  {
210  A3D_ELEM(V_maskr,k,i,j) = 0;
211  }
212  }
213  }
214  }
215  }
216  else {
217  mask.R1 = Rmax;
218  mask.generate_mask(VR());
219  V_maskr = mask.get_binary_mask();
221  }
222 
223  Mask mask2;
224  mask2.type = BINARY_CIRCULAR_MASK;
225  mask2.mode = INNER_MASK;
226  mask2.R1 = Rmax;
227  mask2.generate_mask(VR());
228  V_mask2 = mask2.get_binary_mask();
230  // Image<double> aux3;
231  // aux3.read("mask_closed.mrc");
232  // typeCast(aux3(), V_mask2);
233  // V_mask2.setXmippOrigin();
234 
235  // For debugging purposes
236  // Image<int> save;
237  // save() = V_mask;
238  // save.write("Mask.vol");
239 
240  loop_step = getIntParam("--step");
241 
242  // Blob
243  blob_r = getDoubleParam("--blobr");
244  blob.radius = blob_r; // Blob radius in voxels
245  blob.order = 2; // Order of the Bessel function
246  blob.alpha = 3.6; // Smoothness parameter
247 
248  fn_sph = getParam("--clnm");
249  if (fn_sph != "") {
250  std::string line;
251  line = readNthLine(0);
252  std::vector<double> basisParams = string2vector(line);
253  L1 = basisParams[0];
254  L2 = basisParams[1];
255  Rmax = basisParams[2];
256  line = readNthLine(1);
257  vec = string2vector(line);
258  }
259 
260  sigma4 = 2 * blob_r;
267 }
268 
269 // Show ====================================================================
271  if (verbose==0)
272  return;
273  std::cout
274  << "Volume to deform: " << fnVolI << std::endl
275  << "Reference volume: " << fnVolR << std::endl
276  << "Output volume: " << fnVolOut << std::endl
277  << "Reference mask: " << fnMaskR << std::endl
278  << "Zernike Degree: " << L1 << std::endl
279  << "SH Degree: " << L2 << std::endl
280  << "Save deformation: " << analyzeStrain << std::endl
281  << "Regularization: " << lambda << std::endl
282  << "Step: " << loop_step << std::endl
283  << "Blob radius: " << blob_r << std::endl
284  ;
285 
286 }
287 
288 template<bool SAVE_DEFORMATION>
290  size_t idxY0=VEC_XSIZE(clnm)/3;
291  size_t idxZ0=2*idxY0;
292  const auto &mVI = VI();
293  auto &mVO = VO();
294  auto &mVO2 = VO2();
295  mVO.initZeros(mVI);
296  mVO2.initZeros(mVI);
297  size_t vec_idx = 0;
298  const double iRmax = 1.0 / Rmax;
299  auto stepsMask = std::vector<size_t>();
300  if (fn_sph == "") {
301  for (size_t idx = 0; idx < idxY0; idx++)
302  {
303  if (1 == VEC_ELEM(steps_cp, idx))
304  {
305  stepsMask.emplace_back(idx);
306  }
307  }
308  }
309  else {
310  for (size_t idx = 0; idx < idxY0; idx++)
311  {
312  stepsMask.emplace_back(idx);
313  }
314  }
315  sumVD = 0.0;
316  deformation = 0.0;
317  double Ncount = 0.0;
318 
319  // int startz = STARTINGZ(mVI) + rand() % loop_step + 1;
320  // int starty = STARTINGY(mVI) + rand() % loop_step + 1;
321  // int startx = STARTINGX(mVI) + rand() % loop_step + 1;
322 
323  int startz = STARTINGZ(mVI);
324  int starty = STARTINGY(mVI);
325  int startx = STARTINGX(mVI);
326 
327  for (int k=startz; k<=FINISHINGZ(mVI); k+=loop_step) {
328  for (int i=starty; i<=FINISHINGY(mVI); i+=loop_step) {
329  for (int j=startx; j<=FINISHINGX(mVI); j+=loop_step) {
330  if (A3D_ELEM(V_maski,k,i,j) == 1) {
331  double gx=0.0, gy=0.0, gz=0.0;
332  double k2=k*k;
333  double kr=k*iRmax;
334  double k2i2=k2+i*i;
335  double ir=i*iRmax;
336  double r2=k2i2+j*j;
337  double jr=j*iRmax;
338  double rr=sqrt(r2)*iRmax;
339  for (auto idx : stepsMask) {
340  auto l1 = VEC_ELEM(vL1,idx);
341  auto n = VEC_ELEM(vN,idx);
342  auto l2 = VEC_ELEM(vL2,idx);
343  auto m = VEC_ELEM(vM,idx);
344  auto zsph=ZernikeSphericalHarmonics(l1,n,l2,m,jr,ir,kr,rr);
345  if (rr>0 || l2==0) {
346  gx += VEC_ELEM(clnm,idx) *(zsph);
347  gy += VEC_ELEM(clnm,idx+idxY0) *(zsph);
348  gz += VEC_ELEM(clnm,idx+idxZ0) *(zsph);
349  }
350  }
351  // XX(p) += gx; YY(p) += gy; ZZ(p) += gz;
352  // XX(pos) = 0.0; YY(pos) = 0.0; ZZ(pos) = 0.0;
353  // for (size_t i = 0; i < R.mdimy; i++)
354  // for (size_t j = 0; j < R.mdimx; j++)
355  // VEC_ELEM(pos, i) += MAT_ELEM(R, i, j) * VEC_ELEM(p, j);
356 
357  auto pos = std::array<double, 3>{};
358  pos[0] = j + gx;
359  pos[1] = i + gy;
360  pos[2] = k + gz;
361 
362  double voxel_mVI = A3D_ELEM(mVI,k,i,j);
363  splattingAtPos(pos, voxel_mVI, mVO, mVO2);
364 
365  if (SAVE_DEFORMATION) {
366  Gx(k,i,j) = gx;
367  Gy(k,i,j) = gy;
368  Gz(k,i,j) = gz;
369  }
370 
371  // if (!mVI.outside(pos[2], pos[1], pos[0]))
372  // sumVD += splatVal(pos, voxel_mVI, mVI);
373  deformation += gx*gx+gy*gy+gz*gz;
374  Ncount++;
375  }
376  }
377  }
378  }
379  deformation = sqrt(deformation/Ncount);
380 }
381 
382 void ProgForwardZernikeVol::splattingAtPos(std::array<double, 3> r, double weight, MultidimArray<double> &mVO1, MultidimArray<double> &mVO2) {
383  // Find the part of the volume that must be updated
384  double x_pos = r[0];
385  double y_pos = r[1];
386  double z_pos = r[2];
387  int k0 = XMIPP_MAX(FLOOR(z_pos - blob_r), STARTINGZ(mVO1));
388  int kF = XMIPP_MIN(CEIL(z_pos + blob_r), FINISHINGZ(mVO1));
389  int i0 = XMIPP_MAX(FLOOR(y_pos - blob_r), STARTINGY(mVO1));
390  int iF = XMIPP_MIN(CEIL(y_pos + blob_r), FINISHINGY(mVO1));
391  int j0 = XMIPP_MAX(FLOOR(x_pos - blob_r), STARTINGX(mVO1));
392  int jF = XMIPP_MIN(CEIL(x_pos + blob_r), FINISHINGX(mVO1));
393  // int k0 = XMIPP_MAX(FLOOR(z_pos - sigma4), STARTINGZ(mVO1));
394  // int kF = XMIPP_MIN(CEIL(z_pos + sigma4), FINISHINGZ(mVO1));
395  // int i0 = XMIPP_MAX(FLOOR(y_pos - sigma4), STARTINGY(mVO1));
396  // int iF = XMIPP_MIN(CEIL(y_pos + sigma4), FINISHINGY(mVO1));
397  // int j0 = XMIPP_MAX(FLOOR(x_pos - sigma4), STARTINGX(mVO1));
398  // int jF = XMIPP_MIN(CEIL(x_pos + sigma4), FINISHINGX(mVO1));
399  int size = gaussianProjectionTable.size();
400  for (int k = k0; k <= kF; k++)
401  {
402  double k2 = (z_pos - k) * (z_pos - k);
403  for (int i = i0; i <= iF; i++)
404  {
405  double y2 = (y_pos - i) * (y_pos - i);
406  for (int j = j0; j <= jF; j++)
407  {
408  double mod = sqrt((x_pos - j) * (x_pos - j) + y2 + k2);
409  double didx = mod * 1000;
410  int idx = ROUND(didx);
411  // if (idx < size)
412  // {
413  // double gw = gaussianProjectionTable.vdata[idx];
414  // A3D_ELEM(mVO1, k, i, j) += weight * gw;
415  // A3D_ELEM(mVO2, k, i, j) += weight * gw;
416  // }
417  A3D_ELEM(mVO1,k, i, j) += weight * kaiser_value(mod, blob.radius, blob.alpha, blob.order);
418  A3D_ELEM(mVO2,k, i, j) += weight * kaiser_value(mod, 2, blob.alpha, blob.order);
419  }
420  }
421  }
422 }
423 
424 double ProgForwardZernikeVol::splatVal(std::array<double, 3> r, double weight, const MultidimArray<double> &mV) {
425  // Find the part of the volume that must be updated
426  double x_pos = r[0];
427  double y_pos = r[1];
428  double z_pos = r[2];
429  double val = 0.0;
430  int k0 = XMIPP_MAX(FLOOR(z_pos - blob_r), STARTINGZ(mV));
431  int kF = XMIPP_MIN(CEIL(z_pos + blob_r), FINISHINGZ(mV));
432  int i0 = XMIPP_MAX(FLOOR(y_pos - blob_r), STARTINGY(mV));
433  int iF = XMIPP_MIN(CEIL(y_pos + blob_r), FINISHINGY(mV));
434  int j0 = XMIPP_MAX(FLOOR(x_pos - blob_r), STARTINGX(mV));
435  int jF = XMIPP_MIN(CEIL(x_pos + blob_r), FINISHINGX(mV));
436  for (int k = k0; k <= kF; k++)
437  {
438  double k2 = (z_pos - k) * (z_pos - k);
439  for (int i = i0; i <= iF; i++)
440  {
441  double y2 = (y_pos - i) * (y_pos - i);
442  for (int j = j0; j <= jF; j++)
443  {
444  double mod = sqrt((x_pos - j) * (x_pos - j) + y2 + k2);
445  val += weight * kaiser_value(mod, blob.radius, blob.alpha, blob.order);
446  }
447  }
448  }
449  return val;
450 }
451 
452 // Distance function =======================================================
453 double ProgForwardZernikeVol::distance(double *pclnm)
454 {
455  const MultidimArray<double> &mVR=VR();
457  VEC_ELEM(clnm,i)=pclnm[i+1];
458 
459  if (saveDeformation)
460  deformVolume<true>();
461  else
462  deformVolume<false>();
463 
465  VO.write(fnVolOut);
466 
467  // MultidimArray<int> bg_mask;
468  // bg_mask.resizeNoCopy(VO().zdim, VO().ydim, VO().xdim);
469  // bg_mask.setXmippOrigin();
470  // normalize_Robust(VO(), bg_mask, true);
471 
472  // double val = 0.0;
473  // rmsd(VO(), VR(), val);
474  // return val;
475 
476  // double corr1 = -0.9 * correlationIndex(VO(), VR(), &V_mask2);
477  // double corr2 = -0.1 * correlationIndex(VO2(), VR2(), &V_mask2);
478  // return corr1+corr2+lambda*(deformation);
479 
480  double corr1 = -correlationIndex(VO(), VR(), &V_mask2);
481  return corr1+lambda*(deformation);
482 
483  // volume2Mask(VO(), 0.01);
484 
485  // double massDiff=std::abs(sumVI-sumVD)/sumVI;
486  // double corr2 = -0.25*correlationIndex(VO(), VR(), &V_mask2);
487  // return corr1+corr2+lambda*(deformation);
488 }
489 
490 double continuousZernikeCostVol(double *p, void *vprm)
491 {
493  return prm->distance(p);
494 }
495 
496 // Run =====================================================================
498  // Matrix1D<int> nh;
499  // nh.resize(depth+2);
500  // nh.initConstant(0);
501  // nh(1)=1;
502 
503  VO().initZeros(VR());
504  VO().setXmippOrigin();
505  VO2().initZeros(VR());
506  VO2().setXmippOrigin();
507 
508  saveDeformation=false;
509  sumVI = 0.0;
510  // Numsph(nh);
511 
512  // This filtered version of the input volume is needed to interpolate more accurately VD
513  // MultidimArray<int> bg_mask;
514  // bg_mask.resizeNoCopy(VI().zdim, VI().ydim, VI().xdim);
515  // bg_mask.setXmippOrigin();
516  // normalize_Robust(VI(), bg_mask, true);
517  // // auxI.write("input_filt.vol");
518  // bg_mask *= 0;
519  // normalize_Robust(VR(), bg_mask, true);
520  // auxR.write("ref_filt.vol");
521 
522  // volume2Mask(VR(), 0.01);
523  // volume2Mask(VI(), 0.01);
524  // MultidimArray<double> blobV, blobV2;
525  // volume2Blobs(blobV, blobV2, VR(), V_maskr);
526  // VR() = blobV;
527  // VR2() = blobV2;
528  VR.write("reference_blob.vol");
529  VR2.write("reference_blob2.vol");
530  // volume2Mask(VR(), 0.01);
531 
532  // volume2Blobs(blobV, blobV2, VI(), V_maski);
533  // VI() = blobV;
534  // VI.write("input_blob.vol");
535  // volume2Mask(VI(), 0.01);
536 
537  // Total Volume Mass (Inside Mask)
538  for (int k = STARTINGZ(VI()); k <= FINISHINGZ(VI()); k += loop_step)
539  {
540  for (int i = STARTINGY(VI()); i <= FINISHINGY(VI()); i += loop_step)
541  {
542  for (int j = STARTINGX(VI()); j <= FINISHINGX(VI()); j += loop_step)
543  {
544  if (A3D_ELEM(V_maski, k, i, j) == 1)
545  {
546  auto pos = std::array<double, 3>{};
547  pos[0] = j;
548  pos[1] = i;
549  pos[2] = k;
550  sumVI += splatVal(pos, A3D_ELEM(VI(), k, i, j), VI());
551  }
552  }
553  }
554  }
555 
557  vecSize = 0;
559  size_t totalSize = 3*vecSize;
561  clnm.resize(totalSize);
562  x.initZeros(totalSize);
563 
564  int start=0;
565 
566  if (fn_sph != "") {
567  for (int idx=0; idx<vec.size(); idx++){
568  clnm[idx] = vec[idx];
569  x[idx] = vec[idx];
570  }
571  start = L2;
572  }
573 
574  for (int h=start;h<=L2;h++)
575  {
576  // L = nh(h+1);
577  // prevL = nh(h);
578  // prevsteps=steps;
579  steps.clear();
580  steps.initZeros(totalSize);
581  minimizepos(L1,h,steps);
582  steps_cp = steps;
583 
584  std::cout<<std::endl;
585  std::cout<<"-------------------------- Basis Degrees: ("<<L1<<","<<h<<") --------------------------"<<std::endl;
586  int iter;
587  double fitness;
588  powellOptimizer(x, 1, totalSize, &continuousZernikeCostVol, this,
589  0.01, fitness, iter, steps, true);
590 
591  std::cout<<std::endl;
592  std::cout << "Deformation " << deformation << std::endl;
593  std::ofstream deformFile;
594  deformFile.open (fnRoot+"_deformation.txt");
595  deformFile << deformation;
596  deformFile.close();
597 
598 #ifdef DEBUG
599  Image<double> save;
600  save() = VI();
601  save.write(fnRoot+"_PPPIdeformed.vol");
602  save()-=VR();
603  save.write(fnRoot+"_PPPdiff.vol");
604  save()=VR();
605  save.write(fnRoot+"_PPPR.vol");
606  std::cout << "Error=" << deformation << std::endl;
607  std::cout << "Press any key\n";
608  char c; std::cin >> c;
609 #endif
610 
611  }
612  applyTransformation=true;
613  // x.write(fnRoot+"_clnm.txt");
614  Matrix1D<double> degrees;
615  degrees.initZeros(3);
616  VEC_ELEM(degrees,0) = L1;
617  VEC_ELEM(degrees,1) = L2;
618  VEC_ELEM(degrees,2) = Rmax;
619  writeVector(fnRoot+"_clnm.txt", degrees, false);
620  writeVector(fnRoot+"_clnm.txt", x, true);
621  if (analyzeStrain)
622  {
623  saveDeformation=true;
624  Gx().initZeros(VR());
625  Gy().initZeros(VR());
626  Gz().initZeros(VR());
627  Gx().setXmippOrigin();
628  Gy().setXmippOrigin();
629  Gz().setXmippOrigin();
630  }
631 
632  distance(x.adaptForNumericalRecipes()); // To save the output volume
633 
634 #ifdef DEBUG
635  Image<double> save;
636  save() = Gx();
637  save.write(fnRoot+"_PPPGx.vol");
638  save() = Gy();
639  save.write(fnRoot+"_PPPGy.vol");
640  save() = Gz();
641  save.write(fnRoot+"_PPPGz.vol");
642 #endif
643 
644  if (analyzeStrain)
645  computeStrain();
646 }
647 
648 // // Copy Vectors ============================================================
649 // void ProgForwardZernikeVol::copyvectors(Matrix1D<double> &oldvect,Matrix1D<double> &newvect)
650 // {
651 // size_t groups = 4;
652 // size_t olditems = VEC_XSIZE(oldvect)/groups;
653 // size_t newitems = VEC_XSIZE(newvect)/groups;
654 // for (int g=0;g<groups;g++)
655 // {
656 // for (int i=0;i<olditems;i++)
657 // {
658 // newvect(g*newitems+i) = oldvect(g*olditems+i);
659 // }
660 // }
661 // }
662 
663 // // Minimize Positions ======================================================
664 // void ProgForwardZernikeVol::minimizepos(Matrix1D<double> &vectpos, Matrix1D<double> &prevpos)
665 // {
666 // size_t groups = 4;
667 // size_t olditems = VEC_XSIZE(prevpos)/groups;
668 // size_t newitems = VEC_XSIZE(vectpos)/groups;
669 // for (int i=0;i<olditems;i++)
670 // {
671 // vectpos(3*newitems+i) = 0;
672 // }
673 // if (!optimizeRadius)
674 // {
675 // for (int j=olditems;j<newitems;j++)
676 // {
677 // vectpos(3*newitems+j) = 0;
678 // }
679 // }
680 // }
681 
682 // Minimize Positions ======================================================
683 // void ProgForwardZernikeVol::minimizepos(Matrix1D<double> &vectpos, int &current_l2)
684 // {
685 // size_t currentSize = std::floor((4+4*L1+std::pow(L1,2))/4)*std::pow(current_l2+1,2);
686 // for (int i=0;i<currentSize;i++)
687 // {
688 // VEC_ELEM(vectpos,i) = 1;
689 // VEC_ELEM(vectpos,i+vecSize) = 1;
690 // VEC_ELEM(vectpos,i+2*vecSize) = 1;
691 // }
692 // }
693 
695 {
696  int size = 0;
697  numCoefficients(L1,l2,size);
698  int totalSize = steps.size()/3;
699  for (int idx=0; idx<size; idx++)
700  {
701  VEC_ELEM(steps,idx) = 1;
702  VEC_ELEM(steps,idx+totalSize) = 1;
703  VEC_ELEM(steps,idx+2*totalSize) = 1;
704  }
705 }
706 
707 // // Number Spherical Harmonics ==============================================
708 // void ProgForwardZernikeVol::Numsph(Matrix1D<int> &sphD)
709 // {
710 // for (int d=1;d<(VEC_XSIZE(sphD)-1);d++)
711 // {
712 // if (d%2==0)
713 // {
714 // sphD(d+1) = sphD(d)+((d/2)+1)*(2*d+1);
715 // }
716 // else
717 // {
718 // sphD(d+1) = sphD(d)+(((d-1)/2)+1)*(2*d+1);
719 // }
720 // }
721 // }
722 
723 // Length of coefficients vector
724 // void ProgForwardZernikeVol::numCoefficients(int l1, int l2, int &vecSize)
725 // {
726 // vecSize = std::floor((4+4*l1+std::pow(l1,2))/4)*std::pow(l2+1,2);
727 // }
728 
730 {
731  for (int h=0; h<=l2; h++)
732  {
733  int numSPH = 2*h+1;
734  int count=l1-h+1;
735  int numEven=(count>>1)+(count&1 && !(h&1));
736  if (h%2 == 0)
737  vecSize += numSPH*numEven;
738  else
739  vecSize += numSPH*(l1-h+1-numEven);
740  }
741 }
742 
744 {
745  int idx = 0;
750  for (int h=0; h<=l2; h++) {
751  int totalSPH = 2*h+1;
752  int aux = std::floor(totalSPH/2);
753  for (int l=h; l<=l1; l+=2) {
754  for (int m=0; m<totalSPH; m++) {
755  VEC_ELEM(vL1,idx) = l;
756  VEC_ELEM(vN,idx) = h;
757  VEC_ELEM(vL2,idx) = h;
758  VEC_ELEM(vM,idx) = m-aux;
759  idx++;
760  }
761  }
762  }
763 }
764 
765 // void ProgForwardZernikeVol::fillVectorTerms(Matrix1D<int> &vL1, Matrix1D<int> &vN, Matrix1D<int> &vL2, Matrix1D<int> &vM)
766 // {
767 // vL1.initZeros(vecSize);
768 // vN.initZeros(vecSize);
769 // vL2.initZeros(vecSize);
770 // vM.initZeros(vecSize);
771 // for (int idx=0;idx<vecSize;idx++)
772 // {
773 // int l1,n,l2,m;
774 // spherical_index2lnm(idx,l1,n,l2,m,L1);
775 // VEC_ELEM(vL1,idx) = l1;
776 // VEC_ELEM(vN,idx) = n;
777 // VEC_ELEM(vL2,idx) = l2;
778 // VEC_ELEM(vM,idx) = m;
779 // }
780 // }
781 
782 // Number Spherical Harmonics ==============================================
783 #define Dx(V) (A3D_ELEM(V,k,i,jm2)-8*A3D_ELEM(V,k,i,jm1)+8*A3D_ELEM(V,k,i,jp1)-A3D_ELEM(V,k,i,jp2))/12.0
784 #define Dy(V) (A3D_ELEM(V,k,im2,j)-8*A3D_ELEM(V,k,im1,j)+8*A3D_ELEM(V,k,ip1,j)-A3D_ELEM(V,k,ip2,j))/12.0
785 #define Dz(V) (A3D_ELEM(V,km2,i,j)-8*A3D_ELEM(V,km1,i,j)+8*A3D_ELEM(V,kp1,i,j)-A3D_ELEM(V,kp2,i,j))/12.0
786 
788 {
789  Image<double> LS, LR;
790  LS().initZeros(Gx());
791  LR().initZeros(Gx());
792 
793  // Gaussian filter of the derivatives
797  f.w1=2;
798  f.applyMaskSpace(Gx());
799  f.applyMaskSpace(Gy());
800  f.applyMaskSpace(Gz());
801 
802  Gx.write(fnRoot+"_PPPGx.vol");
803  Gy.write(fnRoot+"_PPPGy.vol");
804  Gz.write(fnRoot+"_PPPGz.vol");
805 
806  MultidimArray<double> &mLS=LS();
807  MultidimArray<double> &mLR=LR();
808  MultidimArray<double> &mGx=Gx();
809  MultidimArray<double> &mGy=Gy();
810  MultidimArray<double> &mGz=Gz();
811  Matrix2D<double> U(3,3), D(3,3), H(3,3);
812  std::vector< std::complex<double> > eigs;
813  H.initZeros();
814  for (int k=STARTINGZ(mLS)+2; k<=FINISHINGZ(mLS)-2; ++k)
815  {
816  int km1=k-1;
817  int kp1=k+1;
818  int km2=k-2;
819  int kp2=k+2;
820  for (int i=STARTINGY(mLS)+2; i<=FINISHINGY(mLS)-2; ++i)
821  {
822  int im1=i-1;
823  int ip1=i+1;
824  int im2=i-2;
825  int ip2=i+2;
826  for (int j=STARTINGX(mLS)+2; j<=FINISHINGX(mLS)-2; ++j)
827  {
828  int jm1=j-1;
829  int jp1=j+1;
830  int jm2=j-2;
831  int jp2=j+2;
832  MAT_ELEM(U,0,0)=Dx(mGx); MAT_ELEM(U,0,1)=Dy(mGx); MAT_ELEM(U,0,2)=Dz(mGx);
833  MAT_ELEM(U,1,0)=Dx(mGy); MAT_ELEM(U,1,1)=Dy(mGy); MAT_ELEM(U,1,2)=Dz(mGy);
834  MAT_ELEM(U,2,0)=Dx(mGz); MAT_ELEM(U,2,1)=Dy(mGz); MAT_ELEM(U,2,2)=Dz(mGz);
835 
836  MAT_ELEM(D,0,0) = MAT_ELEM(U,0,0);
837  MAT_ELEM(D,0,1) = MAT_ELEM(D,1,0) = 0.5*(MAT_ELEM(U,0,1)+MAT_ELEM(U,1,0));
838  MAT_ELEM(D,0,2) = MAT_ELEM(D,2,0) = 0.5*(MAT_ELEM(U,0,2)+MAT_ELEM(U,2,0));
839  MAT_ELEM(D,1,1) = MAT_ELEM(U,1,1);
840  MAT_ELEM(D,1,2) = MAT_ELEM(D,2,1) = 0.5*(MAT_ELEM(U,1,2)+MAT_ELEM(U,2,1));
841  MAT_ELEM(D,2,2) = MAT_ELEM(U,2,2);
842 
843  MAT_ELEM(H,0,1) = 0.5*(MAT_ELEM(U,0,1)-MAT_ELEM(U,1,0));
844  MAT_ELEM(H,0,2) = 0.5*(MAT_ELEM(U,0,2)-MAT_ELEM(U,2,0));
845  MAT_ELEM(H,1,2) = 0.5*(MAT_ELEM(U,1,2)-MAT_ELEM(U,2,1));
846  MAT_ELEM(H,1,0) = -MAT_ELEM(H,0,1);
847  MAT_ELEM(H,2,0) = -MAT_ELEM(H,0,2);
848  MAT_ELEM(H,2,1) = -MAT_ELEM(H,1,2);
849 
850  A3D_ELEM(mLS,k,i,j)=fabs(D.det());
851  allEigs(H,eigs);
852  for (size_t n=0; n < eigs.size(); n++)
853  {
854  double imagabs=fabs(eigs[n].imag());
855  if (imagabs>1e-6)
856  {
857  A3D_ELEM(mLR,k,i,j)=imagabs*180/PI;
858  break;
859  }
860  }
861  }
862  }
863  LS.write(fnVolOut.withoutExtension()+"_strain.mrc");
864  LR.write(fnVolOut.withoutExtension()+"_rotation.mrc");
865  }
866 }
867 
868 void ProgForwardZernikeVol::writeVector(std::string outPath, Matrix1D<double> v, bool append)
869 {
870  std::ofstream outFile;
871  if (append == false)
872  outFile.open(outPath);
873  else
874  outFile.open(outPath, std::ios_base::app);
876  outFile << VEC_ELEM(v,i) << " ";
877  outFile << std::endl;
878 }
879 
880 std::string ProgForwardZernikeVol::readNthLine(int N) const
881 {
882  std::ifstream in(fn_sph.getString());
883  std::string s;
884 
885  //skip N lines
886  for(int i = 0; i < N; ++i)
887  std::getline(in, s);
888 
889  std::getline(in,s);
890  return s;
891 }
892 
893 std::vector<double> ProgForwardZernikeVol::string2vector(std::string const &s) const
894 {
895  std::stringstream iss(s);
896  double number;
897  std::vector<double> v;
898  while (iss >> number)
899  v.push_back(number);
900  return v;
901 }
902 
904 {
905  // blob.radius = 2 * blob_r;
906  vol.initZeros(mV);
907  vol.setXmippOrigin();
908  vol2.initZeros(mV);
909  vol2.setXmippOrigin();
910  for (int k=STARTINGZ(mV); k<=FINISHINGZ(mV); k+=loop_step) {
911  for (int i=STARTINGY(mV); i<=FINISHINGY(mV); i+=loop_step) {
912  for (int j=STARTINGX(mV); j<=FINISHINGX(mV); j+=loop_step) {
913  if (A3D_ELEM(mask,k,i,j) == 1) {
914  auto pos = std::array<double, 3>{};
915  pos[0] = j;
916  pos[1] = i;
917  pos[2] = k;
918  double voxel_mV= A3D_ELEM(mV,k,i,j);
919  splattingAtPos(pos, voxel_mV, vol, vol2);
920  }
921  }
922  }
923  }
924  // blob.radius = 2 * blob_r;
925 }
926 
928 {
929  for (int k = STARTINGZ(vol); k <= FINISHINGZ(vol); k ++)
930  {
931  for (int i = STARTINGY(vol); i <= FINISHINGY(vol); i ++)
932  {
933  for (int j = STARTINGX(vol); j <= FINISHINGX(vol); j ++)
934  {
935  if (A3D_ELEM(vol, k, i, j) >= thr)
936  A3D_ELEM(vol, k, i, j) = 1.0;
937  else
938  A3D_ELEM(vol, k, i, j) = 0.0;
939  }
940  }
941  }
942 }
943 
945 {
946  const MultidimArray<double> mVI = VI();
947  const MultidimArray<double> mVR = VR();
948  const MultidimArray<double> mVR2 = VR2();
949  double N = 0.0;
950  for (int k = STARTINGZ(vol1); k <= FINISHINGZ(vol1); k +=loop_step)
951  {
952  for (int i = STARTINGY(vol1); i <= FINISHINGY(vol1); i +=loop_step)
953  {
954  for (int j = STARTINGX(vol1); j <= FINISHINGX(vol1); j +=loop_step)
955  {
956  // double diff1 = (A3D_ELEM(vol1, k, i, j) - A3D_ELEM(mVR, k, i, j)) / (abs(A3D_ELEM(mVR, k, i, j)) + 0.0001);
957  double diffv1 = A3D_ELEM(vol1, k, i, j) - A3D_ELEM(mVR, k, i, j);
958  double diffv2 = A3D_ELEM(vol2, k, i, j) - A3D_ELEM(mVR2, k, i, j);
959  double diff2v1 = 1.0;
960  if (A3D_ELEM(mVR, k, i, j) == 0.0 || A3D_ELEM(mVI, k, i, j) == 0.0)
961  double diff2v1 = A3D_ELEM(mVR, k, i, j) - A3D_ELEM(mVI, k, i, j);
962  double diff2v2 = 1.0;
963  if (A3D_ELEM(mVR2, k, i, j) == 0.0 || A3D_ELEM(mVI, k, i, j) == 0.0)
964  double diff2v2 = A3D_ELEM(mVR2, k, i, j) - A3D_ELEM(mVI, k, i, j);
965  // double diff = A3D_ELEM(vol1, k, i, j) - A3D_ELEM(vol2, k, i, j);
966  // val += 0.5 * ((diffv1 * diffv1) * (diff2v1 * diff2v1) + (diffv2 * diffv2) * (diff2v2 * diff2v2));
967  val += 0.5 * ((diffv1 * diffv1) + (diffv2 * diffv2));
968  // val += diff1 * diff1;
969  // N += abs(A3D_ELEM(mVR, k, i, j)) + 0.0001;
970  // N += 0.5 * (diff2v1 + diff2v2);
971  N++;
972  }
973  }
974  }
975  val = std::sqrt(val / N);
976 }
double kaiser_value(double r, double a, double alpha, int m)
Definition: blobs.cpp:37
bool analyzeStrain
Save the deformation of each voxel for local strain and rotation analysis.
#define VEC_ELEM(v, i)
Definition: matrix1d.h:245
double alpha
Smoothness parameter.
Definition: blobs.h:121
#define XMIPP_MAX(x, y)
Definition: xmipp_macros.h:193
double getDoubleParam(const char *param, int arg=0)
__host__ __device__ float2 floor(const float2 v)
void clear()
Definition: matrix1d.cpp:67
double continuousZernikeCostVol(double *p, void *vprm)
#define FINISHINGX(v)
std::string readNthLine(int N) const
size_t size() const
Definition: matrix1d.h:508
#define Dy(V)
void volume2Blobs(MultidimArray< double > &vol, MultidimArray< double > &vol2, const MultidimArray< double > &mV, const MultidimArray< int > &mask)
#define VEC_XSIZE(m)
Definition: matrix1d.h:77
doublereal * c
Definition: mask.h:360
void computeStrain()
Compute strain.
void sqrt(Image< double > &op)
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)
double correlationIndex(const MultidimArray< T > &x, const MultidimArray< T > &y, const MultidimArray< int > *mask=NULL, MultidimArray< double > *Contributions=NULL)
FileName fnMaskR
Filename of the reference volume mask.
int l
Definition: svm.h:62
void powellOptimizer(Matrix1D< double > &p, int i0, int n, double(*f)(double *x, void *), void *prm, double ftol, double &fret, int &iter, const Matrix1D< double > &steps, bool show)
FileName fnVolR
Reference volume.
#define FINISHINGZ(v)
glob_prnt iter
int vecSize
Coefficient vector size.
#define STARTINGX(v)
doublereal * x
#define i
ql0001_ & k(htemp+1),(cvec+1),(atemp+1),(bj+1),(bl+1),(bu+1),(x+1),(clamda+1), &iout, infoqp, &zero,(w+1), &lenw,(iw+1), &leniw, &glob_grd.epsmac
Matrix1D< double > gaussianProjectionTable2
#define STARTINGY(v)
#define MAT_ELEM(m, i, j)
Definition: matrix2d.h:116
#define A3D_ELEM(V, k, i, j)
#define FOR_ALL_ELEMENTS_IN_MATRIX1D(v)
Definition: matrix1d.h:72
#define FLOOR(x)
Definition: xmipp_macros.h:240
void minimizepos(int L1, int l2, Matrix1D< double > &steps)
Determine the positions to be minimize of a vector containing spherical harmonic coefficients.
Image< double > VI
Images.
const char * getParam(const char *param, int arg=0)
#define CEIL(x)
Definition: xmipp_macros.h:225
#define Dx(V)
int in
double * f
double splatVal(std::array< double, 3 > r, double weight, const MultidimArray< double > &mV)
double R1
Definition: mask.h:413
double Rmax
Maximum radius for the transformation.
void resize(size_t Xdim, bool copy=true)
Definition: matrix1d.h:410
MultidimArray< int > V_maskr
#define XSIZE(v)
int type
Definition: mask.h:402
FileName fnVolI
Volume to deform.
void addExampleLine(const char *example, bool verbatim=true)
#define ROUND(x)
Definition: xmipp_macros.h:210
void fillVectorTerms(int l1, int l2)
Zernike and SPH coefficients allocation.
void writeVector(std::string outPath, Matrix1D< double > v, bool append)
Save vector to file.
int verbose
Verbosity level.
void defineParams()
Define params.
MultidimArray< int > V_maski
3D mask for reference volume
int L1
Degree of Zernike polynomials and spherical harmonics.
void initZeros()
Definition: matrix1d.h:592
void mod(const MultidimArray< T > &x, MultidimArray< T > &m, double y)
double distance(double *pclnm)
Distance.
#define XMIPP_MIN(x, y)
Definition: xmipp_macros.h:181
void allEigs(const Matrix2D< double > &A, std::vector< std::complex< double > > &eigs)
Definition: matrix2d.cpp:345
std::vector< double > vec
#define j
double steps
int m
#define Dz(V)
std::vector< double > string2vector(std::string const &s) const
#define FINISHINGY(v)
void generate_mask(bool apply_geo=false)
Definition: mask.cpp:1577
bool optimizeRadius
Radius optimization.
Matrix1D< double > gaussianProjectionTable
void rmsd(MultidimArray< double > vol1, MultidimArray< double > vol2, double &val)
FileName withoutExtension() const
void typeCast(const Matrix1D< T1 > &v1, Matrix1D< T2 > &v2)
Definition: matrix1d.h:1227
void splattingAtPos(std::array< double, 3 > r, double weight, MultidimArray< double > &mVO1, MultidimArray< double > &mVO2)
#define BINARY_CIRCULAR_MASK
Definition: mask.h:365
double ZernikeSphericalHarmonics(int n, int m, double xr, double yr, double zr, double r)
FileName fnRoot
Root name for several output files.
String getString() const
int order
Derivation order and Bessel function order.
Definition: blobs.h:118
void initZeros()
Definition: matrix2d.h:626
bool checkParam(const char *param)
MultidimArray< int > V_mask2
int read(const FileName &name, DataMode datamode=DATA, size_t select_img=ALL_IMAGES, bool mapData=false, int mode=WRITE_READONLY)
float r2
ProgClassifyCL2D * prm
#define REALGAUSSIAN
void addUsageLine(const char *line, bool verbatim=false)
void initZeros(const MultidimArray< T1 > &op)
const MultidimArray< int > & get_binary_mask() const
Definition: mask.h:707
#define PI
Definition: tools.h:43
T * adaptForNumericalRecipes() const
Definition: matrix1d.h:844
int getIntParam(const char *param, int arg=0)
#define STARTINGZ(v)
double radius
Spatial radius in Universal System units.
Definition: blobs.h:115
int * n
void readParams()
Read arguments from command line.
double fitness(double *p)
#define LOWPASS
void addParamsLine(const String &line)
int ir
int mode
Definition: mask.h:407
void applyMaskSpace(MultidimArray< double > &v)
FileName fnVolOut
Output Volume (deformed input volume)
void numCoefficients(int l1, int l2, int &vecSize)
Length of coefficients vector.
void volume2Mask(MultidimArray< double > &vol, double thr)
constexpr int INNER_MASK
Definition: mask.h:47
double gaussian1D(double x, double sigma, double mu)