001    package util.wavelet;
002    import java.util.List;
003    import static java.lang.Math.*;
004    
005    /** 
006     *A set of wavelet coefficients and a smoothed array computed using the 'atrous' discrete wavelet trasform on a signal.
007     *  In more detail a wavelet space contains instances of the following classes :
008     * <ul>
009     * <li>WaveletSpace : contains
010     *      <ol>
011     *      <li>Original signal (which also contains a noise estimate for each sample)
012     *      <li>Ordered list of {@link Scale} instances</li>
013     *      <li>Smoothed signal</li>
014     *      <li>Set of {@link WObject} instances</li> 
015     *      </ol>
016     * </li>
017     * <li>{@link Scale} : contains
018     *      <ol>
019     *      <li>An array of wavelet coeffients</li>
020     *      <li>An array of noise threshold coeffients</li>
021     *      <li>a set of Structure instances</li>
022     *      </ol>
023     * </li>
024     * </ul>
025     *
026     * <p>A WaveletSpace contains zero or more WObject instances which in turn contains
027     * one or more InterscaleRelationship instances which in turn each contain two Structure instances.
028     * A WaveletSpace is derived from a Signal which has an associated noise estimate.
029     * A WaveletSpace contains a certain number of wavelet {@link Scale} instances.</p>
030     *
031     * <p>The discrete wavelet transform of a signal is computed using the 1D A-Trous method with a b3-spline smoothing function.
032     * The constructor computes the wavelet coefficients a a set of scales plus a smoothed signal,
033     * the 1-sigma threshold for wavelet coefficients, structures, interscale relationships and object trees
034     * for feature extraction and makes available a set of signals corresponding to each individual object
035     * detected.</p>
036     *
037     * <b>Reference:</b> Starck,J.-L., Murtagh, F.: 2002, <i>Astronomical Image and Data Analysis</i>,
038     * ISBN 3540428852, Springer.
039     *
040     * @author John Talbot
041     */
042    
043    /*
044    
045    Operators and variables from Starck (2002) p.102-103 :
046    <table>
047    <tr><td>Oi      </td><td>signal corresponding to object i                         </td></tr>
048    <tr><td>Wi      </td><td>wavelet space restricted to Oi Structures, zero elsewhere</td></tr>
049    <tr><td>W       </td><td>wavelet transform                                        </td></tr>
050    <tr><td>W^-1    </td><td>inverse transform                                        </td></tr>
051    <tr><td>Pw      </td><td>projection onto Oi Structures                            </td></tr>
052    <tr><td>A=Pw o W</td><td> wavelet transform then projection onto Oi Structures)   </td></tr>
053    <tr><td>A~      </td><td>adjoint of A                                             </td></tr>
054    <tr><td>n       </td><td>iteration of reconstruction                              </td></tr>
055    <tr><td>Oi(n)   </td><td>object i (a 1D signal)                                   </td></tr>
056    <tr><td>wr{n}   </td><td>wavelet residual                                         </td></tr>
057    <tr><td>R(n)    </td><td>residual signal                                          </td></tr>
058    <tr><td>alpha(n)</td><td>covergence parameter alpha                               </td></tr>
059    <tr><td>beta(n) </td><td>covergence parameter beta                                </td></tr>
060    </table>
061    
062    <table>
063    <tr><th colspan="2">Reconstruction algorithm</th></tr>
064    <tr><td>1</td><td>Intialization step</td><td>Oi(0) = W^-1 Wi      <br/>
065                                                 wr(0) = Wi - A(Oi(0))<br/>
066                                                 R(0)  = A~(wr(0))    <br/></td></tr>
067    <tr><td>2</td><td></td><td></td></tr>
068    <tr><td>3</td><td></td><td></td></tr>
069    <tr><td>4</td><td></td><td></td></tr>
070    <tr><td>5</td><td></td><td></td></tr>
071    <tr><td>6</td><td></td><td></td></tr>
072    <tr><td>7</td><td>Compute convergence parameter beta</td><td>beta(n+1) = mag()^2 / mag()^2</td></tr>
073    <tr><td>8</td><td>Resisdual image computation  </td><td>R(n+1) = A~(wr(n+1) + beta(n+1)R(n)</td></tr>
074    <tr><td>9</td><td>Return to step 2</td><td></td></tr>
075    
076      ReconstructedSignal
077    
078      WaveletResidual 
079    
080      ResidualSignal
081      
082    </li>
083    
084    <li>Computation of convergence parameter : alpha = / A(
085    
086    </li>
087    
088    
089    */
090    
091    public class WaveletSpace {
092    
093        /** An reference to the original signal. */
094        public Signal signal;
095    
096        /** 
097         * A list of scales containing wavelet coefficients and optionally noise thresholds. 
098         * This representation is useful when using decimating wavelet transforms which
099         * have a decreasing number of wavelet coefficients at larger scales.
100         */
101        public java.util.List<Scale> scales;
102        
103        /** The last smoothed array as computed by the atrous wavelet transform. */
104        public SimpleSignal smoothedSignal;
105    
106        /** The noise computation method. */
107        NoiseComputation noiseComputation = NoiseComputation.UpperLimit;
108    
109        /** A list of WObject instances contained in the wavelet space */
110        public java.util.List<WObject> wObjects;
111    
112        /** 
113         * Construct a discrete wavelet transform using the 1D A-Trous method with a b3-spline
114         * smoothing function. (Starck 2002 p.29). Boundary conditions are handled by the signal.
115         *  
116         * @param signal the signal to be wavelet transformed
117         */
118        public WaveletSpace(Signal signal) {
119            this.signal  = signal;
120            int maximumScale = signal.estimateNumberOfScales();
121            scales = new java.util.ArrayList<Scale>(maximumScale);
122            smoothedSignal = new SimpleSignal(signal);
123            int n = signal.size();
124            for (int scaleNumber = 0; scaleNumber < maximumScale; scaleNumber++) {
125                Scale scale = new Scale(smoothedSignal, scaleNumber);
126                int step = (int)(pow(2.0d, (double) scaleNumber) + 0.5d);
127                int step2= step * 2;
128                for (int i = 0; i < n; i++) {  // smooth with kernel (1/16, 1/4, 3/8, 1/4, 1/16)
129                    smoothedSignal.setValue(i, 0.375f  *   scale.getValue(i)
130                                             + 0.25f   * ( scale.getValue(i-step)  + scale.getValue(i+step))
131                                             + 0.0625f * ( scale.getValue(i-step2) + scale.getValue(i-step2)));
132                }
133                scale.subtract(smoothedSignal);
134                scales.add(scale);
135            }
136            noiseComputation.compute(signal, scales);
137        }
138    
139        /** 
140         * Construct the WaveletSpace given a signal and a uniform noise value.
141         * @param signal the signal to be wavelet transformed
142         * @param uniformNoise a uniform noise standard deviation
143         */
144        public WaveletSpace(Signal signal, float uniformNoise) {
145            this(signal);
146            // compute noise   if (this.noise == null) computeNoise();
147        }
148    
149        /** 
150         * Get the specified scale as computed by the atrous wavelet transform.
151         * @param scaleNumber the scale number
152         * @return the specified scale as an instance of simple signal
153         */
154        public Scale getScale(int scaleNumber) {
155            return scales.get(scaleNumber);
156        }
157    
158        /** 
159         * Set the scale at the specified scale number.
160         * @param scaleNumber the scale number
161         * @param scale the specified scale
162         */
163        public void setScale(int scaleNumber, Scale scale) {
164            scales.set(scaleNumber, scale);
165        }
166        
167        /** Use the WObject as a mask to eliminate wavelet coefficients not in the object. */
168        public void mask(WObject wObject) {
169            // TODO:
170        }
171    
172        /** 
173         * Discrete wavelet transform reconstruction using the 1D A-Trous method with a b3-spline smoothing function.
174         * Reconstruction is computed by summing up all the structures belonging to the WObject plus the last smoothed array.
175         * (see Starck 1998 p.21-26). 
176         * 
177         * @return the reconstructed signal as an instance of simple signal
178         */
179        public SimpleSignal getReconstruction(WObject wObject) {
180            for (int scale = 0; scale < scales.size(); scale++) {
181                //SimpleSignal coefficients = wObject.getStructures(scale);
182            }
183            return getReconstruction();
184        }
185    
186        /** 
187         * Discrete wavelet transform reconstruction using the 1D A-Trous method with a b3-spline smoothing function.
188         * Reconstruction is computed by summing up all the scales plus the last smoothed array.
189         * (see Starck 1998 p.21-26). 
190         * 
191         * @return the reconstructed signal as an instance of simple signal
192         */
193        public SimpleSignal getReconstruction() {
194            SimpleSignal reconstruction = new SimpleSignal(signal.size());
195            for (SimpleSignal scale : scales) reconstruction.add(scale);
196            reconstruction.add(smoothedSignal);
197            return reconstruction;
198        }
199    
200    //-----------------methods that belong in superclass-----------------------------------
201    
202        /** The maximum number of iterations used to obtain the continuum. */
203        static int MAX_ITERATIONS = 5;
204    
205        /** 
206         * Get the continuum of a signal. The continuum is computed by iteratively substracting
207         * the smoothed signal from the signal; the iteration is required due to border problems.
208         * (see Starck 1998 p.127).
209         * @return the continuum of the signal
210         */
211        public SimpleSignal getContinuum() {
212            SimpleSignal continuum = new SimpleSignal(getSmoothedSignal());
213            SimpleSignal flattenedSignal = new SimpleSignal(signal.size());
214            for (int iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
215                SimpleSignal.subtract(signal, continuum, flattenedSignal);  
216                SimpleWaveletSpace simpleWaveletSpace = new SimpleWaveletSpace(flattenedSignal);
217                continuum.add(simpleWaveletSpace.getSmoothedSignal());
218            }
219            return continuum;
220        }
221    
222        /** 
223         * Get the last smoothed array as computed by the atrous wavelet transform.
224         * @return the last smoothed array as a simple signal
225         */
226        public SimpleSignal getSmoothedSignal() {
227            return smoothedSignal;
228        }
229    }