/** * DaubJ wavelets have the following properties:<br> * * <ul> * <li>Conserve the signal's energy * <li>If the signal is approximately polynomial of degree J/2-1 or less within the support then * fluctuations are approximately zero. * <li>The sum of the scaling numbers is sqrt(2) * <li>The sum of the wavelet numbers is 0 * </ul> * * @param J The wavelet's degree. * @return Description of the DaubJ wavelet. */ public static WaveletDescription<WlCoef_F32> daubJ_F32(int J) { if (J != 4) { throw new IllegalArgumentException("Only 4 is currently supported"); } WlCoef_F32 coef = new WlCoef_F32(); coef.offsetScaling = 0; coef.offsetWavelet = 0; coef.scaling = new float[4]; coef.wavelet = new float[4]; double sqrt3 = Math.sqrt(3); double div = 4.0 * Math.sqrt(2); coef.scaling[0] = (float) ((1 + sqrt3) / div); coef.scaling[1] = (float) ((3 + sqrt3) / div); coef.scaling[2] = (float) ((3 - sqrt3) / div); coef.scaling[3] = (float) ((1 - sqrt3) / div); coef.wavelet[0] = coef.scaling[3]; coef.wavelet[1] = -coef.scaling[2]; coef.wavelet[2] = coef.scaling[1]; coef.wavelet[3] = -coef.scaling[0]; WlBorderCoefStandard<WlCoef_F32> inverse = new WlBorderCoefStandard<>(coef); return new WaveletDescription<>(new BorderIndex1D_Wrap(), coef, inverse); }
private static WlCoef_F32 computeInnerInverseBiorthogonal(WlCoef_F32 coef) { WlCoef_F32 ret = new WlCoef_F32(); // center at zero ret.offsetScaling = -coef.wavelet.length / 2; // center at one ret.offsetWavelet = 1 - coef.scaling.length / 2; ret.scaling = new float[coef.wavelet.length]; ret.wavelet = new float[coef.scaling.length]; for (int i = 0; i < ret.scaling.length; i++) { if (i % 2 == 0) ret.scaling[i] = -coef.wavelet[i]; else ret.scaling[i] = coef.wavelet[i]; } for (int i = 0; i < ret.wavelet.length; i++) { if (i % 2 == 1) ret.wavelet[i] = -coef.scaling[i]; else ret.wavelet[i] = coef.scaling[i]; } return ret; }
/** * Daub J/K biorthogonal wavelets have the following properties:<br> * * <ul> * <li>DO NOT conserve the signal's energy * <li>If the signal is approximately polynomial of degree (J-1)/2-1 within the support then * fluctuations are approximately zero. * <li>The sum of the scaling numbers is 1 * <li>The sum of the wavelet numbers is 0 * </ul> * * @param J The wavelet's degree. K = J-2. * @param borderType How image borders are handled. * @return Description of the Daub J/K wavelet. */ public static WaveletDescription<WlCoef_F32> biorthogonal_F32(int J, BorderType borderType) { if (J != 5) { throw new IllegalArgumentException("Only 5 is currently supported"); } WlCoef_F32 forward = new WlCoef_F32(); forward.offsetScaling = -2; forward.offsetWavelet = 0; forward.scaling = new float[5]; forward.wavelet = new float[3]; forward.scaling[0] = (float) (-1.0 / 8.0); forward.scaling[1] = (float) (2.0 / 8.0); forward.scaling[2] = (float) (6.0 / 8.0); forward.scaling[3] = (float) (2.0 / 8.0); forward.scaling[4] = (float) (-1.0 / 8.0); forward.wavelet[0] = -1.0f / 2.0f; forward.wavelet[1] = 1; forward.wavelet[2] = -1.0f / 2.0f; BorderIndex1D border; WlBorderCoef<WlCoef_F32> inverse; if (borderType == BorderType.REFLECT) { WlCoef_F32 inner = computeInnerInverseBiorthogonal(forward); border = new BorderIndex1D_Reflect(); inverse = computeBorderCoefficients(border, forward, inner); } else if (borderType == BorderType.WRAP) { WlCoef_F32 inner = computeInnerInverseBiorthogonal(forward); inverse = new WlBorderCoefStandard<>(inner); border = new BorderIndex1D_Wrap(); } else { throw new IllegalArgumentException("Unsupported border type: " + borderType); } return new WaveletDescription<>(border, forward, inverse); }