Xmipp  v3.23.11-Nereus
ctf_estimate_psd_with_arma.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Carlos Oscar S. Sorzano (coss@cnb.csic.es)
4  * Javier Angel Velazquez Muriel (javi@cnb.csic.es)
5  *
6  * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21  * 02111-1307 USA
22  *
23  * All comments concerning this program package may be sent to the
24  * e-mail address 'xmipp@cnb.csic.es'
25  ***************************************************************************/
26 
28 
29 #include <core/args.h>
30 #include <core/xmipp_fftw.h>
31 #include <data/filters.h>
32 
33 /* Read parameters from command line --------------------------------------- */
35 {
36  N_AR = program->getIntParam("--N_AR");
37  M_AR = program->getIntParam("--M_AR");
38  N_MA = program->getIntParam("--N_MA");
39  M_MA = program->getIntParam("--M_MA");
40 }
41 
43 {
44  program->addParamsLine("==++ ARMA models");
45  program->addParamsLine(" [--N_AR <N=24>] : N order of the AR model");
46  program->addParamsLine(" [--M_AR <N=24>] : M order of the AR model");
47  program->addParamsLine(" [--N_MA <N=20>] : N order of the MA model");
48  program->addParamsLine(" [--M_MA <N=20>] : M order of the MA model");
49 }
50 
51 // First quadrant neighbours -----------------------------------------------
52 void First_Quadrant_Neighbors(int N, int M, MultidimArray<double> &Neighbors)
53 {
54  long NumberOfPoints = (N + 1) * M;
55  int n;
56  Neighbors.resize(NumberOfPoints, 3);
57 
58  n = 0; // Number of neighbors found so far.
59 
60  for (int p = N; p >= 0; p--)
61  {
62  for (int q = M; q > 0; q--)
63  {
64  A2D_ELEM(Neighbors,n, 0) = (double)p;
65  A2D_ELEM(Neighbors,n, 1) = (double)q;
66  n++;
67  }
68  }
69 }
70 
71 // Second quadrant neighbours ----------------------------------------------
72 void Second_Quadrant_Neighbors(int N, int M, MultidimArray<double> &Neighbors)
73 {
74  long NumberOfPoints = N * (M + 1);
75  int n;
76  Neighbors.resize(NumberOfPoints, 3);
77 
78  n = 0; // Number of neighbors found so far.
79 
80  for (int p = N; p >= 1; p--)
81  {
82  for (int q = 0; q >= -M; q--)
83  {
84  A2D_ELEM(Neighbors,n, 0) = (double)p;
85  A2D_ELEM(Neighbors,n, 1) = (double)q;
86  n++;
87  }
88  }
89 }
90 
91 // Compute ARMA model ------------------------------------------------------
93 {
94  // Calculate the autocorrelation matrix
97  R.setXmippOrigin();
98 
99  /**********************************************************************/
100  // Set equation system for AR part of the model
101  /**********************************************************************/
102  Matrix2D<double> Coeficients;
103  Matrix1D<double> Indep_terms, ARcoeficients;
105 
106  // Assign the support region for the AR part of the model (N1)
108  // Assign the support region for the MA part of the model (N2)
110  // Assign the support region for the AR equations (N3)
111  // Here is the same of N1, but it has not to be
112  First_Quadrant_Neighbors(prm.N_AR, prm.M_AR, N3);
113 
114  long NumberOfARParameters = YSIZE(prm.ARParameters);
115  long NumberOfMAParameters = YSIZE(prm.MAParameters);
116 
117  Coeficients.resizeNoCopy(NumberOfARParameters, NumberOfARParameters);
118  Indep_terms.resizeNoCopy(NumberOfARParameters);
119  ARcoeficients.resizeNoCopy(NumberOfARParameters);
120 
121  // Generate matrix (eq stands for equation number and co for coeficents)
122  for (long eq = 0 ; eq < NumberOfARParameters; eq++)
123  {
124  // take the independet term from the correlation matrix (or calculate it
125  // if it was not calculated before).
126  auto l = (int)A2D_ELEM(N3,eq, 0);
127  auto m = (int)A2D_ELEM(N3,eq, 1);
128  VEC_ELEM(Indep_terms,eq) = A2D_ELEM(R, l, m);
129 
130  // take the coeficients
131  for (long co = 0 ; co < NumberOfARParameters; co++)
132  {
133  // Take the pertinent coeficient form the correlation matrix (or calculate it)
134  auto alpha1 = (int)(A2D_ELEM(N3,eq, 0) - A2D_ELEM(prm.ARParameters,co, 0));
135  auto alpha2 = (int)(A2D_ELEM(N3,eq, 1) - A2D_ELEM(prm.ARParameters,co, 1));
136  auto beta1 = (int)(A2D_ELEM(N3,eq, 0) + A2D_ELEM(prm.ARParameters,co, 0));
137  auto beta2 = (int)(A2D_ELEM(N3,eq, 1) + A2D_ELEM(prm.ARParameters,co, 1));
138  MAT_ELEM(Coeficients,eq, co) = A2D_ELEM(R,alpha1, alpha2) + A2D_ELEM(R,beta1, beta2);
139  }
140  }
141 
142  /**********************************************************************/
143  // Solve the equation system to determine the AR model coeficients and sigma.
144  /**********************************************************************/
145  solveViaCholesky(Coeficients, Indep_terms, ARcoeficients);
146 
147  // Assign the results to the matrix given as parameter
148  for (long n = 0 ; n < NumberOfARParameters; n++)
149  A2D_ELEM(prm.ARParameters, n, 2) = VEC_ELEM(ARcoeficients,n);
150 
151  /**********************************************************************/
152  // Determine the sigma coeficient from the equation for (p,q)=(0,0)
153  /**********************************************************************/
154  double dSum = 0;
155  for (long n = 0 ; n < NumberOfARParameters; n++)
156  {
157  auto p = (int)A2D_ELEM(prm.ARParameters,n, 0);
158  auto q = (int)A2D_ELEM(prm.ARParameters,n, 1);
159  dSum += A2D_ELEM(prm.ARParameters, n, 2) * A2D_ELEM(R, p, q);
160  }
161 
162  // And calculate sigma
163  prm.dSigma = (A2D_ELEM(R, 0, 0) - 2 * dSum);
164  double idSigma = 1.0 / prm.dSigma;
165 
166  /**********************************************************************/
167  // Determine the MA parameters of the model using the AR parameters and
168  // sigma
169  /**********************************************************************/
170  for (long n = 0 ; n < NumberOfMAParameters; n++)
171  {
172  dSum = 0;
173  double MAn0 = A2D_ELEM(prm.MAParameters, n, 0);
174  double MAn1 = A2D_ELEM(prm.MAParameters, n, 1);
175  for (long m = 0 ; m < NumberOfARParameters; m++)
176  {
177  double ARm0 = A2D_ELEM(prm.ARParameters, m, 0);
178  double ARm1 = A2D_ELEM(prm.ARParameters, m, 1);
179  auto alpha1 = (int)(MAn0 - ARm0);
180  auto alpha2 = (int)(MAn1 - ARm1);
181  auto beta1 = (int)(MAn0 + ARm0);
182  auto beta2 = (int)(MAn1 + ARm1);
183  dSum += A2D_ELEM(prm.ARParameters, m, 2) * (
184  A2D_ELEM(R, alpha1, alpha2) + A2D_ELEM(R, beta1, beta2));
185  }
186 
187  auto p = (int)MAn0;
188  auto q = (int)MAn1;
189  A2D_ELEM(prm.MAParameters, n, 2) = (A2D_ELEM(R, p, q) - dSum) * idSigma;
190  }
191 }
192 
193 // Compute the ARMA Filter -------------------------------------------------
196 {
197  bool apply_final_median_filter = false;
198  Matrix1D<double> dDigitalFreq(2);
199 
200  // Resize the Filter to the image dimensions
201  Filter.initZeros(YSIZE(Img), XSIZE(Img));
202 
203  // Compute the filter (only half the values are computed)
204  // The other half is computed based in symmetry.
205  int sizeX = XSIZE(Img);
206  int sizeY = YSIZE(Img);
207  long NumberOfMAParameters = YSIZE(prm.MAParameters);
208  long NumberOfARParameters = YSIZE(prm.ARParameters);
209  MultidimArray<int> iMAParameters(NumberOfMAParameters, 2),
210  iARParameters(NumberOfARParameters, 2);
211  for (long n = 0 ; n < NumberOfMAParameters; n++)
212  {
213  DIRECT_A2D_ELEM(iMAParameters, n, 0) = (int)DIRECT_A2D_ELEM(prm.MAParameters, n, 0);
214  DIRECT_A2D_ELEM(iMAParameters, n, 1) = (int)DIRECT_A2D_ELEM(prm.MAParameters, n, 1);
215  }
216  for (long n = 0 ; n < NumberOfARParameters; n++)
217  {
218  DIRECT_A2D_ELEM(iARParameters, n, 0) = (int)DIRECT_A2D_ELEM(prm.ARParameters, n, 0);
219  DIRECT_A2D_ELEM(iARParameters, n, 1) = (int)DIRECT_A2D_ELEM(prm.ARParameters, n, 1);
220  }
221  for (int i = 0;i < sizeY;i++)
222  for (int j = 0;j < (sizeX / 2);j++)
223  {
224  // Compute dDigitalFreq
225  XX(dDigitalFreq) = j / (double)sizeX;
226  YY(dDigitalFreq) = i / (double)sizeY;
227 
228  // Compute B
229  double B = 0;
230  for (long n = 0 ; n < NumberOfMAParameters; n++)
231  {
232  int p = DIRECT_A2D_ELEM(iMAParameters, n, 0);
233  int q = DIRECT_A2D_ELEM(iMAParameters, n, 1);
234  B += DIRECT_A2D_ELEM(prm.MAParameters, n, 2) * 2 *
235  cos((-2) * PI * (p * YY(dDigitalFreq) + q * XX(dDigitalFreq)));
236  }
237  B = B + 1.0;
238 
239  // Compute A
240  double A = 0;
241  for (long n = 0 ; n < NumberOfARParameters; n++)
242  {
243  int p = DIRECT_A2D_ELEM(iARParameters, n, 0);
244  int q = DIRECT_A2D_ELEM(iARParameters, n, 1);
245  A += DIRECT_A2D_ELEM(prm.ARParameters, n, 2) * 2 *
246  cos((-2) * PI * (p * YY(dDigitalFreq) + q * XX(dDigitalFreq)));
247  }
248  A = 1.0 - A;
249 
250  // Check for posible problems calculating the value of A that could lead
251  // to ARMA filters with erroneous values due to a value of A near 0.
252  if (A < 0)
253  apply_final_median_filter = true;
254 
255  // This is the filter proposed by original paper
256  // As the filter values are symmetrical respect the center (frequency zero),
257  // take advantage of this fact.
258  double val2 = prm.dSigma * B / A;
259  //if (val2>=0) val=sqrt(val2);
260  //else {val=abs(sqrt(std::complex<double>(val2,0)));}
261  A2D_ELEM(Filter,sizeY - 1 - i, sizeX - 1 - j) = A2D_ELEM(Filter,i, j) = fabs(val2);
262  }
263 
264  // Apply final median filter
265  if (apply_final_median_filter)
266  {
268  medianFilter3x3(Filter, aux);
269  // Copy all but the borders
270  for (size_t i = 1; i < YSIZE(Filter) - 1; i++)
271  for (size_t j = 1; j < XSIZE(Filter) - 1; j++)
272  DIRECT_A2D_ELEM(Filter, i, j) = DIRECT_A2D_ELEM(aux, i, j);
273  }
274 }
#define YSIZE(v)
MultidimArray< double > MAParameters
#define A2D_ELEM(v, i, j)
#define VEC_ELEM(v, i)
Definition: matrix1d.h:245
void resize(size_t Ndim, size_t Zdim, size_t Ydim, size_t Xdim, bool copy=true)
void Second_Quadrant_Neighbors(int N, int M, MultidimArray< double > &Neighbors)
void First_Quadrant_Neighbors(int N, int M, MultidimArray< double > &Neighbors)
#define DIRECT_A2D_ELEM(v, i, j)
void auto_correlation_matrix(const MultidimArray< double > &Img, MultidimArray< double > &R, CorrelationAux &aux)
Definition: xmipp_fftw.cpp:957
#define i
void resizeNoCopy(int Ydim, int Xdim)
Definition: matrix2d.h:534
MultidimArray< double > ARParameters
#define MAT_ELEM(m, i, j)
Definition: matrix2d.h:116
#define XX(v)
Definition: matrix1d.h:85
void CausalARMA(MultidimArray< double > &Img, ARMA_parameters &prm)
#define XSIZE(v)
void eq(Image< double > &op1, const Image< double > &op2)
Be careful with integer images for relational operations...due to double comparisons.
#define j
#define YY(v)
Definition: matrix1d.h:93
int m
void ARMAFilter(MultidimArray< double > &Img, MultidimArray< double > &Filter, ARMA_parameters &prm)
void medianFilter3x3(MultidimArray< T > &m, MultidimArray< T > &out)
Definition: filters.h:1088
void readParams(XmippProgram *program)
Read parameters from command line.
static void defineParams(XmippProgram *program)
Define parameters.
void resizeNoCopy(int Xdim)
Definition: matrix1d.h:458
ProgClassifyCL2D * prm
void initZeros(const MultidimArray< T1 > &op)
void solveViaCholesky(const Matrix2D< double > &A, const Matrix1D< double > &b, Matrix1D< double > &result)
#define PI
Definition: tools.h:43
int getIntParam(const char *param, int arg=0)
int * n
void addParamsLine(const String &line)