private int computeCSFDeltaAvg( int[] src, int[] dst, int x0, int y0, int w, int h, int channelIdx) { final int[] csf; final int[] mask_csf; if (channelIdx == 0) { csf = CSF_Y_1024; mask_csf = MASK_CSF_Y_1024; } else if (channelIdx == 1) { csf = CSF_Cb_1024; mask_csf = MASK_CSF_Cb_1024; } else { csf = CSF_Cr_1024; mask_csf = MASK_CSF_Cr_1024; } long lsum = 0; final int[] dct_s = new int[64]; final int[] dct_d = new int[64]; int pixels = 0; final DCT8 dct = new DCT8(); IndexedIntArray iia_s = new IndexedIntArray(dct_s, 0); IndexedIntArray iia_d = new IndexedIntArray(dct_d, 0); int[] s_means_64 = new int[4]; int[] d_means_64 = new int[4]; int[] s_vars_1024 = new int[4]; int[] d_vars_1024 = new int[4]; final int st = this.stride << this.downSampling; final int inc = 1 << this.downSampling; final int inc7 = 7 * inc; for (int y = y0; y < h - 7; y += inc7) { for (int x = x0; x < w - 7; x += inc7) { s_means_64[0] = s_means_64[1] = s_means_64[2] = s_means_64[3] = 0; d_means_64[0] = d_means_64[1] = d_means_64[2] = d_means_64[3] = 0; s_vars_1024[0] = s_vars_1024[1] = s_vars_1024[2] = s_vars_1024[3] = 0; d_vars_1024[0] = d_vars_1024[1] = d_vars_1024[2] = d_vars_1024[3] = 0; int s_gmean64 = 0; int d_gmean64 = 0; int s_gvar64 = 0; int d_gvar64 = 0; // Populate DCT arrays for (int i = 0; i < 8; i++) { final int i8 = i << 3; final int offs = (y + i) * st + (x * inc); for (int j = 0; j < 8; j++) { final int idx1 = i8 + j; final int idx2 = offs + (j * inc); final int sub = ((i & 12) >> 2) + ((j & 12) >> 1); dct_s[idx1] = src[idx2]; dct_d[idx1] = dst[idx2]; s_gmean64 += dct_s[idx1]; d_gmean64 += dct_d[idx1]; s_means_64[sub] += (dct_s[idx1] << 2); d_means_64[sub] += (dct_d[idx1] << 2); } } // Compute variance for (int i = 0; i < 8; i++) { final int i8 = i << 3; for (int j = 0; j < 8; j++) { final int s = dct_s[i8 + j] << 6; final int d = dct_d[i8 + j] << 6; final int sub = ((i & 12) >> 2) + ((j & 12) >> 1); s_gvar64 += (s - s_gmean64) * (s - s_gmean64); d_gvar64 += (d - d_gmean64) * (d - d_gmean64); s_vars_1024[sub] += (s - s_means_64[sub]) * (s - s_means_64[sub]); d_vars_1024[sub] += (d - d_means_64[sub]) * (d - d_means_64[sub]); } } // Replace s_gvar64 /= (63*64) and s_vars_1024[i] *= 16/15 with 63*64*16/15 = 275251/64 // Since s_vars_1024[i] is scaled by 4 (s_means_1024 scaled by 64*64 instead of 1024), // use rescaling factor 275251/256. if (s_gvar64 > 0) { long sum = (long) (s_vars_1024[0] + s_vars_1024[1] + s_vars_1024[2] + s_vars_1024[3]); s_gvar64 = (int) (sum / 256 * 275251 / s_gvar64); } if (d_gvar64 > 0) { long sum = (long) (d_vars_1024[0] + d_vars_1024[1] + d_vars_1024[2] + d_vars_1024[3]); d_gvar64 = (int) (sum / 256 * 275251 / d_gvar64); } // Perform forward DCT (gain is 1<<5) iia_s.index = 0; dct.forward(iia_s, iia_s); iia_d.index = 0; dct.forward(iia_d, iia_d); // Offset DCT gain dct_s[0] >>= 5; dct_d[0] >>= 5; long s_mask_1024 = 0; long d_mask_1024 = 0; // Compute masks for (int i = 0; i < 8; i++) { final int i8 = i << 3; final int j0 = (i == 0) ? 1 : 0; for (int j = j0; j < 8; j++) { final int idx = i8 + j; // Offset DCT gain dct_s[idx] >>= 5; dct_d[idx] >>= 5; s_mask_1024 += (dct_s[idx] * dct_s[idx] * mask_csf[idx]); d_mask_1024 += (dct_d[idx] * dct_d[idx] * mask_csf[idx]); } } if (d_mask_1024 * d_gvar64 > s_mask_1024 * s_gvar64) s_mask_1024 = (long) (Global.sqrt((int) d_mask_1024) >> 8) * (long) (Global.sqrt(d_gvar64) >> 7); else s_mask_1024 = (long) (Global.sqrt((int) s_mask_1024) >> 8) * (long) (Global.sqrt(s_gvar64) >> 7); // Calculate error for (int i = 0; i < 8; i++) { final int i8 = i << 3; for (int j = 0; j < 8; j++) { final int idx = i8 + j; long err1024 = ((long) Math.abs(dct_s[idx] - dct_d[idx])) << 10; if ((i != 0) || (j != 0)) err1024 = (err1024 * mask_csf[idx] < s_mask_1024) ? 0 : err1024 - (s_mask_1024 / mask_csf[idx]); final long val1024 = (err1024 * csf[idx] + 512) >> 10; lsum += ((val1024 * val1024) >> 10); pixels++; } } } } return (pixels == 0) ? 0 : (int) (((lsum + 512) >> 10) / pixels); }