/** * 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); }
/** * Computes inverse coefficients * * @param border * @param forward Forward coefficients. * @param inverse Inverse used in the inner portion of the data stream. * @return */ private static WlBorderCoef<WlCoef_F32> computeBorderCoefficients( BorderIndex1D border, WlCoef_F32 forward, WlCoef_F32 inverse) { int N = Math.max(forward.getScalingLength(), forward.getWaveletLength()); N += N % 2; N *= 2; border.setLength(N); // Because the wavelet transform is a linear invertible system the inverse coefficients // can be found by creating a matrix and inverting the matrix. Boundary conditions are then // extracted from this inverted matrix. DenseMatrix64F A = new DenseMatrix64F(N, N); for (int i = 0; i < N; i += 2) { for (int j = 0; j < forward.scaling.length; j++) { int index = border.getIndex(j + i + forward.offsetScaling); A.add(i, index, forward.scaling[j]); } for (int j = 0; j < forward.wavelet.length; j++) { int index = border.getIndex(j + i + forward.offsetWavelet); A.add(i + 1, index, forward.wavelet[j]); } } LinearSolver<DenseMatrix64F> solver = LinearSolverFactory.linear(N); if (!solver.setA(A) || solver.quality() < 1e-5) { throw new IllegalArgumentException("Can't invert matrix"); } DenseMatrix64F A_inv = new DenseMatrix64F(N, N); solver.invert(A_inv); int numBorder = UtilWavelet.borderForwardLower(inverse) / 2; WlBorderCoefFixed<WlCoef_F32> ret = new WlBorderCoefFixed<>(numBorder, numBorder + 1); ret.setInnerCoef(inverse); // add the lower coefficients first for (int i = 0; i < ret.getLowerLength(); i++) { computeLowerCoef(inverse, A_inv, ret, i * 2); } // add upper coefficients for (int i = 0; i < ret.getUpperLength(); i++) { computeUpperCoef(inverse, N, A_inv, ret, i * 2); } return ret; }
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); }