// Fourier ring correlation ----------------------------------------------- // from precalculated Fourier Transforms, and without sampling rate etc. void getFSC(MultidimArray< Complex >& FT1, MultidimArray< Complex >& FT2, MultidimArray< double >& fsc) { if (!FT1.sameShape(FT2)) { REPORT_ERROR("fourierShellCorrelation ERROR: MultidimArrays have different shapes!"); } MultidimArray< int > radial_count(XSIZE(FT1)); MultidimArray<double> num, den1, den2; Matrix1D<double> f(3); num.initZeros(radial_count); den1.initZeros(radial_count); den2.initZeros(radial_count); fsc.initZeros(radial_count); FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(FT1) { int idx = ROUND(sqrt(kp * kp + ip * ip + jp * jp)); if (idx >= XSIZE(FT1)) { continue; } Complex z1 = DIRECT_A3D_ELEM(FT1, k, i, j); Complex z2 = DIRECT_A3D_ELEM(FT2, k, i, j); double absz1 = abs(z1); double absz2 = abs(z2); num(idx) += (conj(z1) * z2).real; den1(idx) += absz1 * absz1; den2(idx) += absz2 * absz2; radial_count(idx)++; } FOR_ALL_ELEMENTS_IN_ARRAY1D(fsc) { fsc(i) = num(i) / sqrt(den1(i) * den2(i)); } }
/** Kullback-Leibner divergence */ double getKullbackLeibnerDivergence(MultidimArray<Complex >& Fimg, MultidimArray<Complex >& Fref, MultidimArray<double>& sigma2, MultidimArray<double>& p_i, MultidimArray<double>& q_i, int highshell, int lowshell) { // First check dimensions are OK if (!Fimg.sameShape(Fref)) { REPORT_ERROR("getKullbackLeibnerDivergence ERROR: Fimg and Fref are not of the same shape."); } if (highshell < 0) { highshell = XSIZE(Fimg) - 1; } if (lowshell < 0) { lowshell = 0; } if (highshell > XSIZE(sigma2)) { REPORT_ERROR("getKullbackLeibnerDivergence ERROR: highshell is larger than size of sigma2 array."); } if (highshell < lowshell) { REPORT_ERROR("getKullbackLeibnerDivergence ERROR: highshell is smaller than lowshell."); } // Initialize the histogram MultidimArray<int> histogram; int histogram_size = 101; int histogram_origin = histogram_size / 2; double sigma_max = 10.; double histogram_factor = histogram_origin / sigma_max; histogram.initZeros(histogram_size); // This way this will work in both 2D and 3D FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Fimg) { int ires = ROUND(sqrt(kp * kp + ip * ip + jp * jp)); if (ires >= lowshell && ires <= highshell) { // Use FT of masked image for noise estimation! double diff_real = (DIRECT_A3D_ELEM(Fref, k, i, j)).real - (DIRECT_A3D_ELEM(Fimg, k, i, j)).real; double diff_imag = (DIRECT_A3D_ELEM(Fref, k, i, j)).imag - (DIRECT_A3D_ELEM(Fimg, k, i, j)).imag; double sigma = sqrt(DIRECT_A1D_ELEM(sigma2, ires)); // Divide by standard deviation to normalise all the difference diff_real /= sigma; diff_imag /= sigma; // Histogram runs from -10 sigma to +10 sigma diff_real += sigma_max; diff_imag += sigma_max; // Make histogram on-the-fly; // Real part int ihis = ROUND(diff_real * histogram_factor); if (ihis < 0) { ihis = 0; } else if (ihis >= histogram_size) { ihis = histogram_size - 1; } histogram(ihis)++; // Imaginary part ihis = ROUND(diff_imag * histogram_factor); if (ihis < 0) { ihis = 0; } else if (ihis > histogram_size) { ihis = histogram_size; } histogram(ihis)++; } } // Normalise the histogram and the discretised analytical Gaussian double norm = (double)histogram.sum(); double gaussnorm = 0.; for (int i = 0; i < histogram_size; i++) { double x = (double)i / histogram_factor; gaussnorm += gaussian1D(x - sigma_max, 1. , 0.); } // Now calculate the actual Kullback-Leibner divergence double kl_divergence = 0.; p_i.resize(histogram_size); q_i.resize(histogram_size); for (int i = 0; i < histogram_size; i++) { // Data distribution p_i(i) = (double)histogram(i) / norm; // Theoretical distribution double x = (double)i / histogram_factor; q_i(i) = gaussian1D(x - sigma_max, 1. , 0.) / gaussnorm; if (p_i(i) > 0.) { kl_divergence += p_i(i) * log(p_i(i) / q_i(i)); } } kl_divergence /= (double)histogram_size; return kl_divergence; }