001/*
002 * $RCSfile: SubbandAn.java,v $
003 * $Revision: 1.1 $
004 * $Date: 2005/02/11 05:02:31 $
005 * $State: Exp $
006 *
007 * Class:                   SubbandAn
008 *
009 * Description:             Element for a tree structure for a descripotion
010 *                          of subbands on the anslysis side.
011 *
012 *
013 *
014 * COPYRIGHT:
015 *
016 * This software module was originally developed by Raphaël Grosbois and
017 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
018 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
019 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
020 * Centre France S.A) in the course of development of the JPEG2000
021 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
022 * software module is an implementation of a part of the JPEG 2000
023 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
024 * Systems AB and Canon Research Centre France S.A (collectively JJ2000
025 * Partners) agree not to assert against ISO/IEC and users of the JPEG
026 * 2000 Standard (Users) any of their rights under the copyright, not
027 * including other intellectual property rights, for this software module
028 * with respect to the usage by ISO/IEC and Users of this software module
029 * or modifications thereof for use in hardware or software products
030 * claiming conformance to the JPEG 2000 Standard. Those intending to use
031 * this software module in hardware or software products are advised that
032 * their use may infringe existing patents. The original developers of
033 * this software module, JJ2000 Partners and ISO/IEC assume no liability
034 * for use of this software module or modifications thereof. No license
035 * or right to this software module is granted for non JPEG 2000 Standard
036 * conforming products. JJ2000 Partners have full right to use this
037 * software module for his/her own purpose, assign or donate this
038 * software module to any third party and to inhibit third parties from
039 * using this software module for non JPEG 2000 Standard conforming
040 * products. This copyright notice must be included in all copies or
041 * derivative works of this software module.
042 *
043 * Copyright (c) 1999/2000 JJ2000 Partners.
044 *
045 *
046 *
047 */
048
049
050package jj2000.j2k.wavelet.analysis;
051
052import jj2000.j2k.wavelet.*;
053
054/**
055 * This class represents a subband in a bidirectional tree structure
056 * that describes the subband decomposition for a wavelet transform,
057 * specifically for the analysis side.
058 *
059 * <P>The element can be either a node or a leaf of the tree. If it is
060 * a node then ther are 4 descendants (LL, HL, LH and HH). If it is a
061 * leaf there are no descendants.
062 *
063 * <P>The tree is bidirectional. Each element in the tree structure
064 * has a "parent", which is the subband from which the element was
065 * obtained by decomposition. The only exception is the root element
066 * which has no parent (i.e.it's null), for obvious reasons.
067 * */
068public class SubbandAn extends Subband {
069
070    /**
071     * The reference to the parent of this subband. It is null for the
072     * root element. It is null by default.  */
073    public SubbandAn parent = null;
074
075    /**
076     * The reference to the LL subband resulting from the
077     * decomposition of this subband. It is null by default.  */
078    public SubbandAn subb_LL;
079
080    /**
081     * The reference to the HL subband (horizontal high-pass)
082     * resulting from the decomposition of this subband. It is null by
083     * default.  */
084    public SubbandAn subb_HL;
085
086    /**
087     * The reference to the LH subband (vertical high-pass) resulting
088     * from the decomposition of this subband. It is null by default.
089     * */
090    public SubbandAn subb_LH;
091
092    /**
093     * The reference to the HH subband resulting from the
094     * decomposition of this subband. It is null by default.
095     */
096    public SubbandAn subb_HH;
097
098    /** The horizontal analysis filter used to decompose this
099        subband. This is applicable to "node" elements only. The
100        default value is null. */
101    public AnWTFilter hFilter;
102
103    /** The vertical analysis filter used to decompose this
104        subband. This is applicable to "node" elements only. The
105        default value is null. */
106    public AnWTFilter vFilter;
107
108    /**
109     * The L2-norm of the synthesis basis waveform of this subband,
110     * applicable to "leafs" only. By default it is -1 (i.e. not
111     * calculated yet).
112     * */
113    public float l2Norm = -1.0f;
114
115    /**
116     * The contribution to the MSE or WMSE error that would result in the
117     * image if there was an error of exactly one quantization step size in
118     * the sample of the subband. This value is expressed relative to a
119     * nominal dynamic range in the image domain of exactly 1.0. This field
120     * contains valid data only after quantization 9See Quantizer).
121     *
122     * @see jj2000.j2k.quantization.quantizer.Quantizer
123     * */
124    public float stepWMSE;
125
126    /**
127     * Creates a SubbandAn element with all the default values. The
128     * dimensions are (0,0) and the upper left corner is (0,0).
129     *
130     *
131     * */
132    public SubbandAn() {
133    }
134
135    /**
136     * Creates the top-level node and the entire subband tree, with
137     * the top-level dimensions, the number of decompositions, and the
138     * decomposition tree as specified.
139     *
140     * <P>This constructor just calls the same constructor of the
141     * super class, and then calculates the L2-norm (or energy weight)
142     * of each leaf.
143     *
144     * <P>This constructor does not initialize the value of the magBits or
145     * stepWMSE member variables. This variables are normally initialized by
146     * the quantizer (see Quantizer).
147     *
148     * @param w The top-level width
149     *
150     * @param h The top-level height
151     *
152     * @param ulcx The horizontal coordinate of the upper-left corner with
153     * respect to the canvas origin, in the component grid.
154     *
155     * @param ulcy The vertical  coordinate of the upper-left corner with
156     * respect to the canvas origin, in the component grid.
157     *
158     * @param lvls The number of levels (or LL decompositions) in the
159     * tree.
160     *
161     * @param hfilters The horizontal wavelet analysis filters for each
162     * resolution level, starting at resolution level 0.
163     *
164     * @param vfilters The vertical wavelet analysis filters for each
165     * resolution level, starting at resolution level 0.
166     *
167     * @see Subband#Subband(int,int,int,int,int,
168     * WaveletFilter[],WaveletFilter[])
169     *
170     * @see jj2000.j2k.quantization.quantizer.Quantizer
171     *
172     *
173     * */
174    public SubbandAn(int w, int h, int ulcx, int ulcy, int lvls,
175                     WaveletFilter hfilters[], WaveletFilter vfilters[]) {
176        super(w,h,ulcx,ulcy,lvls,hfilters,vfilters);
177        // Caculate the L2-norms
178        calcL2Norms();
179    }
180
181    /**
182     * Returns the parent of this subband. The parent of a subband is
183     * the subband from which this one was obtained by
184     * decomposition. The root element has no parent subband (null).
185     *
186     * @return The parent subband, or null for the root one.
187     *
188     *
189     * */
190    public Subband getParent() {
191        return parent;
192    }
193
194    /**
195     * Returns the LL child subband of this subband.
196     *
197     * @return The LL child subband, or null if there are no childs.
198     *
199     *
200     * */
201    public Subband getLL() {
202        return subb_LL;
203    }
204
205    /**
206     * Returns the HL (horizontal high-pass) child subband of this
207     * subband.
208     *
209     * @return The HL child subband, or null if there are no childs.
210     *
211     *
212     * */
213    public Subband getHL() {
214        return subb_HL;
215    }
216
217    /**
218     * Returns the LH (vertical high-pass) child subband of this
219     * subband.
220     *
221     * @return The LH child subband, or null if there are no childs.
222     *
223     *
224     * */
225    public Subband getLH() {
226        return subb_LH;
227    }
228
229    /**
230     * Returns the HH child subband of this subband.
231     *
232     * @return The HH child subband, or null if there are no childs.
233     *
234     *
235     * */
236    public Subband getHH() {
237        return subb_HH;
238    }
239
240    /**
241     * Splits the current subband in its four subbands. It changes the
242     * status of this element (from a leaf to a node, and sets the
243     * filters), creates the childs and initializes them. An
244     * IllegalArgumentException is thrown if this subband is not a
245     * leaf.
246     *
247     * <P>It uses the initChilds() method to initialize the childs.
248     *
249     * @param hfilter The horizontal wavelet filter used to decompose
250     * this subband. It has to be a AnWTFilter object.
251     *
252     * @param vfilter The vertical wavelet filter used to decompose this
253     * subband. It has to be a AnWTFilter object.
254     *
255     * @return  A reference to the LL leaf (subb_LL).
256     *
257     * @see Subband#initChilds
258     *
259     *
260     * */
261    protected Subband split(WaveletFilter hfilter, WaveletFilter vfilter) {
262        // Test that this is a node
263        if (isNode) {
264            throw new IllegalArgumentException();
265        }
266
267        // Modify this element into a node and set the filters
268        isNode = true;
269        this.hFilter = (AnWTFilter) hfilter;
270        this.vFilter = (AnWTFilter) vfilter;
271
272        // Create childs
273        subb_LL = new SubbandAn();
274        subb_LH = new SubbandAn();
275        subb_HL = new SubbandAn();
276        subb_HH = new SubbandAn();
277
278        // Assign parent
279        subb_LL.parent = this;
280        subb_HL.parent = this;
281        subb_LH.parent = this;
282        subb_HH.parent = this;
283
284        // Initialize childs
285        initChilds();
286
287        // Return reference to LL subband
288        return subb_LL;
289    }
290
291    /**
292     * Calculates the basis waveform of the first leaf for which the
293     * L2-norm has not been calculated yet. This method searches
294     * recursively for the first leaf for which the value has not been
295     * calculated yet, and then calculates the L2-norm on the return
296     * path.
297     *
298     * <P>The wfs argument should be a size 2 array of float arrays
299     * (i.e. 2D array) and it must be of length 2 (or more). When
300     * returning, wfs[0] will contain the line waveform, and wfs[1]
301     * will contain the column waveform.
302     *
303     * <P>This method can not be called on an element that ahs a
304     * non-negative value in l2Norm, since that means that we are
305     * done.
306     *
307     * @param wfs An size 2 array where the line and column waveforms
308     * will be returned.
309     *
310     *
311     * */
312    private void calcBasisWaveForms(float wfs[][]) {
313        if (l2Norm < 0) {
314            // We are not finished with this element yet
315            if (isNode) {
316                // We are on a node => search on childs
317                if (subb_LL.l2Norm < 0f) {
318                    subb_LL.calcBasisWaveForms(wfs);
319                    wfs[0] =
320                        hFilter.getLPSynWaveForm(wfs[0],null);
321                    wfs[1] =
322                        vFilter.getLPSynWaveForm(wfs[1],null);
323                }
324                else if (subb_HL.l2Norm < 0f) {
325                    subb_HL.calcBasisWaveForms(wfs);
326                    wfs[0] =
327                        hFilter.getHPSynWaveForm(wfs[0],null);
328                    wfs[1] =
329                        vFilter.getLPSynWaveForm(wfs[1],null);
330                }
331                else if (subb_LH.l2Norm < 0f) {
332                    subb_LH.calcBasisWaveForms(wfs);
333                    wfs[0] =
334                        hFilter.getLPSynWaveForm(wfs[0],null);
335                    wfs[1] =
336                        vFilter.getHPSynWaveForm(wfs[1],null);
337                }
338                else if (subb_HH.l2Norm < 0f) {
339                    subb_HH.calcBasisWaveForms(wfs);
340                    wfs[0] =
341                        hFilter.getHPSynWaveForm(wfs[0],null);
342                    wfs[1] =
343                        vFilter.getHPSynWaveForm(wfs[1],null);
344                }
345                else {
346                    // There is an error! If all childs have
347                    // non-negative l2norm, then this node should have
348                    // non-negative l2norm
349                    throw new Error("You have found a bug in JJ2000!");
350                }
351            }
352            else {
353                // This is a leaf, just use diracs (null is
354                // equivalent to dirac)
355                wfs[0] = new float[1];
356                wfs[0][0] = 1.0f;
357                wfs[1] = new float[1];
358                wfs[1][0] = 1.0f;
359            }
360
361        }
362        else {
363            // This is an error! The calcBasisWaveForms() method is
364            // never called on an element with non-negative l2norm
365            throw new Error("You have found a bug in JJ2000!");
366        }
367    }
368
369    /**
370     * Assigns the given L2-norm to the first leaf that does not have
371     * an L2-norm value yet (i.e. l2norm is negative). The search is
372     * done recursively and in the same order as that of the
373     * calcBasisWaveForms() method, so that this method is used to
374     * assigne the l2norm of the previously computed waveforms.
375     *
376     * <P>This method can not be called on an element that ahs a
377     * non-negative value in l2Norm, since that means that we are
378     * done.
379     *
380     * @param l2n The L2-norm to assign.
381     *
382     *
383     * */
384    private void assignL2Norm(float l2n) {
385        if (l2Norm < 0) {
386            // We are not finished with this element yet
387            if (isNode) {
388                // We are on a node => search on childs
389                if (subb_LL.l2Norm < 0f) {
390                    subb_LL.assignL2Norm(l2n);
391                }
392                else if (subb_HL.l2Norm < 0f) {
393                    subb_HL.assignL2Norm(l2n);
394                }
395                else if (subb_LH.l2Norm < 0f) {
396                    subb_LH.assignL2Norm(l2n);
397                }
398                else if (subb_HH.l2Norm < 0f) {
399                    subb_HH.assignL2Norm(l2n);
400                    // If child now is done, we are done
401                    if (subb_HH.l2Norm >= 0f) {
402                        l2Norm = 0f; // We are on a node, any non-neg value OK
403                    }
404                }
405                else {
406                    // There is an error! If all childs have
407                    // non-negative l2norm, then this node should have
408                    // non-negative l2norm
409                    throw new Error("You have found a bug in JJ2000!");
410                }
411            }
412            else {
413                // This is a leaf, assign the L2-norm
414                l2Norm = l2n;
415            }
416
417        }
418        else {
419            // This is an error! The assignL2Norm() method is
420            // never called on an element with non-negative l2norm
421            throw new Error("You have found a bug in JJ2000!");
422        }
423    }
424
425
426    /**
427     * Calculates the L2-norm of the sythesis waveforms of every leaf
428     * in the tree. This method should only be called on the root
429     * element.
430     *
431     *
432     * */
433    private void calcL2Norms() {
434        int i;
435        float wfs[][] = new float[2][];
436        double acc;
437        float l2n;
438
439        // While we are not done on the root element, compute basis
440        // functions and assign L2-norm
441        while (l2Norm < 0f) {
442            calcBasisWaveForms(wfs);
443            // Compute line L2-norm, which is the product of the line
444            // and column L2-norms
445            acc = 0.0;
446            for (i=wfs[0].length-1; i>=0; i--) {
447                acc += wfs[0][i]*wfs[0][i];
448            }
449            l2n = (float) Math.sqrt(acc);
450            // Compute column L2-norm
451            acc = 0.0;
452            for (i=wfs[1].length-1; i>=0; i--) {
453                acc += wfs[1][i]*wfs[1][i];
454            }
455            l2n *= (float) Math.sqrt(acc);
456            // Release waveforms
457            wfs[0] = null;
458            wfs[1] = null;
459            // Assign the value
460            assignL2Norm(l2n);
461        }
462    }
463
464    /**
465     * This function returns the horizontal wavelet filter relevant to this
466     * subband
467     *
468     * @return The horizontal wavelet filter
469     *
470     *
471     */
472    public WaveletFilter getHorWFilter(){
473        return hFilter;
474    }
475
476    /**
477     * This function returns the vertical wavelet filter relevant to this
478     * subband
479     *
480     * @return The vertical wavelet filter
481     *
482     *
483     */
484    public WaveletFilter getVerWFilter(){
485        return hFilter;
486    }
487}