Xmipp  v3.23.11-Nereus
volume_halves_restoration.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Carlos Oscar Sanchez 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 
27 #include <data/numerical_tools.h>
28 
29 // Read arguments ==========================================================
31 {
32  fnV1 = getParam("--i1");
33  fnV2 = getParam("--i2");
34  fnRoot = getParam("--oroot");
35  NiterReal = getIntParam("--denoising");
36  NiterFourier = getIntParam("--deconvolution");
37  sigma0 = getDoubleParam("--deconvolution",1);
38  lambda = getDoubleParam("--deconvolution",2);
39  bankStep = getDoubleParam("--filterBank",0);
40  bankOverlap = getDoubleParam("--filterBank",1);
41  weightFun = getIntParam("--filterBank",2);
42  weightPower = getDoubleParam("--filterBank",3);
43  NiterDiff = getIntParam("--difference");
44  Kdiff = getDoubleParam("--difference",1);
45  if (checkParam("--mask"))
46  mask.readParams(this);
47 }
48 
49 // Show ====================================================================
51 {
52  if (!verbose)
53  return;
54  std::cout
55  << "Volume1: " << fnV1 << std::endl
56  << "Volume2: " << fnV2 << std::endl
57  << "Rootname: " << fnRoot << std::endl
58  << "Denoising Iterations: " << NiterReal << std::endl
59  << "Deconvolution Iterations: " << NiterFourier << std::endl
60  << "Sigma0: " << sigma0 << std::endl
61  << "Lambda: " << lambda << std::endl
62  << "Bank step:" << bankStep << std::endl
63  << "Bank overlap:" << bankOverlap << std::endl
64  << "Weight fun:" << weightFun << std::endl
65  << "Weight power:" << weightPower << std::endl
66  << "Difference Iterations: " << NiterDiff << std::endl
67  << "Kdiff: " << Kdiff << std::endl
68  ;
69  mask.show();
70 }
71 
72 // usage ===================================================================
74 {
75  addUsageLine("Given two halves of a volume (and an optional mask), produce a better estimate of the volume underneath");
76  addParamsLine(" --i1 <volume1> : First half");
77  addParamsLine(" --i2 <volume2> : Second half");
78  addParamsLine(" [--oroot <root=\"volumeRestored\">] : Output rootname");
79  addParamsLine(" [--denoising <N=0>] : Number of iterations of denoising in real space");
80  addParamsLine(" [--deconvolution <N=0> <sigma0=0.2> <lambda=0.001>] : Number of iterations of deconvolution in Fourier space, initial sigma and lambda");
81  addParamsLine(" [--filterBank <step=0> <overlap=0.5> <weightFun=1> <weightPower=3>] : Frequency step for the filter bank (typically, 0.01; between 0 and 0.5)");
82  addParamsLine(" : filter overlap is between 0 (no overlap) and 1 (full overlap)");
83  addParamsLine(" : Weight function (0=mean, 1=min, 2=mean*diff");
84  addParamsLine(" [--difference <N=0> <K=1.5>] : Number of iterations of difference evaluation in real space");
86 }
87 
89 {
90  V1.read(fnV1);
91  V2.read(fnV2);
92  V1().setXmippOrigin();
93  V2().setXmippOrigin();
94 
95  if (mask.fn_mask!="")
96  {
99  pMaskSize=(size_t)(pMask->sum());
100  }
101  else
102  pMask = nullptr;
103 
104  V1r()=V1(); // Copy the restored volumes
105  V2r()=V2();
106 
107  // Initialize filter and calculate frequencies
110  R2.initConstant(-1);
111  const MultidimArray<double> &mV1=V1();
113  {
114  double fz, fy, fx;
115  FFT_IDX2DIGFREQ(k,ZSIZE(mV1),fz);
116  FFT_IDX2DIGFREQ(i,YSIZE(mV1),fy);
117  FFT_IDX2DIGFREQ(j,XSIZE(mV1),fx);
118  A3D_ELEM(R2,k,i,j) = fx*fx+fy*fy+fz*fz;
119  }
120 }
121 
123 {
124  show();
125  produceSideInfo();
126 
127  if (NiterReal>0)
128  for (int iter=0; iter<NiterReal; iter++)
129  {
130  std::cout << "Denoising iteration " << iter << std::endl;
131  estimateS();
134  }
135 
136  if (NiterFourier>0)
137  {
139  for (int iter=0; iter<NiterFourier; iter++)
140  {
141  std::cout << "Deconvolution iteration " << iter << std::endl;
142  estimateS();
143 
147  optimizeSigma();
148 
149  deconvolveS();
150  }
151 
152  S.write(fnRoot+"_deconvolved.vol");
153  convolveS();
154  S.write(fnRoot+"_convolved.vol");
155  }
156 
157  if (bankStep>0)
158  filterBank();
159 
160  if (NiterDiff>0)
161  for (int iter=0; iter<NiterDiff; iter++)
162  {
163  std::cout << "Difference iteration " << iter << std::endl;
165  }
166 
167  V1r.write(fnRoot+"_restored1.vol");
168  V2r.write(fnRoot+"_restored2.vol");
169 }
170 
172 {
173  S().resizeNoCopy(V1r());
174  MultidimArray<double> &mS=S();
175  const MultidimArray<double> &mV1r=V1r();
176  const MultidimArray<double> &mV2r=V2r();
177 
178  // Compute average
181 
182  // Apply mask
183  if (pMask!=nullptr)
185  if (DIRECT_MULTIDIM_ELEM(*pMask,n)==0)
186  DIRECT_MULTIDIM_ELEM(mS,n)=0;
187 
188  // Apply positivity
190  if (DIRECT_MULTIDIM_ELEM(mS,n)<0)
191  DIRECT_MULTIDIM_ELEM(mS,n)=0;
192 
193  // Filter S
196  if (DIRECT_MULTIDIM_ELEM(R2,n)>0.25)
199 
200  // Calculate HS CDF in real space
202  if (pMask==nullptr)
203  {
204  aux=S();
205  aux*=aux;
206  }
207  else
208  {
209  aux.resizeNoCopy(pMaskSize);
210  size_t idx=0;
212  if (DIRECT_MULTIDIM_ELEM(*pMask,n)!=0)
214  }
215  cdfS.calculateCDF(aux);
216 }
217 
219 {
220  // Calculate N=Vi-H*S and its energy CDF
221  N().resizeNoCopy(Vi);
222  MultidimArray<double> &mN=N();
223  const MultidimArray<double> &mS=S();
225  {
226  double diff=DIRECT_MULTIDIM_ELEM(Vi,n)-DIRECT_MULTIDIM_ELEM(mS,n);
227  DIRECT_MULTIDIM_ELEM(mN,n)=diff*diff;
228  }
229  CDF cdfN;
230  cdfN.calculateCDF(mN);
231 
232  // Mask the input volume with a mask value that is proportional to the probability of being larger than noise
233  Vir.resizeNoCopy(Vi);
235  {
236  double e=DIRECT_MULTIDIM_ELEM(Vi,n)*DIRECT_MULTIDIM_ELEM(Vi,n);
237  double pN=cdfN.getProbability(e);
238  if (pN<1)
239  {
240  double pS=cdfS.getProbability(e);
241  double pp=pS*pN;
243  }
244  else
246  }
247 }
248 
250 {
251  if (verbose>0)
252  std::cout << " Deconvolving with sigma=" << sigmaConv1 << " " << sigmaConv2 << std::endl;
253  double K1=-0.5/(sigmaConv1*sigmaConv1);
254  double K2=-0.5/(sigmaConv2*sigmaConv2);
256  {
257  double R2n=DIRECT_MULTIDIM_ELEM(R2,n);
258  if (R2n<=0.25)
259  {
260  double H1=exp(K1*R2n);
261  double H2=exp(K2*R2n);
263 
266  }
267  }
270 
271 // MultidimArray<double> &mS=S();
272 // transformer.inverseFourierTransform();
273 // S.write("PPPS.vol");
274 }
275 
277 {
278  double sigmaConv=(sigmaConv1+sigmaConv2)/2;
279  double K=-0.5/(sigmaConv*sigmaConv);
281  {
282  double R2n=DIRECT_MULTIDIM_ELEM(R2,n);
283  if (R2n<=0.25)
284  {
285  double H1=exp(K*R2n);
287  }
288  }
290 }
291 
292 double restorationSigmaCost(double *x, void *_prm)
293 {
294  auto *prm=(ProgVolumeHalvesRestoration *) _prm;
295  double sigma1=x[1];
296  double sigma2=x[2];
297  if (sigma1<0 || sigma2<0 || sigma1>2 || sigma2>2)
298  return 1e38;
299  double K1=-0.5/(sigma1*sigma1);
300  double K2=-0.5/(sigma2*sigma2);
301  double error=0;
302  double N=0;
303  const MultidimArray< std::complex<double> > &fV=prm->fVol;
306  const MultidimArray<double> &R2=prm->R2;
308  {
309  double R2n=DIRECT_MULTIDIM_ELEM(R2,n);
310  if (R2n<=0.25)
311  {
312  double H1=exp(K1*R2n);
313  double H2=exp(K2*R2n);
314  error+=abs(DIRECT_MULTIDIM_ELEM(fV,n)*H1-DIRECT_MULTIDIM_ELEM(fV1r,n))+
316  N++;
317  }
318  }
319  return error;
320 }
321 
323 {
324 
325  Matrix1D<double> p(2), steps(2);
326  p(0)=sigmaConv1;
327  p(1)=sigmaConv2;
328  steps.initConstant(1);
329  double cost;
330  int iter;
331  powellOptimizer(p, 1, 2, &restorationSigmaCost, this, 0.01, cost, iter, steps, verbose>=2);
332  sigmaConv1=p(0);
333  sigmaConv2=p(1);
334 }
335 
337 {
338  // Apply band pass filter
339  double w2=w*w;
340  double w2Step=(w+bankStep)*(w+bankStep);
341  MultidimArray< std::complex<double> >&fVout=transformer.fFourier;
342  fVout.initZeros();
344  {
345  double R2n=DIRECT_MULTIDIM_ELEM(R2,n);
346  if (R2n>=w2 && R2n<w2Step)
348  }
349  transformer.inverseFourierTransform();
350 }
351 
352 //#define DEBUG
354 {
355  MultidimArray<double> Vfiltered1, Vfiltered2;
356  Vfiltered1.initZeros(V1r());
357  Vfiltered2.initZeros(V2r());
358 
361 
362  FourierTransformer bank1, bank2;
363  bank1.setReal(Vfiltered1);
364  bank2.setReal(Vfiltered2);
365  double filterStep = bankStep*(1-bankOverlap);
366  MultidimArray<double> &mV1r=V1r();
367  MultidimArray<double> &mV2r=V2r();
368  MultidimArray<double> &mS=S();
369  mV1r.initZeros(Vfiltered2);
370  mV2r.initZeros(Vfiltered2);
371  mS.initZeros(Vfiltered2);
372  int i=0;
373  int imax=ceil(0.5/filterStep);
374  std::cerr << "Calculating filter bank ..." << std::endl;
375  init_progress_bar(imax);
376 
377  // keep this comment to understand the while
378  // for (double w=0; w<0.5; w+=filterStep)
379  double w=0;
380  for(; w<0.5; w+=filterStep)
381  {
382  filterBand(fV1r,bank1,w);
383  filterBand(fV2r,bank2,w);
384 
385  // Compute energy of the noise
386  N().resizeNoCopy(Vfiltered1);
387  MultidimArray<double> &mN=N();
389  {
390  double diff=DIRECT_MULTIDIM_ELEM(Vfiltered1,n)-DIRECT_MULTIDIM_ELEM(Vfiltered2,n);
391  DIRECT_MULTIDIM_ELEM(mN,n)=0.5*diff*diff;
392  }
393 
394  CDF cdfN;
395  cdfN.calculateCDF(mN);
396 
397  // Compute weights
399  {
400  double e1=DIRECT_MULTIDIM_ELEM(Vfiltered1,n)*DIRECT_MULTIDIM_ELEM(Vfiltered1,n);
401  double w1=cdfN.getProbability(e1);
402 
403  double e2=DIRECT_MULTIDIM_ELEM(Vfiltered2,n)*DIRECT_MULTIDIM_ELEM(Vfiltered2,n);
404  double w2=cdfN.getProbability(e2);
405 
406  double weight = 0;
407  switch (weightFun)
408  {
409  case 0: weight=0.5*(w1+w2); break;
410  case 1: weight=std::min(w1,w2); break;
411  case 2: weight=0.5*(w1+w2)*(1-fabs(w1-w2)/(w1+w2)); break;
412  }
413  weight=pow(weight,weightPower);
414 
415  double Vf1w=DIRECT_MULTIDIM_ELEM(Vfiltered1,n)*weight;
416  double Vf2w=DIRECT_MULTIDIM_ELEM(Vfiltered2,n)*weight;
417  DIRECT_MULTIDIM_ELEM(mV1r,n)+=Vf1w;
418  DIRECT_MULTIDIM_ELEM(mV2r,n)+=Vf2w;
419  if (e1>e2)
420  DIRECT_MULTIDIM_ELEM(mS,n)+=Vf1w;
421  else
422  DIRECT_MULTIDIM_ELEM(mS,n)+=Vf2w;
423  }
424  progress_bar(++i);
425 
426 #ifdef DEBUG
427  Image<double> save;
428  save()=Vfiltered1;
429  save.write("PPP1.vol");
430  save()=mV1r;
431  save.write("PPP1r.vol");
432  save()=Vfiltered2;
433  save.write("PPP2.vol");
434  save()=mS;
435  save.write("PPPS.vol");
436  save()=Vfiltered2-Vfiltered1;
437  save.write("PPPdiff.vol");
438  save()=weight;
439  save.write("PPPweight.vol");
440  save()=sumWeight;
441  save.write("PPPsumWeight.vol");
442  std::cout << "w=" << w << " Press";
443  char c; std::cin >> c;
444 #endif
445  }
446  progress_bar(imax);
447 
448  S() *= 1-bankOverlap;
449  mV1r *= 1-bankOverlap;
450  mV2r *= 1-bankOverlap;
451  S.write(fnRoot+"_filterBank.vol");
452 }
453 
455 {
456  // Compute the difference between the two
457  N()=V1r();
458  N()-=V2r();
459 
460  S()=V1r();
461  S()+=V2r();
462  S()*=0.5;
463 
464  // Compute the std within the signal mask
465  double mean, stddev;
466  if (pMask==nullptr)
467  N().computeAvgStdev(mean,stddev);
468  else
469  N().computeAvgStdev_within_binary_mask(*pMask,mean,stddev);
470  stddev*=Kdiff;
471 
474  MultidimArray<double> &mN=N();
475  MultidimArray<double> &mS=S();
476  double k=-0.5/(stddev*stddev);
478  {
479  double w=exp(k*DIRECT_MULTIDIM_ELEM(mN,n)*DIRECT_MULTIDIM_ELEM(mN,n));
480  double s=DIRECT_MULTIDIM_ELEM(mS,n);
481  double d1=DIRECT_MULTIDIM_ELEM(m1,n)-s;
482  double d2=DIRECT_MULTIDIM_ELEM(m2,n)-s;
483  DIRECT_MULTIDIM_ELEM(m1,n)=s+d1*w;
484  DIRECT_MULTIDIM_ELEM(m2,n)=s+d2*w;
485  }
486 
487  S()=V1r();
488  S()+=V2r();
489  S()*=0.5;
490  S.write(fnRoot+"_avgDiff.vol");
491 }
void init_progress_bar(long total)
#define YSIZE(v)
void min(Image< double > &op1, const Image< double > &op2)
void readParams()
Read argument from command line.
double getDoubleParam(const char *param, int arg=0)
void inverseFourierTransform()
Definition: xmipp_fftw.cpp:329
void produceSideInfo()
Side information.
doublereal * c
FileName fn_mask
Definition: mask.h:487
void resizeNoCopy(const MultidimArray< T1 > &v)
#define pp(s, x)
Definition: ml2d.cpp:473
MultidimArray< std::complex< double > > fFourier
Definition: xmipp_fftw.h:70
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)
MultidimArray< std::complex< double > > fV2r
doublereal * w
void initConstant(T val)
void abs(Image< double > &op)
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)
#define FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(V)
glob_prnt iter
void calculateCDF(MultidimArray< double > &V, double probStep=0.005)
Calculate the CDF of V with a probability step of 0.005 (p is between 0 and 1)
Definition: histogram.cpp:258
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
static void defineParams(XmippProgram *program, int allowed_data_types=ALL_KINDS, const char *prefix=nullptr, const char *comment=nullptr, bool moreOptions=false)
Definition: mask.cpp:1203
#define A3D_ELEM(V, k, i, j)
double restorationSigmaCost(double *x, void *_prm)
const char * getParam(const char *param, int arg=0)
void setReal(MultidimArray< double > &img)
Definition: xmipp_fftw.cpp:129
void defineParams()
Define parameters.
Definition: histogram.h:365
#define XSIZE(v)
void progress_bar(long rlen)
double getProbability(double x)
Get the probability Pr{V<=x}.
Definition: histogram.cpp:280
#define FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(v)
#define ZSIZE(v)
#define DIRECT_MULTIDIM_ELEM(v, n)
MultidimArray< std::complex< double > > fV1r
void significanceRealSpace(const MultidimArray< double > &V1, MultidimArray< double > &V1r)
void readParams(XmippProgram *program)
Definition: mask.cpp:1284
int verbose
Verbosity level.
void filterBand(const MultidimArray< std::complex< double > > &Vin, FourierTransformer &transformer, double w)
void FourierTransform(T &v, T1 &V, bool getCopy=true)
Definition: xmipp_fftw.h:166
__device__ float FFT_IDX2DIGFREQ(int idx, int size)
#define j
double steps
void error(char *s)
Definition: tools.cpp:107
void generate_mask(bool apply_geo=false)
Definition: mask.cpp:1577
#define INT_MASK
Definition: mask.h:385
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)
constexpr int K
ProgClassifyCL2D * prm
void estimateS()
Different estimates.
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
int getIntParam(const char *param, int arg=0)
void initConstant(T val)
Definition: matrix1d.cpp:83
int * n
double sum() const
void show() const
Definition: mask.cpp:1021
void addParamsLine(const String &line)
MultidimArray< std::complex< double > > fVol