void FourierProjector::produceSideInfo() { // Zero padding MultidimArray<double> Vpadded; int paddedDim=(int)(paddingFactor*volumeSize); // JMRT: TODO: I think it is a very poor design to modify the volume passed // in the construct, it will be padded anyway, so new memory should be allocated volume->window(Vpadded,FIRST_XMIPP_INDEX(paddedDim),FIRST_XMIPP_INDEX(paddedDim),FIRST_XMIPP_INDEX(paddedDim), LAST_XMIPP_INDEX(paddedDim),LAST_XMIPP_INDEX(paddedDim),LAST_XMIPP_INDEX(paddedDim)); volume->clear(); // Make Fourier transform, shift the volume origin to the volume center and center it MultidimArray< std::complex<double> > Vfourier; transformer3D.completeFourierTransform(Vpadded,Vfourier); ShiftFFT(Vfourier, FIRST_XMIPP_INDEX(XSIZE(Vpadded)), FIRST_XMIPP_INDEX(YSIZE(Vpadded)), FIRST_XMIPP_INDEX(ZSIZE(Vpadded))); CenterFFT(Vfourier,true); Vfourier.setXmippOrigin(); // Compensate for the Fourier normalization factor double K=(double)(XSIZE(Vpadded)*XSIZE(Vpadded)*XSIZE(Vpadded))/(double)(volumeSize*volumeSize); FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Vfourier) DIRECT_MULTIDIM_ELEM(Vfourier,n)*=K; Vpadded.clear(); // Compute Bspline coefficients if (BSplineDeg==3) { MultidimArray< double > VfourierRealAux, VfourierImagAux; Complex2RealImag(Vfourier, VfourierRealAux, VfourierImagAux); Vfourier.clear(); produceSplineCoefficients(BSPLINE3,VfourierRealCoefs,VfourierRealAux); produceSplineCoefficients(BSPLINE3,VfourierImagCoefs,VfourierImagAux); //VfourierRealAux.clear(); //VfourierImagAux.clear(); } else Complex2RealImag(Vfourier, VfourierRealCoefs, VfourierImagCoefs); // Allocate memory for the 2D Fourier transform projection().initZeros(volumeSize,volumeSize); projection().setXmippOrigin(); transformer2D.FourierTransform(projection(),projectionFourier,false); // Calculate phase shift terms phaseShiftImgA.initZeros(projectionFourier); phaseShiftImgB.initZeros(projectionFourier); double shift=-FIRST_XMIPP_INDEX(volumeSize); double xxshift = -2 * PI * shift / volumeSize; for (size_t i=0; i<YSIZE(projectionFourier); ++i) { double phasey=(double)(i) * xxshift; for (size_t j=0; j<XSIZE(projectionFourier); ++j) { // Phase shift to move the origin of the image to the corner double dotp = (double)(j) * xxshift + phasey; sincos(dotp,&DIRECT_A2D_ELEM(phaseShiftImgB,i,j),&DIRECT_A2D_ELEM(phaseShiftImgA,i,j)); } } }
void FourierProjector::produceSideInfo() { // Zero padding MultidimArray<double> Vpadded; int paddedDim=(int)(paddingFactor*volumeSize); volume->window(Vpadded,FIRST_XMIPP_INDEX(paddedDim),FIRST_XMIPP_INDEX(paddedDim),FIRST_XMIPP_INDEX(paddedDim), LAST_XMIPP_INDEX(paddedDim),LAST_XMIPP_INDEX(paddedDim),LAST_XMIPP_INDEX(paddedDim)); volume->clear(); // Make Fourier transform, shift the volume origin to the volume center and center it MultidimArray< std::complex<double> > Vfourier; transformer3D.completeFourierTransform(Vpadded,Vfourier); ShiftFFT(Vfourier, FIRST_XMIPP_INDEX(XSIZE(Vpadded)), FIRST_XMIPP_INDEX(YSIZE(Vpadded)), FIRST_XMIPP_INDEX(ZSIZE(Vpadded))); CenterFFT(Vfourier,true); Vfourier.setXmippOrigin(); // Compensate for the Fourier normalization factor double K=(double)(XSIZE(Vpadded)*XSIZE(Vpadded)*XSIZE(Vpadded))/(double)(volumeSize*volumeSize); FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Vfourier) DIRECT_MULTIDIM_ELEM(Vfourier,n)*=K; Vpadded.clear(); // Compute Bspline coefficients if (BSplineDeg==3) { MultidimArray< double > VfourierRealAux, VfourierImagAux; Complex2RealImag(Vfourier, VfourierRealAux, VfourierImagAux); Vfourier.clear(); produceSplineCoefficients(BSPLINE3,VfourierRealCoefs,VfourierRealAux); produceSplineCoefficients(BSPLINE3,VfourierImagCoefs,VfourierImagAux); //VfourierRealAux.clear(); //VfourierImagAux.clear(); } else Complex2RealImag(Vfourier, VfourierRealCoefs, VfourierImagCoefs); // Allocate memory for the 2D Fourier transform projection().initZeros(volumeSize,volumeSize); projection().setXmippOrigin(); transformer2D.FourierTransform(projection(),projectionFourier,false); }
// Fill data array with oversampled Fourier transform, and calculate its power spectrum void Projector::computeFourierTransformMap(MultidimArray<DOUBLE> &vol_in, MultidimArray<DOUBLE> &power_spectrum, int current_size, int nr_threads, bool do_gridding) { MultidimArray<DOUBLE> Mpad; MultidimArray<Complex > Faux; FourierTransformer transformer; // DEBUGGING: multi-threaded FFTWs are giving me a headache? // For a long while: switch them off! //transformer.setThreadsNumber(nr_threads); DOUBLE normfft; // Size of padded real-space volume int padoridim = padding_factor * ori_size; // Initialize data array of the oversampled transform ref_dim = vol_in.getDim(); // Make Mpad switch (ref_dim) { case 2: Mpad.initZeros(padoridim, padoridim); normfft = (DOUBLE)(padding_factor * padding_factor); break; case 3: Mpad.initZeros(padoridim, padoridim, padoridim); if (data_dim ==3) normfft = (DOUBLE)(padding_factor * padding_factor * padding_factor); else normfft = (DOUBLE)(padding_factor * padding_factor * padding_factor * ori_size); break; default: REPORT_ERROR("Projector::computeFourierTransformMap%%ERROR: Dimension of the data array should be 2 or 3"); } // First do a gridding pre-correction on the real-space map: // Divide by the inverse Fourier transform of the interpolator in Fourier-space // 10feb11: at least in 2D case, this seems to be the wrong thing to do!!! // TODO: check what is best for subtomo! if (do_gridding)// && data_dim != 3) griddingCorrect(vol_in); // Pad translated map with zeros vol_in.setXmippOrigin(); Mpad.setXmippOrigin(); FOR_ALL_ELEMENTS_IN_ARRAY3D(vol_in) // This will also work for 2D A3D_ELEM(Mpad, k, i, j) = A3D_ELEM(vol_in, k, i, j); // Translate padded map to put origin of FT in the center CenterFFT(Mpad, true); // Calculate the oversampled Fourier transform transformer.FourierTransform(Mpad, Faux, false); // Free memory: Mpad no longer needed Mpad.clear(); // Resize data array to the right size and initialise to zero initZeros(current_size); // Fill data only for those points with distance to origin less than max_r // (other points will be zero because of initZeros() call above // Also calculate radial power spectrum power_spectrum.initZeros(ori_size / 2 + 1); MultidimArray<DOUBLE> counter(power_spectrum); counter.initZeros(); int max_r2 = r_max * r_max * padding_factor * padding_factor; FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Faux) // This will also work for 2D { int r2 = kp*kp + ip*ip + jp*jp; // The Fourier Transforms are all "normalised" for 2D transforms of size = ori_size x ori_size if (r2 <= max_r2) { // Set data array A3D_ELEM(data, kp, ip, jp) = DIRECT_A3D_ELEM(Faux, k, i, j) * normfft; // Calculate power spectrum int ires = ROUND( sqrt((DOUBLE)r2) / padding_factor ); // Factor two because of two-dimensionality of the complex plane DIRECT_A1D_ELEM(power_spectrum, ires) += norm(A3D_ELEM(data, kp, ip, jp)) / 2.; DIRECT_A1D_ELEM(counter, ires) += 1.; } } // Calculate radial average of power spectrum FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(power_spectrum) { if (DIRECT_A1D_ELEM(counter, i) < 1.) DIRECT_A1D_ELEM(power_spectrum, i) = 0.; else DIRECT_A1D_ELEM(power_spectrum, i) /= DIRECT_A1D_ELEM(counter, i); } transformer.cleanup(); }
void ProgSSNR::estimateSSNR(int dim, Matrix2D<double> &output) { // These vectors are for 1D Matrix1D<double> S_S21D((int)(XSIZE(S()) / 2 - ring_width)), S_N21D((int)(XSIZE(S()) / 2 - ring_width)), K1D((int)(XSIZE(S()) / 2 - ring_width)), S_SSNR1D; Matrix1D<double> N_S21D((int)(XSIZE(S()) / 2 - ring_width)), N_N21D((int)(XSIZE(S()) / 2 - ring_width)), N_SSNR1D; // Selfile of the 2D images MetaData SF_individual; std::cerr << "Computing the SSNR ...\n"; init_progress_bar(SF_S.size()); int imgno = 1; Image<double> Is, In; Projection Iths, Ithn; MultidimArray< std::complex<double> > FFT_Is, FFT_Iths, FFT_In, FFT_Ithn; MultidimArray<double> S2s, N2s, S2n, N2n; FileName fn_img; FourierTransformer FT(FFTW_BACKWARD); FourierProjector *Sprojector=NULL; FourierProjector *Nprojector=NULL; if (fourierProjections) { Sprojector=new FourierProjector(S(),2,0.5,LINEAR); Nprojector=new FourierProjector(N(),2,0.5,LINEAR); } FOR_ALL_OBJECTS_IN_METADATA2(SF_S, SF_N) { double rot, tilt, psi; SF_S.getValue(MDL_ANGLE_ROT,rot, __iter.objId); SF_S.getValue(MDL_ANGLE_TILT,tilt,__iter.objId); SF_S.getValue(MDL_ANGLE_PSI,psi,__iter.objId); SF_S.getValue(MDL_IMAGE,fn_img,__iter.objId); Is.read(fn_img); Is().setXmippOrigin(); SF_N.getValue(MDL_IMAGE,fn_img,__iter2.objId); In.read(fn_img); In().setXmippOrigin(); if (fourierProjections) { projectVolume(*Sprojector, Iths, YSIZE(Is()), XSIZE(Is()), rot, tilt, psi); projectVolume(*Nprojector, Ithn, YSIZE(Is()), XSIZE(Is()), rot, tilt, psi); } else { projectVolume(S(), Iths, YSIZE(Is()), XSIZE(Is()), rot, tilt, psi); projectVolume(N(), Ithn, YSIZE(Is()), XSIZE(Is()), rot, tilt, psi); } #ifdef DEBUG Image<double> save; save() = Is(); save.write("PPPread_signal.xmp"); save() = In(); save.write("PPPread_noise.xmp"); save() = Iths(); save.write("PPPtheo_signal.xmp"); save() = Ithn(); save.write("PPPtheo_noise.xmp"); #endif Is() -= Iths(); In() -= Ithn(); // According to the article: should we not subtract here (simply remove this line) // "...except that there is no subtraction in the denominator because the // underlying signal is zero by definition." if (dim == 2) { FT.completeFourierTransform(Is(), FFT_Is); FT.completeFourierTransform(Iths(), FFT_Iths); FT.completeFourierTransform(In(), FFT_In); FT.completeFourierTransform(Ithn(), FFT_Ithn); } else { FT.FourierTransform(Is(), FFT_Is); FT.FourierTransform(Iths(), FFT_Iths); FT.FourierTransform(In(), FFT_In); FT.FourierTransform(Ithn(), FFT_Ithn); } #ifdef DEBUG Image< std::complex<double> > savec; savec() = FFT_Is; savec.write("PPPFFTread_signal.xmp"); savec() = FFT_In; savec.write("PPPFFTread_noise.xmp"); savec() = FFT_Iths; savec.write("PPPFFTtheo_signal.xmp"); savec() = FFT_Ithn; savec.write("PPPFFTtheo_noise.xmp"); #endif // Compute the amplitudes S2s.resizeNoCopy(FFT_Iths); N2s.resizeNoCopy(FFT_Iths); S2n.resizeNoCopy(FFT_Iths); N2n.resizeNoCopy(FFT_Iths); FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(FFT_Iths) { DIRECT_MULTIDIM_ELEM(S2s, n) = abs(DIRECT_MULTIDIM_ELEM(FFT_Iths, n)); DIRECT_MULTIDIM_ELEM(S2s, n) *= DIRECT_MULTIDIM_ELEM(S2s, n); DIRECT_MULTIDIM_ELEM(N2s, n) = abs(DIRECT_MULTIDIM_ELEM(FFT_Is, n)); DIRECT_MULTIDIM_ELEM(N2s, n) *= DIRECT_MULTIDIM_ELEM(N2s, n); DIRECT_MULTIDIM_ELEM(S2n, n) = abs(DIRECT_MULTIDIM_ELEM(FFT_Ithn, n)); DIRECT_MULTIDIM_ELEM(S2n, n) *= DIRECT_MULTIDIM_ELEM(S2n, n); DIRECT_MULTIDIM_ELEM(N2n, n) = abs(DIRECT_MULTIDIM_ELEM(FFT_In, n)); DIRECT_MULTIDIM_ELEM(N2n, n) *= DIRECT_MULTIDIM_ELEM(N2n, n); } #ifdef DEBUG save() = S2s(); save.write("PPPS2s.xmp"); save() = N2s(); save.write("PPPN2s.xmp"); save() = S2n(); save.write("PPPS2n.xmp"); save() = N2n(); save.write("PPPN2n.xmp"); #endif if (dim == 2) { // Compute the SSNR image Image<double> SSNR2D; SSNR2D().initZeros(S2s); const MultidimArray<double> & SSNR2Dmatrix=SSNR2D(); FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(S2s) { double ISSNR = 0, alpha = 0, SSNR = 0; double aux = DIRECT_MULTIDIM_ELEM(N2s,n); if (aux > min_power) ISSNR = DIRECT_MULTIDIM_ELEM(S2s,n) / aux; aux = DIRECT_MULTIDIM_ELEM(N2n,n); if (aux > min_power) alpha = DIRECT_MULTIDIM_ELEM(S2n,n) / aux; if (alpha > min_power) { aux = ISSNR / alpha - 1.0; SSNR = XMIPP_MAX(aux, 0.0); } if (SSNR > min_power) DIRECT_MULTIDIM_ELEM(SSNR2Dmatrix,n) = 10.0 * log10(SSNR + 1.0); } CenterFFT(SSNR2D(), true); #ifdef DEBUG save() = SSNR2Dmatrix; save.write("PPPSSNR2D.xmp"); #endif // Save image FileName fn_img_out; fn_img_out.compose(imgno, fn_out_images, "stk"); SSNR2D.write(fn_img_out); size_t objId = SF_individual.addObject(); SF_individual.setValue(MDL_IMAGE,fn_img_out,objId); SF_individual.setValue(MDL_ANGLE_ROT,rot,objId); SF_individual.setValue(MDL_ANGLE_TILT,tilt,objId); SF_individual.setValue(MDL_ANGLE_PSI,psi,objId); }