001/*
002 * $RCSfile: CBlkRateDistStats.java,v $
003 * $Revision: 1.1 $
004 * $Date: 2005/02/11 05:02:07 $
005 * $State: Exp $
006 *
007 * Class:                   CBlkRateDistStats
008 *
009 * Description:             The coded (compressed) code-block with
010 *                          rate-distortion statistics.
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 * */
045package jj2000.j2k.entropy.encoder;
046
047import jj2000.j2k.entropy.CodedCBlk;
048import jj2000.j2k.wavelet.analysis.SubbandAn;
049
050/**
051 * This class stores coded (compressed) code-blocks with their associated
052 * rate-distortion statistics. This object should always contain all the
053 * compressed data of the code-block. It is applicable to the encoder engine
054 * only. Some data of the coded-block is stored in the super class, see
055 * CodedCBlk.
056 *
057 * <P>The rate-distortion statistics (i.e. R-D slope) is stored for valid
058 * points only. The set of valid points is determined by the entropy coder
059 * engine itself. Normally they are selected so as to lye in a convex hull,
060 * which can be achived by using the 'selectConvexHull' method of this class,
061 * but some other strategies might be employed.
062 *
063 * <P>The rate (in bytes) for each truncation point (valid or not) is stored
064 * in the 'truncRates' array. The rate of a truncation point is the total
065 * number of bytes in 'data' (see super class) that have to be decoded to
066 * reach the truncation point.
067 *
068 * <P>The slope (reduction of distortion divided by the increase in rate) at
069 * each of the valid truncation points is stored in 'truncSlopes'.
070 *
071 * <P>The index of each valid truncation point is stored in 'truncIdxs'. The
072 * index should be interpreted in the following way: a valid truncation point
073 * at position 'n' has the index 'truncIdxs[n]', the rate
074 * 'truncRates[truncIdxs[n]]' and the slope 'truncSlopes[n]'. The arrays
075 * 'truncIdxs' and 'truncRates' have at least 'nVldTrunc' elements. The
076 * 'truncRates' array has at least 'nTotTrunc' elements.
077 *
078 * <P>In addition the 'isTermPass' array contains a flag for each truncation
079 * point (valid and non-valid ones) that tells if the pass is terminated or
080 * not. If this variable is null then it means that no pass is terminated,
081 * except the last one which always is.
082 *
083 * <P>The compressed data is stored in the 'data' member variable of the super
084 * class.
085 *
086 * @see CodedCBlk
087 * */
088public class CBlkRateDistStats extends CodedCBlk {
089
090    /** The subband to which the code-block belongs */
091    public SubbandAn sb;
092
093    /** The total number of truncation points */
094    public int nTotTrunc;
095
096    /** The number of valid truncation points */
097    public int nVldTrunc;
098
099    /** The rate (in bytes) for each truncation point (valid and non-valid
100     * ones) */
101    public int truncRates[];
102
103    /** The distortion for each truncation point (valid and non-valid ones) */
104    public double truncDists[];
105
106    /** The negative of the rate-distortion slope for each valid truncation
107        point */
108    public float truncSlopes[];
109
110    /** The indices of the valid truncation points, in increasing
111     * order. */
112    public int truncIdxs[];
113
114    /** Array of flags indicating terminated passes (valid or non-valid
115     * truncation points). */
116    public boolean isTermPass[];
117
118    /** The number of ROI coefficients in the code-block */
119    public int nROIcoeff = 0;
120
121    /** Number of ROI coding passes */
122    public int nROIcp = 0;
123
124    /**
125     * Creates a new CBlkRateDistStats object without allocating any space for
126     * 'truncRates', 'truncSlopes', 'truncDists' and 'truncIdxs' or 'data'.
127     * */
128    public CBlkRateDistStats() {
129    }
130
131    /**
132     * Creates a new CBlkRateDistStats object and initializes the valid
133     * truncation points, their rates and their slopes, from the 'rates' and
134     * 'dist' arrays. The 'rates', 'dist' and 'termp' arrays must contain the
135     * rate (in bytes), the reduction in distortion (from nothing coded) and
136     * the flag indicating if termination is used, respectively, for each
137     * truncation point.
138     *
139     * <P>The valid truncation points are selected by taking them as lying on
140     * a convex hull. This is done by calling the method selectConvexHull().
141     *
142     * <P> Note that the arrays 'rates' and 'termp' are copied, not
143     * referenced, so they can be modified after a call to this constructor.
144     *
145     * @param m The horizontal index of the code-block, within the subband.
146     *
147     * @param n The vertical index of the code-block, within the subband.
148     *
149     * @param skipMSBP The number of skipped most significant bit-planes for
150     * this code-block.
151     *
152     * @param data The compressed data. This array is referenced by this
153     * object so it should not be modified after.
154     *
155     * @param rates The rates (in bytes) for each truncation point in the
156     * compressed data. This array is modified by the method but no reference
157     * is kept to it.
158     *
159     * @param dists The reduction in distortion (with respect to no information
160     * coded) for each truncation point. This array is modified by the method
161     * but no reference is kept to it.
162     *
163     * @param termp An array of boolean flags indicating, for each pass, if a
164     * pass is terminated or not (true if terminated). If null then it is
165     * assumed that no pass is terminated except the last one which always is.
166     *
167     * @param np The number of truncation points contained in 'rates', 'dist'
168     * and 'termp'.
169     *
170     * @param inclast If false the convex hull is constructed as for lossy
171     * coding. If true it is constructed as for lossless coding, in which case
172     * it is ensured that all bit-planes are sent (i.e. the last truncation
173     * point is always included).
174     * */
175    public CBlkRateDistStats(int m, int n, int skipMSBP, byte data[],
176                          int rates[], double dists[], boolean termp[],
177                          int np, boolean inclast) {
178        super(m,n,skipMSBP,data);
179        selectConvexHull(rates,dists,termp,np,inclast);
180    }
181
182    /**
183     * Compute the rate-distorsion slopes and selects those that lie in a
184     * convex hull. It will compute the slopes, select the ones that form the
185     * convex hull and initialize the 'truncIdxs' and 'truncSlopes' arrays, as
186     * well as 'nVldTrunc', with the selected truncation points. It will also
187     * initialize 'truncRates' and 'isTermPass' arrays, as well as
188     * 'nTotTrunc', with all the truncation points (selected or not).
189     *
190     * <P> Note that the arrays 'rates' and 'termp' are copied, not
191     * referenced, so they can be modified after a call to this method.
192     *
193     * @param rates The rates (in bytes) for each truncation point in the
194     * compressed data. This array is modified by the method.
195     *
196     * @param dists The reduction in distortion (with respect to no
197     * information coded) for each truncation point. This array is modified by
198     * the method.
199     *
200     * @param termp An array of boolean flags indicating, for each pass, if a
201     * pass is terminated or not (true if terminated). If null then it is
202     * assumed that no pass is terminated except the last one which always is.
203     *
204     * @param n The number of truncation points contained in 'rates', 'dist'
205     * and 'termp'.
206     *
207     * @param inclast If false the convex hull is constructed as for lossy
208     * coding. If true it is constructed as for lossless coding, in which case
209     * it is ensured that all bit-planes are sent (i.e. the last truncation
210     * point is always included).
211     * */
212    public void selectConvexHull(int rates[], double dists[], boolean termp[],
213                                 int n, boolean inclast) {
214        int first_pnt;    // The first point containing some coded data
215        int p;            // last selected point
216        int k;            // current point
217        int i;            // current valid point
218        int npnt;         // number of selected (i.e. valid) points
219        int delta_rate;   // Rate difference
220        double delta_dist; // Distortion difference
221        float k_slope;    // R-D slope for the current point
222        float p_slope;    // R-D slope for the last selected point
223        int ll_rate;      // Rate for "lossless" coding (i.e. all coded info)
224
225        // Convention: when a negative value is stored in 'rates' it meas an
226        // invalid point. The absolute value is always the rate for that point.
227
228        // Look for first point with some coded info (rate not 0)
229        first_pnt = 0;
230        while (first_pnt < n && rates[first_pnt] <= 0) {
231            first_pnt++;
232        }
233
234        // Select the valid points
235        npnt = n-first_pnt;
236        p_slope = 0f; // To keep compiler happy
237ploop:
238        do {
239            p = -1;
240            for (k=first_pnt; k<n; k++) {
241                if (rates[k] < 0) { // Already invalidated point
242                    continue;
243                }
244                // Calculate decrease in distortion and rate
245                if (p >= 0) {
246                    delta_rate = rates[k]-rates[p];
247                    delta_dist = dists[k]-dists[p];
248                }
249                else { // This is with respect to no info coded
250                    delta_rate = rates[k];
251                    delta_dist = dists[k];
252                }
253                // If exactly same distortion don't eliminate if the rates are
254                // equal, otherwise it can lead to infinite slope in lossless
255                // coding.
256                if (delta_dist < 0f || (delta_dist == 0f && delta_rate > 0)) {
257                    // This point increases distortion => invalidate
258                    rates[k] = -rates[k];
259                    npnt--;
260                    continue; // Goto next point
261                }
262                k_slope = (float)(delta_dist/delta_rate);
263                // Check that there is a decrease in distortion, slope is not
264                // infinite (i.e. delta_dist is not 0) and slope is
265                // decreasing.
266                if (p>=0 &&
267                    (delta_rate <= 0 || k_slope >= p_slope )) {
268                    // Last point was not good
269                    rates[p] = -rates[p]; // Remove p from valid points
270                    npnt--;
271                    continue ploop; // Restart from the first one
272                }
273                else {
274                    p_slope = k_slope;
275                    p = k;
276                }
277            }
278            // If we get to last point we are done
279            break;
280        } while (true); // We end the loop with the break statement
281
282        // If in lossless mode make sure we don't eliminate any last bit-planes
283        // from being sent.
284        if (inclast && n > 0 && rates[n-1] < 0) {
285            rates[n-1] = -rates[n-1];
286            // This rate can never be equal to any previous selected rate,
287            // given the selection algorithm above, so no problem arises of
288            // infinite slopes.
289            npnt++;
290        }
291
292        // Initialize the arrays of this object
293        nTotTrunc = n;
294        nVldTrunc = npnt;
295        truncRates = new int[n];
296        truncDists = new double[n];
297        truncSlopes = new float[npnt];
298        truncIdxs = new int[npnt];
299        if (termp != null) {
300            isTermPass = new boolean[n];
301            System.arraycopy(termp,0,isTermPass,0,n);
302        }
303        else {
304            isTermPass = null;
305        }
306        System.arraycopy(rates,0,truncRates,0,n);
307        for (k=first_pnt, p=-1, i=0; k<n; k++) {
308            if (rates[k]>0) { // A valid point
309                truncDists[k] = dists[k];
310                if (p<0) { // Only arrives at first valid point
311                    truncSlopes[i] = (float)(dists[k]/rates[k]);
312                }
313                else {
314                    truncSlopes[i] = (float)((dists[k]-dists[p])/
315                                             (rates[k]-rates[p]));
316                }
317                truncIdxs[i] = k;
318                i++;
319                p = k;
320            }
321            else {
322                truncDists[k] = -1;
323                truncRates[k] = -truncRates[k];
324            }
325        }
326    }
327
328    /**
329     * Returns the contents of the object in a string. This is used for
330     * debugging.
331     *
332     * @return A string with the contents of the object
333     * */
334    public String toString() {
335        return super.toString() +
336            "\n nVldTrunc = "+nVldTrunc+", nTotTrunc="+nTotTrunc+", num. ROI"+
337            " coeff="+nROIcoeff+", num. ROI coding passes="+nROIcp;
338    }
339}