001/*
002 *
003 * $RCSfile: Subband.java,v $
004 * $Revision: 1.1 $
005 * $Date: 2005/02/11 05:02:27 $
006 * $State: Exp $
007 *
008 * Class:                   Subband
009 *
010 * Description:             Asbtract element for a tree strcuture for
011 *                          a description of subbands.
012 *
013 *
014 *
015 * COPYRIGHT:
016 *
017 * This software module was originally developed by Raphaël Grosbois and
018 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
019 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
020 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
021 * Centre France S.A) in the course of development of the JPEG2000
022 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
023 * software module is an implementation of a part of the JPEG 2000
024 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
025 * Systems AB and Canon Research Centre France S.A (collectively JJ2000
026 * Partners) agree not to assert against ISO/IEC and users of the JPEG
027 * 2000 Standard (Users) any of their rights under the copyright, not
028 * including other intellectual property rights, for this software module
029 * with respect to the usage by ISO/IEC and Users of this software module
030 * or modifications thereof for use in hardware or software products
031 * claiming conformance to the JPEG 2000 Standard. Those intending to use
032 * this software module in hardware or software products are advised that
033 * their use may infringe existing patents. The original developers of
034 * this software module, JJ2000 Partners and ISO/IEC assume no liability
035 * for use of this software module or modifications thereof. No license
036 * or right to this software module is granted for non JPEG 2000 Standard
037 * conforming products. JJ2000 Partners have full right to use this
038 * software module for his/her own purpose, assign or donate this
039 * software module to any third party and to inhibit third parties from
040 * using this software module for non JPEG 2000 Standard conforming
041 * products. This copyright notice must be included in all copies or
042 * derivative works of this software module.
043 *
044 * Copyright (c) 1999/2000 JJ2000 Partners.
045 *  */
046package jj2000.j2k.wavelet;
047
048import java.awt.Point;
049
050/**
051 * This abstract class represents a subband in a bidirectional tree structure
052 * that describes the subband decomposition for a wavelet transform. This
053 * class is implemented by the SubbandAn and SubbandSyn classes, which are for
054 * the analysis and synthesis sides, respectively.
055 *
056 * <P>The element can be either a node or a leaf of the tree. If it is a node
057 * then ther are 4 descendants (LL, HL, LH and HH). If it is a leaf ther are
058 * no descendants.
059 *
060 * <P>The tree is bidirectional. Each element in the tree structure has a
061 * "parent", which is the subband from which the element was obtained by
062 * decomposition. The only exception is the root element which has no parent
063 * (i.e.it's null), for obvious reasons.
064 *
065 * @see jj2000.j2k.wavelet.analysis.SubbandAn
066 * @see jj2000.j2k.wavelet.synthesis.SubbandSyn
067 * */
068public abstract class Subband {
069
070    /** The ID for the LL orientation */
071    public final static int WT_ORIENT_LL = 0;
072
073    /** The ID for the HL (horizontal high-pass) orientation */
074    public final static int WT_ORIENT_HL = 1;
075
076    /** The ID for the LH (vertical high-pass) orientation */
077    public final static int WT_ORIENT_LH = 2;
078
079    /** The ID for the HH orientation */
080    public final static int WT_ORIENT_HH = 3;
081
082    /**
083     * True if it is a node in the tree, false if it is a leaf. False by
084     * default.  */
085    public boolean isNode;
086
087    /**
088     * The orientation of this subband (WT_ORIENT_LL, WT_ORIENT_HL,
089     * WT_ORIENT_LH, WT_ORIENT_HH). It is WT_ORIENT_LL by default. The
090     * orientation of the top-level node (i.e. the full image before any
091     * decomposition) is WT_ORIENT_LL.  */
092    // The default value is always 0, which is WT_ORIENT_LL.
093    public int orientation;
094
095    /**
096     * The level in the tree to which this subband belongs, which is the
097     * number of wavelet decompositions performed to produce this subband. It
098     * is 0 for the top-level (i.e. root) node. It is 0 by default.
099     * */
100    public int level;
101
102    /**
103     * The resolution level to which this subband contributes. Level 0 is the
104     * smallest resolution level (the one with the lowest frequency LL
105     * subband). It is 0 by default.
106     * */
107    public int resLvl;
108
109    /** The number of code-blocks (in both directions) contained in this
110     * subband.  */
111    public Point numCb = null;
112
113    /**
114     * The base 2 exponent of the analysis gain of the subband. The analysis
115     * gain of a subband is defined as the gain of the previous subband
116     * (i.e. the one from which this one was obtained) multiplied by the line
117     * gain and by the column gain. The line (column) gain is the gain of the
118     * line (column) filter that was used to obtain it, which is the DC gain
119     * for a low-pass filter and the Nyquist gain for a high-pass filter. It
120     * is 0 by default.
121     *
122     * <P>Using the base 2 exponent of the value contrains the possible gains
123     * to powers of 2. However this is perfectly compatible to the filter
124     * normalization policy assumed here. See the split() method for more
125     * details.
126     *
127     * @see #split
128     * */
129    public int anGainExp;
130
131    /**
132     * The subband index within its resolution level. This value uniquely
133     * identifies a subband within a resolution level and a decomposition
134     * level within it. Note that only leaf elements represent "real"
135     * subbands, while node elements represent only intermediate stages.
136     *
137     * <P>It is defined recursively. The root node gets a value of 0. For a
138     * given node, with a subband index 'b', its LL descendant gets 4*b, its
139     * HL descendant 4*b+1, its LH descendant 4*b+2, and its HH descendant
140     * 4*b+3, for their subband indexes.
141     * */
142    public int sbandIdx = 0;
143
144    /**
145     * The horizontal coordinate of the upper-left corner of the subband, with
146     * respect to the canvas origin, in the component's grid and subband's
147     * decomposition level. This is the real horizontal index of the first
148     * column of this subband. If even the horizontal decomposition of this
149     * subband should be done with the low-pass-first convention. If odd it
150     * should be done with the high-pass-first convention.
151     * */
152    public int ulcx;
153
154    /**
155     * The vertical coordinate of the upper-left corner of the subband, with
156     * respect to the canvas origin, in the component's grid and subband's
157     * decomposition level. This is the real vertical index of the first
158     * column of this subband. If even the vertical decomposition of this
159     * subband should be done with the low-pass-first convention. If odd it
160     * should be done with the high-pass-first convention.
161     * */
162    public int ulcy;
163
164    /** The horizontal coordinate of the upper-left corner of the subband */
165    public int ulx;
166
167    /** The vertical coordinate of the upper-left corner of the subband */
168    public int uly;
169
170    /** The width of the subband */
171    public int w;
172
173    /** The height of the subband */
174    public int h;
175
176    /** The nominal code-block width */
177    public int nomCBlkW;
178
179    /** The nominal code-block height */
180    public int nomCBlkH;
181
182    /**
183     * Returns the parent of this subband. The parent of a subband is the
184     * subband from which this one was obtained by decomposition. The root
185     * element has no parent subband (null).
186     *
187     * @return The parent subband, or null for the root one.
188     * */
189    public abstract Subband getParent();
190
191    /**
192     * Returns the LL child subband of this subband.
193     *
194     * @return The LL child subband, or null if there are no childs.
195     * */
196    public abstract Subband getLL();
197
198    /**
199     * Returns the HL (horizontal high-pass) child subband of this subband.
200     *
201     * @return The HL child subband, or null if there are no childs.
202     * */
203    public abstract Subband getHL();
204
205    /**
206     * Returns the LH (vertical high-pass) child subband of this subband.
207     *
208     * @return The LH child subband, or null if there are no childs.
209     * */
210    public abstract Subband getLH();
211
212    /**
213     * Returns the HH child subband of this subband.
214     *
215     * @return The HH child subband, or null if there are no childs.
216     * */
217    public abstract Subband getHH();
218
219    /**
220     * Splits the current subband in its four subbands. This creates the four
221     * childs (LL, HL, LH and HH) and converts the leaf in a node.
222     *
223     * @param hfilter The horizontal wavelet filter used to decompose this
224     * subband.
225     *
226     * @param vfilter The vertical wavelet filter used to decompose this
227     * subband.
228     *
229     * @return  A reference to the LL leaf (getLL()).
230     * */
231    protected abstract Subband split(WaveletFilter hfilter,
232                                     WaveletFilter vfilter);
233
234    /**
235     * Initializes the childs of this node with the correct values. The sizes
236     * of the child subbands are calculated by taking into account the
237     * position of the subband in the canvas.
238     *
239     * <P>For the analysis subband gain calculation it is assumed that
240     * analysis filters are normalized with a DC gain of 1 and a Nyquist gain
241     * of 2.
242     * */
243    protected void initChilds() {
244        Subband subb_LL = getLL();
245        Subband subb_HL = getHL();
246        Subband subb_LH = getLH();
247        Subband subb_HH = getHH();
248
249        // LL subband
250        subb_LL.level = level+1;
251        subb_LL.ulcx = (ulcx+1)>>1;
252        subb_LL.ulcy = (ulcy+1)>>1;
253        subb_LL.ulx = ulx;
254        subb_LL.uly = uly;
255        subb_LL.w = ((ulcx+w+1)>>1)-subb_LL.ulcx;
256        subb_LL.h = ((ulcy+h+1)>>1)-subb_LL.ulcy;
257        // If this subband in in the all LL path (i.e. it's global orientation
258        // is LL) then child LL band contributes to a lower resolution level.
259        subb_LL.resLvl = (orientation == WT_ORIENT_LL) ? resLvl-1 : resLvl;
260        subb_LL.anGainExp = anGainExp;
261        subb_LL.sbandIdx = (sbandIdx<<2);
262        // HL subband
263        subb_HL.orientation = WT_ORIENT_HL;
264        subb_HL.level = subb_LL.level;
265        subb_HL.ulcx = ulcx>>1;
266        subb_HL.ulcy = subb_LL.ulcy;
267        subb_HL.ulx = ulx + subb_LL.w;
268        subb_HL.uly = uly;
269        subb_HL.w = ((ulcx+w)>>1)-subb_HL.ulcx;
270        subb_HL.h = subb_LL.h;
271        subb_HL.resLvl = resLvl;
272        subb_HL.anGainExp = anGainExp+1;
273        subb_HL.sbandIdx = (sbandIdx<<2)+1;
274        // LH subband
275        subb_LH.orientation = WT_ORIENT_LH;
276        subb_LH.level = subb_LL.level;
277        subb_LH.ulcx = subb_LL.ulcx;
278        subb_LH.ulcy = ulcy>>1;
279        subb_LH.ulx = ulx;
280        subb_LH.uly = uly + subb_LL.h;
281        subb_LH.w = subb_LL.w;
282        subb_LH.h = ((ulcy+h)>>1)-subb_LH.ulcy;
283        subb_LH.resLvl = resLvl;
284        subb_LH.anGainExp = anGainExp+1;
285        subb_LH.sbandIdx = (sbandIdx<<2)+2;
286        // HH subband
287        subb_HH.orientation = WT_ORIENT_HH;
288        subb_HH.level = subb_LL.level;
289        subb_HH.ulcx = subb_HL.ulcx;
290        subb_HH.ulcy = subb_LH.ulcy;
291        subb_HH.ulx = subb_HL.ulx;
292        subb_HH.uly = subb_LH.uly;
293        subb_HH.w = subb_HL.w;
294        subb_HH.h = subb_LH.h;
295        subb_HH.resLvl = resLvl;
296        subb_HH.anGainExp = anGainExp+2;
297        subb_HH.sbandIdx = (sbandIdx<<2)+3;
298    }
299
300    /**
301     * Creates a Subband element with all the default values. The dimensions
302     * are (0,0), the upper left corner is (0,0) and the upper-left corner
303     * with respect to the canvas is (0,0) too.
304     * */
305    public Subband() {
306    }
307
308    /**
309     * Creates the top-level node and the entire subband tree, with the
310     * top-level dimensions, the number of decompositions, and the
311     * decomposition tree as specified.
312     *
313     * <P>For the analysis subband gain calculation it is assumed that
314     * analysis filters are normalized with a DC gain of 1 and a Nyquist gain
315     * of 2.
316     *
317     * <P>This constructor does not initialize the value of the magBits member
318     * variable. This variable is normally initialized by the quantizer, on
319     * the encoder side, or the bit stream reader, on the decoder side.
320     *
321     * @param w The top-level width
322     *
323     * @param h The top-level height
324     *
325     * @param ulcx The horizontal coordinate of the upper-left corner with
326     * respect to the canvas origin, in the component grid.
327     *
328     * @param ulcy The vertical coordinate of the upper-left corner with
329     * respect to the canvas origin, in the component grid.
330     *
331     * @param lvls The number of levels (or LL decompositions) in the tree.
332     *
333     * @param hfilters The horizontal wavelet filters (analysis or synthesis)
334     * for each resolution level, starting at resolution level 0. If there are
335     * less elements in the array than there are resolution levels, the last
336     * element is used for the remaining resolution levels.
337     *
338     * @param vfilters The vertical wavelet filters (analysis or synthesis)
339     * for each resolution level, starting at resolution level 0. If there are
340     * less elements in the array than there are resolution levels, the last
341     * element is used for the remaining resolution levels.
342     *
343     * @see WaveletTransform
344     * */
345    public Subband(int w, int h, int ulcx, int ulcy, int lvls,
346                   WaveletFilter hfilters[], WaveletFilter vfilters[]) {
347        int i,hi,vi;
348        Subband cur; // The current subband
349
350        // Initialize top-level node
351        this.w = w;
352        this.h = h;
353        this.ulcx = ulcx;
354        this.ulcy = ulcy;
355        this.resLvl = lvls;
356        // First create dyadic decomposition.
357        cur = this;
358        for (i=0; i<lvls; i++) {
359            hi = (cur.resLvl <= hfilters.length) ? cur.resLvl-1 :
360                hfilters.length-1;
361            vi = (cur.resLvl <= vfilters.length) ? cur.resLvl-1 :
362                vfilters.length-1;
363            cur = cur.split(hfilters[hi],vfilters[vi]);
364        }
365    }
366
367    /**
368     * Returns the next subband in the same resolution level, following the
369     * subband index order. If already at the last subband then null is
370     * returned. If this subband is not a leaf an IllegalArgumentException is
371     * thrown.
372     *
373     * @return The next subband in the same resolution level, following the
374     * subband index order, or null if already at last subband.
375     * */
376    public Subband nextSubband() {
377        Subband sb;
378
379        if (isNode) {
380            throw new IllegalArgumentException();
381        }
382
383        switch (orientation) {
384        case WT_ORIENT_LL:
385            sb = getParent();
386            if (sb == null || sb.resLvl != resLvl) {
387                // Already at top-level or last subband in res. level
388                return null;
389            }
390            else {
391                return sb.getHL();
392            }
393        case WT_ORIENT_HL:
394            return getParent().getLH();
395        case WT_ORIENT_LH:
396            return getParent().getHH();
397        case WT_ORIENT_HH:
398            // This is the complicated one
399            sb = this;
400            while (sb.orientation == WT_ORIENT_HH) {
401                sb = sb.getParent();
402            }
403            switch (sb.orientation) {
404            case WT_ORIENT_LL:
405                sb = sb.getParent();
406                if (sb == null || sb.resLvl != resLvl) {
407                    // Already at top-level or last subband in res. level
408                    return null;
409                }
410                else {
411                    sb = sb.getHL();
412                }
413                break;
414            case WT_ORIENT_HL:
415                sb = sb.getParent().getLH();
416                break;
417            case WT_ORIENT_LH:
418                sb = sb.getParent().getHH();
419                break;
420            default:
421                throw new Error("You have found a bug in JJ2000");
422            }
423            while (sb.isNode) {
424                sb = sb.getLL();
425            }
426            return sb;
427        default:
428            throw new Error("You have found a bug in JJ2000");
429        }
430    }
431
432    /**
433     * Returns the first leaf subband element in the next higher resolution
434     * level.
435     *
436     * @return The first leaf element in the next higher resolution level, or
437     * null if there is no higher resolution level.
438     * */
439    public Subband getNextResLevel() {
440        Subband sb;
441
442        if (level == 0) { // No higher res. level
443            return null;
444        }
445        // Go up until we get to a different resolution level
446        sb = this;
447        do {
448            sb = sb.getParent();
449            if (sb == null) { // No higher resolution level
450                return null;
451            }
452        } while (sb.resLvl == resLvl);
453        // Now go down to HL, which is in next higher resolution level
454        sb = sb.getHL();
455        // Now go down LL until get to a leaf
456        while (sb.isNode) {
457            sb = sb.getLL();
458        }
459        return sb;
460    }
461
462    /**
463     * Returns a subband element in the tree, given its resolution level and
464     * subband index. This method searches through the tree.
465     *
466     * @param rl The resolution level.
467     *
468     * @param sbi The subband index, within the resolution level.
469     * */
470    public Subband getSubbandByIdx(int rl, int sbi) {
471        Subband sb = this;
472
473        // Find the root subband for the resolution level
474        if (rl>sb.resLvl || rl<0) {
475            throw new IllegalArgumentException("Resolution level index "+
476                                               "out of range");
477        }
478
479        // Returns directly if it is itself
480        if(rl==sb.resLvl && sbi==sb.sbandIdx) return sb;
481
482        if(sb.sbandIdx!=0) sb = sb.getParent();
483
484        while(sb.resLvl>rl) sb = sb.getLL();
485        while(sb.resLvl<rl) sb = sb.getParent();
486
487        switch(sbi) {
488        case 0:
489        default:
490            return sb;
491        case 1:
492            return sb.getHL();
493        case 2:
494            return sb.getLH();
495        case 3:
496            return sb.getHH();
497        }
498
499    }
500
501    /**
502     * Returns a reference to the Subband element to which the specified point
503     * belongs. The specified point must be inside this (i.e. the one defined
504     * by this object) subband. This method searches through the tree.
505     *
506     * @param x horizontal coordinate of the specified point.
507     *
508     * @param y horizontal coordinate of the specified point.
509     * */
510    public Subband getSubband(int x,int y) {
511        Subband cur,hhs;
512
513        // Check that we are inside this subband
514        if (x<ulx || y<uly || x>=ulx+w || y>=uly+h) {
515            throw new IllegalArgumentException();
516        }
517
518        cur = this;
519        while (cur.isNode) {
520            hhs = cur.getHH();
521            // While we are still at a node -> continue
522            if (x<hhs.ulx) {
523                // Is the result of horizontal low-pass
524                if (y<hhs.uly) {
525                    // Vertical low-pass
526                    cur = cur.getLL();
527                } else {
528                    // Vertical high-pass
529                    cur = cur.getLH();
530                }
531            } else {
532                // Is the result of horizontal high-pass
533                if (y<hhs.uly) {
534                    // Vertical low-pass
535                    cur = cur.getHL();
536                } else {
537                    // Vertical high-pass
538                    cur = cur.getHH();
539                }
540            }
541        }
542
543        return cur;
544    }
545
546    /**
547     * Returns subband informations in a string.
548     *
549     * @return Subband informations
550     * */
551    public String toString() {
552
553        String string =
554            "w=" + w + ", h=" + h + ", ulx=" + ulx + ", uly=" + uly +
555            ", ulcx= "+ulcx+", ulcy="+ulcy+", idx=" + sbandIdx +
556            "\norient=" + orientation + ", node=" + isNode +
557            ", level=" + level + ", resLvl=" + resLvl+ ", nomCBlkW=" +
558            nomCBlkW + ", nomCBlkH=" + nomCBlkH;
559
560        return string;
561    }
562
563    /**
564     * This function returns the horizontal wavelet filter relevant to this
565     * subband
566     *
567     * @return The horizontal wavelet filter
568     * */
569    public abstract WaveletFilter getHorWFilter();
570
571    /**
572     * This function returns the vertical wavelet filter relevant to this
573     * subband
574     *
575     * @return The vertical wavelet filter
576     * */
577    public abstract WaveletFilter getVerWFilter();
578
579
580}
581