Xmipp  v3.23.11-Nereus
adjust_volume_grey_levels.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Carlos Oscar S. Sorzano (coss@cnb.csic.es)
4  *
5  * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20  * 02111-1307 USA
21  *
22  * All comments concerning this program package may be sent to the
23  * e-mail address 'xmipp@cnb.csic.es'
24  ***************************************************************************/
25 
27 #include "data/numerical_tools.h"
28 #include "data/projection.h"
30 
32 {
33  // Usage
34  addUsageLine("Search for a linear transformation of the gray values of a volume so that the");
35  addUsageLine("error between the theoretically projected images and the experimental images");
36  addUsageLine("is minimized. This program must be used before computing the Volumetric SSNR");
37  addUsageLine("if the reconstruction algorithm scales the output volume differently.");
38  // See also
39 
40  // Examples
41  addExampleLine("Adjust a volume to a set of images:", false);
42  addExampleLine("xmipp_adjust_volume_grey_levels -i input_volume.vol -m experimental.sel -o output_volume.vol ");
43 
44  // Parameters
45  addParamsLine(" -i <volume_file> : Volume to adjust its range.");
46  addParamsLine(" alias --input;");
47  addParamsLine(" -m <metadata_file> : Set of projections of the volume.");
48  addParamsLine(" alias --metadata;");
49  addParamsLine(" [-o <volume_file=\"\">] : Output adjusted volume. By default, the input one.");
50  addParamsLine(" alias --output;");
51  addParamsLine(" [--optimize] : Optimize the linear transformation. By default, keep the initially computed.");
52  addParamsLine(" [--probb_eval <p=0.2>] : The goal function is evaluated each time from a random set of projections.");
53  addParamsLine(" : Each image has a probability of p of being evaluated.");
54 }
55 
57 {
58  fn_vol = getParam("-i");
59  fn_sel = getParam("-m");
60  fn_out = (checkParam("-o"))? getParam("-o") : fn_vol;
61  optimize = checkParam("--optimize");
62  probb_eval = getDoubleParam("--probb_eval");
63  verbose = (checkParam("-v"))? getIntParam("-v"): false;
64  tempFile = (STR_EQUAL(fn_vol.c_str(), fn_out.c_str()));
65 }
66 
68 {
69  if (verbose)
70  show();
71 
72  // Read input volume
73  ImIn.read(fn_vol);
74  V.alias(ImIn());
75  V.setXmippOrigin();
76 
77  int Xdim, Ydim, Zdim;
78  Xdim = XSIZE(V);
79  Ydim = YSIZE(V);
80  Zdim = ZSIZE(V);
81 
82  Image<float> ImOut;
83  ImOut.mapFile2Write(Xdim, Ydim, Zdim, fn_out, tempFile);
84  ImOut().setXmippOrigin();
85 
86  // Read input metadataFile
87  SF.read(fn_sel,nullptr);
88 
89  apply(ImOut());
90 
91  ImIn.clear();
92  ImOut.write();
93 }
94 
95 /* Goal function ----------------------------------------------------------- */
97 double projectionMismatching(double *p, void *prm)
98 {
99  return globalAdjustVolumeProg->mismatching(p[1], p[2]);
100 }
101 
102 //#define DEBUG
103 double ProgAdjustVolume::mismatching(double a, double b)
104 {
105  if (a <= 0)
106  return 1e38;
107 
108  // Transform the volume
109  MultidimArray<double> aux = V;
110  FOR_ALL_ELEMENTS_IN_ARRAY3D(aux) aux(k, i, j) = a * aux(k, i, j) + b;
111 
112  // Compute the mismatching
113  double retval = 0;
114  //SF.go_first_ACTIVE();
115  int N = 0;
116  //while (!SF.eof())
117  if(SF.isEmpty())
118  {
119  std::cerr << "Empty inputFile File\n";
120  exit(1);
121  }
122  Image<double> I;
123  ApplyGeoParams params;
124  params.only_apply_shifts=true;
125  for (size_t objId : SF.ids())
126  {
127  // Skip randomly some images
128  double x = rnd_unif(0, 1);
129  if (x > probb_eval)
130  continue;
131  N++;
132 
133  I.readApplyGeo(SF, objId, params);
134  I().setXmippOrigin();
135 
136  // Project the auxiliary volume in the same direction
137  Projection P;
138  projectVolume(aux, P, YSIZE(I()), XSIZE(I()),
139  I.rot(), I.tilt(), I.psi());
140 
141  // Compute the difference
143  diff = I() - P();
144  retval += diff.sum2();
145 
146 #ifdef DEBUG
147 
148  I.write("PPPexp.xmp");
149  I() = P();
150  I.write("PPPtheo.xmp");
151  std::cout << "Difference=" << diff.sum2() << std::endl;
152  std::cout << "Press any key\n";
153  char c;
154  std::cin >> c;
155 #endif
156 
157  }
158  //TODO Review this
159  // while (SF.nextObject()!= NO_MORE_OBJECTS)
160  // ;
161  if (0 == N) {
162  REPORT_ERROR(ERR_NUMERICAL, "N is zero (0), which would lead to division by zero");
163  }
164  return retval / N;
165 }
166 #undef DEBUG
167 
168 /* Apply ------------------------------------------------------------------- */
170 {
171  // Compute the average power and average value of all the projections
172  double sum = 0, sum2 = 0, N = 0;
173  std::cerr << "Computing first estimate of the linear transformation ...\n";
174  int imgno = SF.size();
175  init_progress_bar(imgno);
176  int i = 0;
177 
178  int projXdim, projYdim;
179  if(SF.isEmpty())
180  {
181  std::cerr << "Empty inputFile File\n";
182  exit(1);
183  }
184  Image<double> I;
185  for (size_t objId : SF.ids())
186  {
187  // Read image
188  I.readApplyGeo(SF, objId);
189  projXdim = XSIZE(I());
190  projYdim = YSIZE(I());
191 
192  // Compute the image statistics
193  double avg=0., stddev=0., min, max;
194  I().computeStats(avg, stddev, min, max);
195  double Ni = projXdim * projYdim;
196  sum += avg;
197  sum2 += stddev * stddev;
198  N += Ni;
199 
200  // End of loop
201  i++;
202  if (i % 10 == 0)
203  progress_bar(i);
204  }
205  progress_bar(imgno);
206  std::cout << std::endl;
207 
208  // Statistics of the volume
209  double avg0=0., stddev0=0., min0, max0;
210  V.computeStats(avg0, stddev0, min0, max0);
211 
212  // First guess of the transformation parameters a*(x-vm)+b
213  // r is the average length of a ray
214  // The equations to solve are
215  // v_i follows currently N(avg0,stddev0)
216  // we want it to follow N(avgF,stddevF)
217  // such that sum_{i=1}^r{v_i} follows N(avg_pict,stddev_pict)
218  // On the other hand we know that
219  // sum_{i=1}^r{v_i} follows N(r avgF, sqrt(r)*stddevF)
220  // Thus,
221  // avgF=avg_pict/r
222  // stddevF=stddev_pict/sqrt(r)
223  // the equations of the transformation are
224  // y=ax+b
225  // avg_y =a*avg_x+b=avgF
226  // stddev_y =a*stddev_y=stddevF
227  // Therefore
228  // a=stddevF/stddev0
229  // b=avgF-a*avg0
230  double r = pow(MULTIDIM_SIZE(V), 1.0 / 3.0);
231  double avg_pict = sum / imgno;
232  double stddev_pict = sqrt(sum2 / imgno);
233  double avgF = avg_pict / r;
234  double stddevF = stddev_pict / sqrt(r);
235  double a = stddevF / stddev0;
236  double b = avgF - a * avg0;
237  std::cout << "First Linear transformation: y=" << a << "*x+" << b << std::endl;
238 
239  // Optimize
240  if (optimize)
241  {
242  Matrix1D<double> p(2), steps(2);
243  p(0) = a;
244  p(1) = b;
245  steps.initConstant(1);
246  double ftol = 0.01, fret;
247  int iter;
248  globalAdjustVolumeProg = this;
249  powellOptimizer(p, 1, 2, &projectionMismatching, nullptr,
250  ftol, fret, iter, steps, true);
251  a = p(0);
252  b = p(1);
253  }
254 
255  // Apply the transformation
256 // out = V;
257  FOR_ALL_ELEMENTS_IN_ARRAY3D(V) out(k, i, j) = a * V(k, i, j) + b;
258 }
259 
260 /* Show -------------------------------------------------------------------- */
262 {
263  std::cout << "Input Volume: " << fn_vol << std::endl
264  << "Input MetaDAtaFile: " << fn_sel << std::endl
265  << "Output Volume: " << fn_out << std::endl
266  << "Optimize: " << optimize << std::endl;
267 }
268 
void init_progress_bar(long total)
ProgAdjustVolume * globalAdjustVolumeProg
#define YSIZE(v)
void min(Image< double > &op1, const Image< double > &op2)
double mismatching(double a, double b)
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
double psi(const size_t n=0) const
doublereal * c
#define MULTIDIM_SIZE(v)
void sqrt(Image< double > &op)
MultidimArray< double > V
void computeStats(double &avg, double &stddev, T &minval, T &maxval) const
double probb_eval
Probability of being evaluated.
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 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)
double rot(const size_t n=0) const
glob_prnt iter
virtual IdIteratorProxy< false > ids()
doublereal * x
int readApplyGeo(const FileName &name, const MDRow &row, const ApplyGeoParams &params=DefaultApplyGeoParams)
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
double tilt(const size_t n=0) const
double rnd_unif()
bool isEmpty() const override
#define FOR_ALL_ELEMENTS_IN_ARRAY3D(V)
doublereal * b
const char * getParam(const char *param, int arg=0)
#define XSIZE(v)
void progress_bar(long rlen)
void max(Image< double > &op1, const Image< double > &op2)
Error related to numerical calculation.
Definition: xmipp_error.h:179
#define ZSIZE(v)
void addExampleLine(const char *example, bool verbatim=true)
void projectVolume(FourierProjector &projector, Projection &P, int Ydim, int Xdim, double rot, double tilt, double psi, const MultidimArray< double > *ctf)
int verbose
Verbosity level.
void alias(const MultidimArray< T > &m)
#define STR_EQUAL(str1, str2)
Definition: xmipp_strings.h:42
#define j
double steps
FileName fn_sel
Filename with the input projections.
void apply(MultidimArray< float > &output_volume)
double projectionMismatching(double *p, void *prm)
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)
ProgClassifyCL2D * prm
void addUsageLine(const char *line, bool verbatim=false)
int getIntParam(const char *param, int arg=0)
void mapFile2Write(size_t Xdim, size_t Ydim, size_t Zdim, const FileName &_filename, bool createTempFile=false, size_t select_img=APPEND_IMAGE, bool isStack=false, int mode=WRITE_OVERWRITE)
void initConstant(T val)
Definition: matrix1d.cpp:83
doublereal * a
void clear()
Definition: xmipp_image.h:144
void addParamsLine(const String &line)
FileName fn_vol
Filename with the input volume.