001    package util.wavelet;
002    import java.util.List;
003    import static java.lang.Math.*;
004    
005    /** A wavelet scale containing wavelet coefficients.
006     * @author John Talbot
007     */
008    public class Scale extends Signal {
009       
010        /** The scale number. Higher numbers indicate smoother scales. */
011        int scaleNumber;
012      
013        /** A lookup table for efficiently accessing the Structure at a given index, if -1 then no structure*/
014        protected int[] structureLookupTable;
015    
016        /** Structures in this level. */
017        public java.util.List<Structure> structures;  // LAZY evaluation if a threshold is given in constructor, null otherwise
018           
019        /** If true only positive features are detected. */
020        public static final boolean POSITIVE = true;
021    
022        /** 
023         * Construct using an array of wavelet coefficients and an array of noise values encoded
024         * as an instance of signal.
025         *
026         * @param   signal  a {@link SimpleSignal}
027         */
028        public Scale(SimpleSignal signal, int scaleNumber) {
029            super(signal);
030            this.scaleNumber = scaleNumber;
031        }
032    
033        /** 
034         * Find the {@link Structure} instances defined as a contiguous set of wavelet coefficients above noise.
035         *
036         * @return   a list of Structure instances
037         */
038        void findStructures() {
039            if (structures != null) return;
040            structures = new java.util.ArrayList<Structure>(16);
041            structureLookupTable = new int[size()];
042            int currentLabel = 0;
043            int start = 0;
044            boolean inStructure = false;
045            for (int i = 0; i < size(); i++) {
046                if ( POSITIVE && isAboveNoise(i) || !POSITIVE && isBelowNoise(i)) {
047                    structureLookupTable[i] = currentLabel;
048                    if (!inStructure) {
049                        inStructure = true;
050                        start = i;
051                    }
052                } else {
053                    structureLookupTable[i] = NOISE;  // flag this position as noise
054                    if (inStructure) {
055                        inStructure = false;    
056                        structures.add(new Structure(this, start, i)); // 'end' defined as one more than the actual end
057                        currentLabel++;
058                    }                  
059                }
060            }
061        }
062    
063        static final int NOISE = -1;
064        
065        /** 
066         * Get the {@link Structure} at the given pixel position or null if none exists there.
067         *
068         * @param   position    pixel position
069         * @return   the {@link Structure} at the given position or null if none exists there
070         */    
071        public Structure getStructure(int position) {
072            if (structures == null) findStructures();   // LAZY evaluation
073            if (structureLookupTable[position] == NOISE )
074                return null;
075            else
076                return getStructures().get(structureLookupTable[position]);
077        }
078    
079        /** 
080         * Get the Structures.
081         * @return a list of Structures found in this scale
082         */
083        public java.util.List<Structure> getStructures() {
084            if (structures == null) findStructures();
085            return structures;
086        }
087    
088        /** 
089         * Get the wavelet coefficient value at the given position and for the given {@link WObject}, zero otherwise.
090         * Precondition : 0 &ge; <code>index</code> &le; size().
091         *
092         * @param   position     must be within the wavelet coefficients of this Scale
093         * @param   wObjectIndex WObject index 
094         * @return   the wavelet coefficient value at the given position    
095         */    
096    
097        public float getValue(int position, int wObjectIndex) {
098            
099            // TODO :
100            /*
101            Structure structure = getStructure(position);
102            if (structure != null && structure.wObject == index)
103                return getValue(position);
104            else
105                return 0f;            
106            */
107            return getValue(position);   // XXX: incorrect
108        }
109    
110        /** 
111         * If this scale contains Structures which belong to a given WObject then
112         * add those wavelet coefficients to a given signal and return results in that signal.
113         * Precondition: signal has the same size
114         *
115         * @param signal the signal to be added to this scale
116         * @param index the object index to
117         */
118        public void add(SimpleSignal signal, int index) {        
119            for (int i = 0; i < size(); i++)
120                signal.setValue(i, getValue(i) + signal.getValue(i));
121        }
122    
123        /** 
124         * Get the scale number. Higher numbers indicate smoother scales. 
125         * Useful for checking purposes, such as verifying that a Structure
126         * is related to another structure plus or minus a scale number etc...
127         *
128         * @return the scale number (starts at 0)
129         */
130        public int getScaleNumber() {
131            return scaleNumber;
132        }
133    
134    }