001    package util.wavelet;
002    import java.util.List;
003    import static java.lang.Math.*;
004    
005    /** A simple wavelet space contains a simple signal and its wavelet transform.
006     *      <ol>
007     *      <li>The original SimpleSignal
008     *      <li>An ordered list of instances of SimpleSignal representing scales</li>
009     *      <li>An instance of smoothed signal</li>
010     *      </ol>
011     *
012     * @author John Talbot
013     */
014    public class SimpleWaveletSpace {
015    
016        /** Reference to original signal. */
017        public SimpleSignal signal;
018    
019        /** List of scales containing wavelet coefficients. */
020        public java.util.List<SimpleSignal> scales;
021        
022        /** Last smoothed array as computed by the atrous wavelet transform. */
023        SimpleSignal smoothedSignal;
024    
025        /** 
026         * Construct a discrete wavelet transform using the 1D A-Trous method with a b3-spline
027         * smoothing function. (Starck 2002 p.29). Boundary conditions are handled by the simple signal object.
028         * @param signal the simple signal to be wavelet transformed
029         */
030        public SimpleWaveletSpace(SimpleSignal signal) {
031            this.signal  = signal;
032            int maximumScale = signal.estimateNumberOfScales();
033            scales = new java.util.ArrayList<SimpleSignal>(maximumScale);
034            smoothedSignal = new SimpleSignal(signal);
035            int n = signal.size();
036            for (int scaleNumber = 0; scaleNumber < maximumScale; scaleNumber++) {
037                SimpleSignal scale = new SimpleSignal(smoothedSignal);
038                int step = (int)(pow(2.0d, (double) scaleNumber) + 0.5d);
039                int step2= step * 2;
040                for (int i = 0; i < n; i++) {  // smooth with kernel (1/16, 1/4, 3/8, 1/4, 1/16)
041                    smoothedSignal.setValue(i, 0.375f  *   scale.getValue(i)
042                                             + 0.25f   * ( scale.getValue(i-step)  + scale.getValue(i+step))
043                                             + 0.0625f * ( scale.getValue(i-step2) + scale.getValue(i-step2)));
044                }
045                scale.subtract(smoothedSignal);
046                scales.add(scale);
047            }
048        }
049    
050        /** The maximum number of iterations used to obtain the continuum. */
051        static int MAX_ITERATIONS = 5;
052    
053        /** 
054         * Get the continuum of a signal. The continuum is computed by iteratively substracting
055         * the smoothed signal from the signal; the iteration is required due to border problems.
056         * (see Starck 1998 p.127).
057         * @return the continuum of the signal
058         */
059        public SimpleSignal getContinuum() {
060            int n = signal.size();
061            SimpleSignal continuum = new SimpleSignal(getSmoothedSignal());
062            SimpleSignal flattenedSignal = new SimpleSignal(n);
063            for (int iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
064                SimpleSignal.subtract(signal, continuum, flattenedSignal);  
065                SimpleWaveletSpace simpleWaveletSpace = new SimpleWaveletSpace(flattenedSignal);
066                continuum.add(simpleWaveletSpace.getSmoothedSignal());
067            }
068            return continuum;
069        }
070    
071        /** 
072         * Get the last smoothed array as computed by the atrous wavelet transform.
073         * @return the last smoothed array as a simple signal
074         */
075        public SimpleSignal getSmoothedSignal() {
076            return smoothedSignal;
077        }
078        
079        /** 
080         * Get the specified scale as computed by the atrous wavelet transform.
081         * @param scaleNumber the scale number
082         * @return the specified scale as an instance of simple signal
083         */
084        public SimpleSignal getScale(int scaleNumber) {
085            return scales.get(scaleNumber);
086        }
087    
088        /** 
089         * Set the scale at the specified scale number.
090         * @param scaleNumber the scale number
091         * @param scale the specified scale
092         */
093        public void setScale(int scaleNumber, SimpleSignal scale) {
094            scales.set(scaleNumber, scale);
095        }
096    
097        /** 
098         * Get the number of scales as computed by the atrous wavelet transform.
099         * @return the number of scales
100         */
101        public int getNumberOfScales() {
102            return scales.size();
103        }
104    
105        /** Use the WObject as a mask to eliminate wavelet coefficients not in the object. */
106        public void mask(WObject wObject) {
107            // TODO:
108        }
109    
110        /** 
111         * Discrete wavelet transform reconstruction using the 1D A-Trous method with a b3-spline smoothing function.
112         * Reconstruction is computed by summing up all the scales plus the last smoothed array.
113         * (see Starck 1998 p.21-26). 
114         * @return the reconstructed signal as an instance of simple signal
115         */
116        public SimpleSignal getReconstruction() {
117            SimpleSignal reconstruction = new SimpleSignal(signal.size());
118            for (SimpleSignal scale : scales) reconstruction.add(scale);
119            reconstruction.add(smoothedSignal);
120            return reconstruction;
121        }
122    
123        /** 
124         * Discrete wavelet transform reconstruction using the 1D A-Trous method with a b3-spline smoothing function.
125         * Reconstruction is computed by summing up all the structures belonging to the WObject plus the last smoothed array.
126         * (see Starck 1998 p.21-26). 
127         * @return the reconstructed signal as an instance of simple signal
128         */
129        public SimpleSignal getReconstruction(WObject wObject) {
130            // TODO:
131            //for (int scale = 0; scale < scales.size(); scale++) {
132            //    SimpleSignal coefficients = wObject.getStructures(scale);
133            //}
134            return getReconstruction();
135        }
136    
137    }