Xmipp  v3.23.11-Nereus
movie_estimate_gain.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Victoria Peredo
4  * Estrella Fernandez
5  * Carlos Oscar S. Sorzano (coss@cnb.csic.es)
6  *
7  * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22  * 02111-1307 USA
23  *
24  * All comments concerning this program package may be sent to the
25  * e-mail address 'xmipp@cnb.csic.es'
26  ***************************************************************************/
27 
28 #include <algorithm>
29 #include "movie_estimate_gain.h"
31 
33 {
34  addUsageLine("Estimate the gain image for a movie");
35  addParamsLine(" -i <movie>: Input movie");
36  addParamsLine(" [--oroot <fn=\"estimated\">]: Estimated corrections and gains");
37  addParamsLine(" :+(Ideal=Observed*Corr, Observed=Ideal*Gain)");
38  addParamsLine(" [--iter <N=3>]: Number of iterations");
39  addParamsLine(" [--sigma <s=-1>]: Sigma to use, if negative, then it is searched");
40  addParamsLine(" [--maxSigma <s=3>]: Maximum number of neighbour rows/columns to analyze");
41  addParamsLine(" [--frameStep <s=1>]: Skip frames during the estimation");
42  addParamsLine(" : Set to 1 to process all frames, set to 2 to process 1 every 2 frames, ...");
43  addParamsLine(" [--sigmaStep <s=0.5>]: Step size for sigma");
44  addParamsLine(" [--singleRef] : Use a single histogram reference");
45  addParamsLine(" :+This assumes that there is no image contamination or carbon holes");
46  addParamsLine(" [--gainImage <fn=\"\">] : Reference to external gain image (we will divide by it)");
47  addParamsLine(" [--applyGain <fnOut>] : Flag for using external gain image");
48  addParamsLine(" : applyGain=True will use external gain image");
49 }
50 
52 {
53  fnIn=getParam("-i");
54  fnRoot=getParam("--oroot");
55  Niter=getIntParam("--iter");
56  sigma=getIntParam("--sigma");
57  maxSigma=getDoubleParam("--maxSigma");
58  sigmaStep=getDoubleParam("--sigmaStep");
59  singleReference=checkParam("--singleRef");
60  frameStep=getIntParam("--frameStep");
61  fnGain=getParam("--gainImage");
62  applyGain=checkParam("--applyGain");
63  if (applyGain)
64  fnCorrected=getParam("--applyGain");
65 }
66 
68 {
69  if (fnIn.getExtension()=="mrc")
70  fnIn+=":mrcs";
71  mdIn.read(fnIn);
73  if (mdIn.size()==0)
74  exit(0);
75  Image<double> Iframe;
76  FileName fnFrame;
78  Iframe.read(fnFrame);
79  Xdim=XSIZE(Iframe());
80  Ydim=YSIZE(Iframe());
81 
84  if (fnGain!="")
85  {
86  IGain.read(fnGain);
87  if (YSIZE(IGain())!=Ydim || XSIZE(IGain())!=Xdim)
88  REPORT_ERROR(ERR_MULTIDIM_SIZE,"The gain image and the movie do not have the same dimensions");
89  }
90  else
91  {
92  IGain().resizeNoCopy(Ydim,Xdim);
93  IGain().initConstant(1);
94  }
95 
97 
98  int iFrame=0;
99  for (size_t objId : mdIn.ids())
100  {
101  if (iFrame%frameStep==0)
102  {
103  mdIn.getValue(MDL_IMAGE,fnFrame,objId);
104  Iframe.read(fnFrame);
105  MultidimArray<double> mIframe=Iframe();
106  MultidimArray<double> mIGain=IGain();
108  DIRECT_MULTIDIM_ELEM(mIframe,n) /= DIRECT_MULTIDIM_ELEM(mIGain,n); sumObs+=Iframe();
109  }
110  iFrame++;
111  }
112  sumObs*=2;
113 
114  // Initialize sigma values
115  const auto numIterations = static_cast<size_t>(maxSigma / sigmaStep);
116  listOfSigmas.reserve(numIterations);
117  for (size_t i=0; i<=numIterations; ++i)
118  listOfSigmas.push_back(i*sigmaStep);
119 
120  for (size_t i=0; i<listOfSigmas.size(); ++i)
121  {
122  int jmax=ceil(3*listOfSigmas[i]);
123  listOfWidths.push_back(jmax);
124  auto *weights=new double[jmax+1];
125  double K=1;
126  if (listOfSigmas[i]>0)
127  K=-0.5/(listOfSigmas[i]*listOfSigmas[i]);
128  for (int j=0; j<=jmax; ++j)
129  weights[j]=exp(K*j*j);
130  listOfWeights.push_back(weights);
131  }
132 }
133 
135 {
136  if (verbose==0)
137  return;
138  std::cout
139  << "Input movie: " << fnIn << std::endl
140  << "Output rootname: " << fnRoot << std::endl
141  << "N. Iterations: " << Niter << std::endl
142  << "Sigma: " << sigma << std::endl
143  << "Max. Sigma: " << maxSigma << std::endl
144  << "Sigma step: " << sigmaStep << std::endl
145  << "Single ref: " << singleReference << std::endl
146  << "Frame step: " << frameStep << std::endl
147  << "Ext. gain image: " << fnGain << std::endl
148  << "Apply ext. gain: " << applyGain << std::endl
149  ;
150 }
151 
152 
154 {
155  produceSideInfo();
156 
157  FileName fnFrame;
158  Image<double> Iframe;
159  MultidimArray<double> IframeTransformed, IframeIdeal;
160  MultidimArray<double> sumIdeal;
161  MultidimArray<double> &mIGain=IGain();
162 
163  if (applyGain)
164  {
165  int idx=1;
167  for (size_t objId : mdIn.ids())
168  {
169  mdIn.getValue(MDL_IMAGE,fnFrame,objId);
170  Iframe.read(fnFrame);
171  MultidimArray<double> &mIframe = Iframe();
173  DIRECT_MULTIDIM_ELEM(mIframe,n) /= DIRECT_MULTIDIM_ELEM(mIGain,n);
174  //Iframe.write(formatString("%i@%s"%(idx,fnCorrected)));
175  Iframe.write(fnCorrected, idx, WRITE_REPLACE);
176  idx++;
177  }
178  }else{
179  for (int n=0; n<Niter; n++)
180  {
181  std::cout << "Iteration " << n << std::endl;
182  sumIdeal.initZeros(Ydim,Xdim);
183  int iFrame=0;
184  for (size_t objId : mdIn.ids())
185  {
186  if (iFrame%frameStep==0)
187  {
188  mdIn.getValue(MDL_IMAGE,fnFrame,objId);
189  std::cout << " Frame " << fnFrame << std::endl;
190  Iframe.read(fnFrame);
191  IframeIdeal = Iframe();
193  DIRECT_A2D_ELEM(IframeIdeal,i,j)/=DIRECT_A2D_ELEM(mIGain,i,j);
194  computeHistograms(IframeIdeal);
195 
196  //sigma=0;
197  size_t bestSigmaCol = 0;
198  if (sigma>=0)
199  {
200  double bestDistance=1e38;
201  for (size_t s = 0; s< listOfWeights.size(); ++s)
202  if (fabs(listOfSigmas[s]-sigma)<bestDistance)
203  {
204  bestDistance=fabs(listOfSigmas[s]-sigma);
205  bestSigmaCol=s;
206  }
207  }
208  else
209  selectBestSigmaByColumn(IframeIdeal);
210  std::cout << " sigmaCol: " << listOfSigmas[bestSigmaCol] << std::endl;
211  size_t bestSigmaRow = 0;
212 
213  if (sigma>=0)
214  {
215  double bestDistance=1e38;
216  for (size_t s = 0; s< listOfWeights.size(); ++s)
217  if (fabs(listOfSigmas[s]-sigma)<bestDistance)
218  {
219  bestDistance=fabs(listOfSigmas[s]-sigma);
220  bestSigmaRow=s;
221  }
222  }
223  else
224  selectBestSigmaByRow(IframeIdeal);
225  std::cout << " sigmaRow: " << listOfSigmas[bestSigmaRow] << std::endl;
226 
227  constructSmoothHistogramsByRow(listOfWeights[bestSigmaRow],listOfWidths[bestSigmaRow]);
228  transformGrayValuesRow(IframeIdeal,IframeTransformed);
229  FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(IframeTransformed)
230  DIRECT_A2D_ELEM(sumIdeal,i,j)+=DIRECT_A2D_ELEM(IframeTransformed,i,j);
231  constructSmoothHistogramsByColumn(listOfWeights[bestSigmaCol],listOfWidths[bestSigmaCol]);
232  transformGrayValuesColumn(IframeIdeal,IframeTransformed);
233  FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(IframeTransformed)
234  DIRECT_A2D_ELEM(sumIdeal,i,j)+=DIRECT_A2D_ELEM(IframeTransformed,i,j);
235  }
236  iFrame++;
237  }
238 
240  {
241  double den=DIRECT_A2D_ELEM(sumObs,i,j);
242  if (fabs(den)<1e-6)
243  DIRECT_A2D_ELEM(mIGain,i,j)=1.0;
244  else
245  DIRECT_A2D_ELEM(mIGain,i,j)=DIRECT_A2D_ELEM(sumIdeal,i,j)/den;
246  }
247  mIGain/=mIGain.computeAvg();
248 
249  #ifdef NEVER_DEFINED
250  IGain.write(fnCorr);
251  Image<double> save;
252  typeCast(sumIdeal,save());
253  save.write("PPPSumIdeal.xmp");
254  typeCast(sumObs,save());
255  save.write("PPPSumObs.xmp");
256  //std::cout << "Press any key\n";
257  //char c; std::cin >> c;
258  #endif
259  }
260  }
261  IGain.write(fnRoot+"_gain.xmp");
262 }
263 
265 {
266  auto* auxElemC=new double[Ydim];
267  auto* auxElemR=new double[Xdim];
268 
269  for(size_t j=0; j<XSIZE(columnH); j++)
270  {
271  for(size_t i=0; i<Ydim; i++)
272  auxElemC[i]=A2D_ELEM(Iframe,i,j);
273  std::sort(auxElemC, auxElemC+Ydim);
274  for(size_t i=0; i<Ydim; i++)
275  A2D_ELEM(columnH,i,j)=auxElemC[i];
276  }
277  delete[] auxElemC;
278 
279  for(size_t i=0; i<YSIZE(rowH); i++)
280  {
281  memcpy(auxElemR,&A2D_ELEM(Iframe,i,0),Xdim*sizeof(double));
282  std::sort(auxElemR, auxElemR+Xdim);
283  memcpy(&A2D_ELEM(rowH,i,0),auxElemR,Xdim*sizeof(double));
284  }
285  delete[] auxElemR;
286 
287 
288 #ifdef NEVER_DEFINED
289  Image<double> save;
290  typeCast(columnH,save());
291  save.write("PPPcolumnH.xmp");
292  typeCast(rowH,save());
293  save.write("PPProwH.xmp");
294 #endif
295 }
296 
298 {
299 
301 
302  for (size_t j=0; j<XSIZE(columnH); ++j)
303  {
304  double sumWeightsC = 0;
305  for(int k = -width; k<=width; ++k)
306  {
307  if (j+k<0 || j+k>=XSIZE(columnH))
308  continue;
309  double actualWeightC = listOfWeights[abs(k)];
310  sumWeightsC += actualWeightC;
311  for (size_t i=0; i<Ydim; ++i)
312  DIRECT_A2D_ELEM(smoothColumnH,i,j) += actualWeightC * DIRECT_A2D_ELEM(columnH,i,j+k);
313  }
314 
315  double iSumWeightsC=1/sumWeightsC;
316  for (size_t i=0; i<Ydim; ++i)
317  DIRECT_A2D_ELEM(smoothColumnH,i,j) *= iSumWeightsC;
318  }
319 
320  if (singleReference)
321  {
322  // Compute the average of all column histograms
323  for (size_t i=0; i<Ydim; ++i)
324  for (size_t j=1; j<Xdim; ++j)
326 
327  double iXdim=1.0/Xdim;
328  for (size_t i=0; i<Ydim; ++i)
329  {
330  DIRECT_A2D_ELEM(smoothColumnH,i,0)*=iXdim;
331  double aux=DIRECT_A2D_ELEM(smoothColumnH,i,0);
332  for (size_t j=1; j<Xdim; ++j)
334  }
335  }
336 #ifdef NEVER_DEFINED
337  Image<double> save;
338  typeCast(smoothColumnH,save());
339  save.write("PPPsmoothColumnH.xmp");
340 #endif
341 }
342 
344 {
346  for(size_t i = 0; i<YSIZE(rowH); ++i)
347  {
348  double sumWeightsR = 0;
349  for(int k = -width; k<=width; ++k)
350  {
351  if (i+k<0 || i+k>=YSIZE(rowH))
352  continue;
353  double actualWeightR = listOfWeights[abs(k)];
354  sumWeightsR += actualWeightR;
355  for (size_t j=0; j< Xdim; ++j)
356  DIRECT_A2D_ELEM(smoothRowH,i,j) += actualWeightR * DIRECT_A2D_ELEM(rowH,i+k,j);
357  }
358  double iSumWeightsR=1/sumWeightsR;
359  for (size_t j=0; j<Xdim; ++j)
360  DIRECT_A2D_ELEM(smoothRowH,i,j) *= iSumWeightsR;
361  }
362 
363  if (singleReference)
364  {
365  // Compute the average of all row histograms
366  for (size_t j=0; j<Xdim; ++j)
367  for (size_t i=1; i<Ydim; ++i)
369 
370  double iYdim=1.0/Ydim;
371  for (size_t j=0; j<Xdim; ++j)
372  {
373  DIRECT_A2D_ELEM(smoothRowH,0,j)*=iYdim;
374  double aux=DIRECT_A2D_ELEM(smoothRowH,0,j);
375  for (size_t i=1; i<Ydim; ++i)
377  }
378  }
379 
380 #ifdef NEVER_DEFINED
381  Image<double> save;
382  typeCast(smoothRowH,save());
383  save.write("PPPsmoothRowH.xmp");
384 #endif
385 }
386 #undef NEVER_DEFINED
387 
389 {
390  IframeTransformedColumn.initZeros(Ydim,Xdim);
392  double *aSingleColumnH0=&DIRECT_A1D_ELEM(aSingleColumnH,0);
393  double *aSingleColumnHF=(&DIRECT_A1D_ELEM(aSingleColumnH,Ydim-1))+1;
394 
395 
396  for (size_t j=0; j<Xdim; ++j)
397  {
398  for (size_t i=0; i<Ydim; ++i)
400 
401  for (size_t i=0; i<Ydim; ++i)
402  {
403  double pixval=DIRECT_A2D_ELEM(Iframe,i,j);
404  double *pixvalPtr=std::upper_bound(aSingleColumnH0,aSingleColumnHF,pixval);
405  pixvalPtr-=1;
406  int idx=pixvalPtr-aSingleColumnH0;
407  DIRECT_A2D_ELEM(IframeTransformedColumn,i,j)+=(double)DIRECT_A2D_ELEM(smoothColumnH,idx,j);
408  }
409  }
410 
411 
412 #ifdef NEVER_DEFINED
413  Image<double> save;
414  typeCast(IframeTransformedColumn,save());
415  save.write("PPPIframeTransformedColumn.xmp");
416  typeCast(Iframe,save());
417  save.write("PPPIframe.xmp");
418  std::cout << "Press any key to continue\n";
419  char c; std::cin >> c;
420 #endif
421 }
422 
423 
425 {
426  IframeTransformedRow.initZeros(Ydim,Xdim);
428  double *aSingleRowH0=&DIRECT_A1D_ELEM(aSingleRowH,0);
429  double *aSingleRowHF=(&DIRECT_A1D_ELEM(aSingleRowH,Xdim-1))+1;
430 
431  for (size_t i=0; i<Ydim; ++i)
432  {
433  memcpy(aSingleRowH0,&DIRECT_A2D_ELEM(rowH,i,0),Xdim*sizeof(double));
434 
435  for (size_t j=0; j<Xdim; ++j)
436  {
437  double pixvalR=DIRECT_A2D_ELEM(Iframe,i,j);
438  double *pixvalPtrR=std::upper_bound(aSingleRowH0,aSingleRowHF,pixvalR);
439  pixvalPtrR-=1;
440  int idxR=pixvalPtrR-aSingleRowH0;
441  DIRECT_A2D_ELEM(IframeTransformedRow,i,j)+=(double)DIRECT_A2D_ELEM(smoothRowH,i,idxR);
442  }
443  }
444 
445 #ifdef NEVER_DEFINED
446  Image<double> save;
447  typeCast(IframeTransformedRow,save());
448  save.write("PPPIframeTransformedRow.xmp");
449  typeCast(Iframe,save());
450  save.write("PPPIframe.xmp");
451  std::cout << "Press any key to continue\n";
452  char c; std::cin >> c;
453 #endif
454 
455 }
456 
458 {
459  double retvalC=0;
460  for (size_t i=0; i<YSIZE(I); ++i)
461  for (size_t j=0; j<XSIZE(I)-1; ++j)
462  retvalC+=std::abs(DIRECT_A2D_ELEM(I,i,j)-DIRECT_A2D_ELEM(I,i,j+1));
463 
464  return retvalC/((XSIZE(I)-1)*YSIZE(I));
465 }
466 
468 {
469  double retvalR=0;
470  for (size_t i=0; i<YSIZE(I)-1; ++i)
471  for (size_t j=0; j<XSIZE(I); ++j)
472  retvalR+=std::abs(DIRECT_A2D_ELEM(I,i,j)-DIRECT_A2D_ELEM(I,i+1,j));
473 
474  return retvalR/((YSIZE(I)-1)*XSIZE(I));
475 }
476 
478 {
479  double bestAvgTV=1e38;
480  size_t best_s=0;
481  MultidimArray<double> IframeTransformed;
482 
483  for(size_t s = 0; s< listOfWeights.size(); ++s)
484  {
486  transformGrayValuesColumn(Iframe,IframeTransformed);
487  double avgTV=computeTVColumns(IframeTransformed);
488  if (avgTV<bestAvgTV)
489  {
490  bestAvgTV=avgTV;
491  best_s=s;
492  }
493  }
494  return best_s;
495 }
496 
498 {
499  double bestAvgTV=1e38;
500  size_t best_s=0;
501  MultidimArray<double> IframeTransformed;
502 
503  for(size_t s = 0; s< listOfWeights.size(); ++s)
504  {
506  transformGrayValuesRow(Iframe,IframeTransformed);
507  double avgTV=computeTVRows(IframeTransformed);
508  if (avgTV<bestAvgTV)
509  {
510  bestAvgTV=avgTV;
511  best_s=s;
512  }
513  }
514 
515  return best_s;
516 }
MultidimArray< double > rowH
#define YSIZE(v)
size_t selectBestSigmaByRow(const MultidimArray< double > &Iframe)
#define A2D_ELEM(v, i, j)
std::vector< double > listOfSigmas
std::vector< double * > listOfWeights
double getDoubleParam(const char *param, int arg=0)
void read(const FileName &inFile, const std::vector< MDLabel > *desiredLabels=nullptr, bool decomposeStack=true) override
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
#define FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(m)
doublereal * c
void resizeNoCopy(const MultidimArray< T1 > &v)
void constructSmoothHistogramsByColumn(const double *listOfWeights, int width)
#define DIRECT_A2D_ELEM(v, i, j)
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)
void computeHistograms(const MultidimArray< double > &Iframe)
void abs(Image< double > &op)
Incorrect MultidimArray size.
Definition: xmipp_error.h:174
virtual IdIteratorProxy< false > ids()
size_t size() const override
#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
MultidimArray< double > sumObs
MultidimArray< double > columnH
double computeTVColumns(MultidimArray< double > &I)
String getExtension() const
#define DIRECT_A1D_ELEM(v, i)
const char * getParam(const char *param, int arg=0)
MultidimArray< double > smoothRowH
size_t firstRowId() const override
#define XSIZE(v)
#define FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(v)
void transformGrayValuesRow(const MultidimArray< double > &Iframe, MultidimArray< double > &IframeTransformedRow)
#define DIRECT_MULTIDIM_ELEM(v, n)
void createEmptyFile(const FileName &filename, int xdim, int ydim, int Zdim, size_t select_img, bool isStack, int mode, int _swapWrite, const MDRowVec *md)
int verbose
Verbosity level.
void sort(struct DCEL_T *dcel)
Definition: sorting.cpp:18
#define j
MultidimArray< double > smoothColumnH
bool getValue(MDObject &mdValueOut, size_t id) const override
void transformGrayValuesColumn(const MultidimArray< double > &Iframe, MultidimArray< double > &IframeTransformedColumn)
MultidimArray< double > aSingleRowH
std::vector< double > listOfWidths
MultidimArray< double > aSingleColumnH
virtual void removeDisabled()
void typeCast(const Matrix1D< T1 > &v1, Matrix1D< T2 > &v2)
Definition: matrix1d.h:1227
void constructSmoothHistogramsByRow(const double *listOfWeights, int width)
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
void addUsageLine(const char *line, bool verbatim=false)
void initZeros(const MultidimArray< T1 > &op)
double computeAvg() const
double computeTVRows(MultidimArray< double > &I)
int getIntParam(const char *param, int arg=0)
int * n
Name of an image (std::string)
void addParamsLine(const String &line)
size_t selectBestSigmaByColumn(const MultidimArray< double > &Iframe)