Xmipp  v3.23.11-Nereus
fourier_projection.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 
26 #include "fourier_projection.h"
27 #include "core/bilib/kernel.h"
28 #include "core/geometry.h"
29 #include "core/transformations.h"
30 #include "core/xmipp_fftw.h"
31 
32 /* Reset =================================================================== */
33 void Projection::reset(int Ydim, int Xdim)
34 {
35  data.initZeros(Ydim, Xdim);
37 }
38 
39 /* Set angles ============================================================== */
40 void Projection::setAngles(double _rot, double _tilt, double _psi)
41 {
42  setEulerAngles(_rot, _tilt, _psi);
43  Euler_angles2matrix(_rot, _tilt, _psi, euler);
47 }
48 
49 /* Read ==================================================================== */
50 void Projection::read(const FileName &fn, const bool only_apply_shifts,
51  DataMode datamode , MDRow * row)
52 {
53  Image<double>::read(fn, datamode);
54  if (row != nullptr)
55  applyGeo(*row, only_apply_shifts);
60 }
61 
62 /* Another function for assignment ========================================= */
64 {
65  *this = P;
66 }
67 
68 FourierProjector::FourierProjector(double paddFactor, double maxFreq, int degree)
69 {
70  paddingFactor = paddFactor;
71  maxFrequency = maxFreq;
72  BSplineDeg = degree;
73  volume = nullptr;
74 }
75 
76 FourierProjector::FourierProjector(MultidimArray<double> &V, double paddFactor, double maxFreq, int degree)
77 {
78  paddingFactor = paddFactor;
79  maxFrequency = maxFreq;
80  BSplineDeg = degree;
81  updateVolume(V);
82 }
83 
85 {
86  volume = &V;
87  volumeSize=XSIZE(*volume);
88  produceSideInfo();
89 }
90 
91 void FourierProjector::project(double rot, double tilt, double psi, const MultidimArray<double> *ctf)
92 {
93  double freqy;
94  double freqx;
95  std::complex< double > f;
96  Euler_angles2matrix(rot,tilt,psi,E);
97  projectionFourier.initZeros();
98  double maxFreq2=maxFrequency*maxFrequency;
99  auto Xdim=(int)XSIZE(VfourierRealCoefs);
100  auto Ydim=(int)YSIZE(VfourierRealCoefs);
101  auto Zdim=(int)ZSIZE(VfourierRealCoefs);
102 
103  for (size_t i=0; i<YSIZE(projectionFourier); ++i)
104  {
105  FFT_IDX2DIGFREQ(i,volumeSize,freqy);
106  double freqy2=freqy*freqy;
107 
108  double freqYvol_X=MAT_ELEM(E,1,0)*freqy;
109  double freqYvol_Y=MAT_ELEM(E,1,1)*freqy;
110  double freqYvol_Z=MAT_ELEM(E,1,2)*freqy;
111  for (size_t j=0; j<XSIZE(projectionFourier); ++j)
112  {
113  // The frequency of pairs (i,j) in 2D
114  FFT_IDX2DIGFREQ(j,volumeSize,freqx);
115 
116  // Do not consider pixels with high frequency
117  if ((freqy2+freqx*freqx)>maxFreq2)
118  continue;
119 
120  // Compute corresponding frequency in the volume
121  double freqvol_X=freqYvol_X+MAT_ELEM(E,0,0)*freqx;
122  double freqvol_Y=freqYvol_Y+MAT_ELEM(E,0,1)*freqx;
123  double freqvol_Z=freqYvol_Z+MAT_ELEM(E,0,2)*freqx;
124 
125  double c;
126  double d;
127  if (BSplineDeg==xmipp_transformation::NEAREST)
128  {
129  // 0 order interpolation
130  // Compute corresponding index in the volume
131  auto kVolume=(int)round(freqvol_Z*volumePaddedSize);
132  auto iVolume=(int)round(freqvol_Y*volumePaddedSize);
133  auto jVolume=(int)round(freqvol_X*volumePaddedSize);
134  c = A3D_ELEM(VfourierRealCoefs,kVolume,iVolume,jVolume);
135  d = A3D_ELEM(VfourierImagCoefs,kVolume,iVolume,jVolume);
136  }
137  else if (BSplineDeg==xmipp_transformation::LINEAR)
138  {
139  // B-spline linear interpolation
140  double kVolume=freqvol_Z*volumePaddedSize;
141  double iVolume=freqvol_Y*volumePaddedSize;
142  double jVolume=freqvol_X*volumePaddedSize;
143  c=VfourierRealCoefs.interpolatedElement3D(jVolume,iVolume,kVolume);
144  d=VfourierImagCoefs.interpolatedElement3D(jVolume,iVolume,kVolume);
145  }
146  else
147  {
148  // B-spline cubic interpolation
149  double kVolume=freqvol_Z*volumePaddedSize;
150  double iVolume=freqvol_Y*volumePaddedSize;
151  double jVolume=freqvol_X*volumePaddedSize;
152 
153  // Commented for speed-up, the corresponding code is below
154  // c=VfourierRealCoefs.interpolatedElementBSpline3D(jVolume,iVolume,kVolume);
155  // d=VfourierImagCoefs.interpolatedElementBSpline3D(jVolume,iVolume,kVolume);
156 
157  // The code below is a replicate for speed reasons of interpolatedElementBSpline3D
158  double z=kVolume;
159  double y=iVolume;
160  double x=jVolume;
161 
162  // Logical to physical
163  z -= STARTINGZ(VfourierRealCoefs);
164  y -= STARTINGY(VfourierRealCoefs);
165  x -= STARTINGX(VfourierRealCoefs);
166 
167  auto l1 = (int)ceil(x - 2);
168  int l2 = l1 + 3;
169 
170  auto m1 = (int)ceil(y - 2);
171  int m2 = m1 + 3;
172 
173  auto n1 = (int)ceil(z - 2);
174  int n2 = n1 + 3;
175 
176  c = d = 0.0;
177  double aux;
178  for (int nn = n1; nn <= n2; nn++)
179  {
180  int equivalent_nn=nn;
181  if (nn<0)
182  equivalent_nn=-nn-1;
183  else if (nn>=Zdim)
184  equivalent_nn=2*Zdim-nn-1;
185  double yxsumRe = 0.0;
186  double yxsumIm = 0.0;
187  for (int m = m1; m <= m2; m++)
188  {
189  int equivalent_m=m;
190  if (m<0)
191  equivalent_m=-m-1;
192  else if (m>=Ydim)
193  equivalent_m=2*Ydim-m-1;
194  double xsumRe = 0.0;
195  double xsumIm = 0.0;
196  for (int l = l1; l <= l2; l++)
197  {
198  double xminusl = x - (double) l;
199  int equivalent_l=l;
200  if (l<0)
201  equivalent_l=-l-1;
202  else if (l>=Xdim)
203  equivalent_l=2*Xdim-l-1;
204  auto CoeffRe = (double) DIRECT_A3D_ELEM(VfourierRealCoefs,equivalent_nn,equivalent_m,equivalent_l);
205  auto CoeffIm = (double) DIRECT_A3D_ELEM(VfourierImagCoefs,equivalent_nn,equivalent_m,equivalent_l);
206  BSPLINE03(aux,xminusl);
207  xsumRe += CoeffRe * aux;
208  xsumIm += CoeffIm * aux;
209  }
210 
211  double yminusm = y - (double) m;
212  BSPLINE03(aux,yminusm);
213  yxsumRe += xsumRe * aux;
214  yxsumIm += xsumIm * aux;
215  }
216 
217  double zminusn = z - (double) nn;
218  BSPLINE03(aux,zminusn);
219  c += yxsumRe * aux;
220  d += yxsumIm * aux;
221  }
222  }
223  // Phase shift to move the origin of the image to the corner
224  double a=DIRECT_A2D_ELEM(phaseShiftImgA,i,j);
225  double b=DIRECT_A2D_ELEM(phaseShiftImgB,i,j);
226  if (ctf!=nullptr)
227  {
228  double ctfij=DIRECT_A2D_ELEM(*ctf,i,j);
229  a*=ctfij;
230  b*=ctfij;
231  }
232 
233  // Multiply Fourier coefficient in volume times phase shift
234  double ac = a * c;
235  double bd = b * d;
236  double ab_cd = (a + b) * (c + d);
237 
238  // And store the multiplication
239  auto *ptrI_ij=(double *)&DIRECT_A2D_ELEM(projectionFourier,i,j);
240  *ptrI_ij = ac - bd;
241  *(ptrI_ij+1) = ab_cd - ac - bd;
242  }
243  }
244  transformer2D.inverseFourierTransform();
245 }
246 
248 {
249  // Zero padding
250  MultidimArray<double> Vpadded;
251  auto paddedDim=(int)(paddingFactor*volumeSize);
252  volume->window(Vpadded,FIRST_XMIPP_INDEX(paddedDim),FIRST_XMIPP_INDEX(paddedDim),FIRST_XMIPP_INDEX(paddedDim),
253  LAST_XMIPP_INDEX(paddedDim),LAST_XMIPP_INDEX(paddedDim),LAST_XMIPP_INDEX(paddedDim));
254  volume->clear();
255  // Make Fourier transform, shift the volume origin to the volume center and center it
257  FourierTransformer transformer3D;
258  transformer3D.completeFourierTransform(Vpadded,Vfourier);
259  ShiftFFT(Vfourier, FIRST_XMIPP_INDEX(XSIZE(Vpadded)), FIRST_XMIPP_INDEX(YSIZE(Vpadded)), FIRST_XMIPP_INDEX(ZSIZE(Vpadded)));
260  CenterFFT(Vfourier,true);
261  Vfourier.setXmippOrigin();
262 
263  // Compensate for the Fourier normalization factor
264  double K=(double)(XSIZE(Vpadded)*XSIZE(Vpadded)*XSIZE(Vpadded))/(double)(volumeSize*volumeSize);
266  DIRECT_MULTIDIM_ELEM(Vfourier,n)*=K;
267  Vpadded.clear();
268  // Compute Bspline coefficients
269  if (BSplineDeg==xmipp_transformation::BSPLINE3)
270  {
271  MultidimArray< double > VfourierRealAux;
272  MultidimArray< double > VfourierImagAux;
273  Complex2RealImag(Vfourier, VfourierRealAux, VfourierImagAux);
274  Vfourier.clear();
275  produceSplineCoefficients(xmipp_transformation::BSPLINE3,VfourierRealCoefs,VfourierRealAux);
276 
277  // Release memory as soon as you can
278  VfourierRealAux.clear();
279 
280  // Remove all those coefficients we are sure we will not use during the projections
281  volumePaddedSize=XSIZE(VfourierRealCoefs);
282  int idxMax=maxFrequency*XSIZE(VfourierRealCoefs)+10; // +10 is a safety guard
283  idxMax=std::min(FINISHINGX(VfourierRealCoefs),idxMax);
284  int idxMin=std::max(-idxMax,STARTINGX(VfourierRealCoefs));
285  VfourierRealCoefs.selfWindow(idxMin,idxMin,idxMin,idxMax,idxMax,idxMax);
286 
287  produceSplineCoefficients(xmipp_transformation::BSPLINE3,VfourierImagCoefs,VfourierImagAux);
288  VfourierImagAux.clear();
289  VfourierImagCoefs.selfWindow(idxMin,idxMin,idxMin,idxMax,idxMax,idxMax);
290  }
291  else {
292  Complex2RealImag(Vfourier, VfourierRealCoefs, VfourierImagCoefs);
293  volumePaddedSize=XSIZE(VfourierRealCoefs);
294  }
295 
296  produceSideInfoProjection();
297 }
298 
300 {
301  // Allocate memory for the 2D Fourier transform
302  projection().initZeros(volumeSize,volumeSize);
303  projection().setXmippOrigin();
304  transformer2D.FourierTransform(projection(),projectionFourier,false);
305 
306  // Calculate phase shift terms
307  phaseShiftImgA.initZeros(projectionFourier);
308  phaseShiftImgB.initZeros(projectionFourier);
309  double shift=-FIRST_XMIPP_INDEX(volumeSize);
310  double xxshift = -2 * PI * shift / volumeSize;
311  for (size_t i=0; i<YSIZE(projectionFourier); ++i)
312  {
313  double phasey=(double)(i) * xxshift;
314  for (size_t j=0; j<XSIZE(projectionFourier); ++j)
315  {
316  // Phase shift to move the origin of the image to the corner
317  double dotp = (double)(j) * xxshift + phasey;
318  //sincos(dotp,&DIRECT_A2D_ELEM(phaseShiftImgB,i,j),&DIRECT_A2D_ELEM(phaseShiftImgA,i,j));
319  DIRECT_A2D_ELEM(phaseShiftImgB,i,j) = sin(dotp);
320  DIRECT_A2D_ELEM(phaseShiftImgA,i,j) = cos(dotp);
321  }
322  }
323 }
324 
325 void projectVolume(FourierProjector &projector, Projection &P, int Ydim, int Xdim,
326  double rot, double tilt, double psi, const MultidimArray<double> *ctf)
327 {
328  projector.project(rot,tilt,psi,ctf);
329  P() = projector.projection();
330 }
331 
Matrix2D< double > eulert
#define YSIZE(v)
void min(Image< double > &op1, const Image< double > &op2)
void reset(int Ydim, int Xdim)
#define FINISHINGX(v)
double psi(const size_t n=0) const
void Euler_angles2matrix(T alpha, T beta, T gamma, Matrix2D< T > &A, bool homogeneous)
Definition: geometry.cpp:624
doublereal * c
void ShiftFFT(MultidimArray< std::complex< double > > &v, double xshift)
Definition: xmipp_fft.cpp:311
static double * y
FourierProjector(double paddFactor, double maxFreq, int degree)
#define DIRECT_A2D_ELEM(v, i, j)
Matrix2D< double > euler
void updateVolume(MultidimArray< double > &V)
Matrix2D< T > transpose() const
Definition: matrix2d.cpp:1314
double rot(const size_t n=0) const
void selfTranspose()
Definition: matrix1d.h:944
#define STARTINGX(v)
doublereal * x
DataMode
#define i
doublereal * d
double tilt(const size_t n=0) const
void produceSideInfoProjection()
Prepare projection space.
#define STARTINGY(v)
#define MAT_ELEM(m, i, j)
Definition: matrix2d.h:116
void CenterFFT(MultidimArray< T > &v, bool forward)
Definition: xmipp_fft.h:291
#define A3D_ELEM(V, k, i, j)
MultidimArray< double > data
Definition: xmipp_image.h:55
doublereal * b
void window(MultidimArray< T1 > &result, int n0, int z0, int y0, int x0, int nF, int zF, int yF, int xF, T1 init_value=0) const
double * f
void produceSplineCoefficients(int SplineDegree, MultidimArray< double > &coeffs, const MultidimArray< T > &V1)
#define XSIZE(v)
void max(Image< double > &op1, const Image< double > &op2)
#define FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(v)
void project(double rot, double tilt, double psi, const MultidimArray< double > *ctf=nullptr)
void produceSideInfo()
Prepare the Spline coefficients and projection space.
#define ZSIZE(v)
double z
#define DIRECT_MULTIDIM_ELEM(v, n)
void projectVolume(FourierProjector &projector, Projection &P, int Ydim, int Xdim, double rot, double tilt, double psi, const MultidimArray< double > *ctf)
#define DIRECT_A3D_ELEM(v, k, i, j)
Matrix1D< double > direction
__device__ float FFT_IDX2DIGFREQ(int idx, int size)
#define j
int m
void setEulerAngles(double rot, double tilt, double psi, const size_t n=0)
int round(double x)
Definition: ap.cpp:7245
#define FIRST_XMIPP_INDEX(size)
Definition: xmipp_macros.h:439
Image< double > projection
void completeFourierTransform(T &v, T1 &V)
Definition: xmipp_fftw.h:315
void applyGeo(const MDRow &row, bool only_apply_shifts=false, bool wrap=xmipp_transformation::WRAP) override
void read(const FileName &fn, const bool only_apply_shifts=false, DataMode datamode=DATA, MDRow *row=nullptr)
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 setAngles(double _rot, double _tilt, double _psi)
void initZeros(const MultidimArray< T1 > &op)
#define LAST_XMIPP_INDEX(size)
Definition: xmipp_macros.h:448
#define PI
Definition: tools.h:43
void getRow(size_t i, Matrix1D< T > &v) const
Definition: matrix2d.cpp:871
#define STARTINGZ(v)
int * n
void Complex2RealImag(const MultidimArray< std::complex< double > > &in, MultidimArray< double > &real, MultidimArray< double > &imag)
Definition: xmipp_fft.cpp:103
doublereal * a
void assign(const Projection &P)
#define BSPLINE03(y, x)
Definition: kernel.h:83