/** * 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; }
// todo rename and move to a utility function? public static WlBorderCoefFixed<WlCoef_I32> convertToInt( WlBorderCoefFixed<WlCoef_F32> orig, WlCoef_I32 inner) { WlBorderCoefFixed<WlCoef_I32> ret = new WlBorderCoefFixed<>(orig.getLowerLength(), orig.getUpperLength()); for (int i = 0; i < orig.getLowerLength(); i++) { WlCoef_F32 o = orig.getLower(i); WlCoef_I32 r = new WlCoef_I32(); ret.setLower(i, r); convertCoef_F32_to_I32(inner.denominatorScaling, inner.denominatorWavelet, o, r); } for (int i = 0; i < orig.getUpperLength(); i++) { WlCoef_F32 o = orig.getUpper(i); WlCoef_I32 r = new WlCoef_I32(); ret.setUpper(i, r); convertCoef_F32_to_I32(inner.denominatorScaling, inner.denominatorWavelet, o, r); } ret.setInnerCoef(inner); return ret; }