001: /*
002: * $RCSfile: StdDequantizer.java,v $
003: * $Revision: 1.1 $
004: * $Date: 2005/02/11 05:02:19 $
005: * $State: Exp $
006: *
007: * Class: StdDequantizer
008: *
009: * Description: Scalar deadzone dequantizer that returns integers
010: * or floats.
011: * This is a merger of the ScalarDZDeqInt and
012: * ScalarDZDeqFloat classes by Joel Askelof and Diego
013: * Santa Cruz.
014: *
015: *
016: *
017: * COPYRIGHT:
018: *
019: * This software module was originally developed by Raphaël Grosbois and
020: * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
021: * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
022: * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
023: * Centre France S.A) in the course of development of the JPEG2000
024: * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
025: * software module is an implementation of a part of the JPEG 2000
026: * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
027: * Systems AB and Canon Research Centre France S.A (collectively JJ2000
028: * Partners) agree not to assert against ISO/IEC and users of the JPEG
029: * 2000 Standard (Users) any of their rights under the copyright, not
030: * including other intellectual property rights, for this software module
031: * with respect to the usage by ISO/IEC and Users of this software module
032: * or modifications thereof for use in hardware or software products
033: * claiming conformance to the JPEG 2000 Standard. Those intending to use
034: * this software module in hardware or software products are advised that
035: * their use may infringe existing patents. The original developers of
036: * this software module, JJ2000 Partners and ISO/IEC assume no liability
037: * for use of this software module or modifications thereof. No license
038: * or right to this software module is granted for non JPEG 2000 Standard
039: * conforming products. JJ2000 Partners have full right to use this
040: * software module for his/her own purpose, assign or donate this
041: * software module to any third party and to inhibit third parties from
042: * using this software module for non JPEG 2000 Standard conforming
043: * products. This copyright notice must be included in all copies or
044: * derivative works of this software module.
045: *
046: * Copyright (c) 1999/2000 JJ2000 Partners.
047: * */
048: package jj2000.j2k.quantization.dequantizer;
049:
050: import jj2000.j2k.wavelet.synthesis.*;
051: import jj2000.j2k.entropy.decoder.*;
052: import jj2000.j2k.quantization.*;
053: import jj2000.j2k.codestream.*;
054: import jj2000.j2k.entropy.*;
055: import jj2000.j2k.decoder.*;
056: import jj2000.j2k.image.*;
057: import jj2000.j2k.io.*;
058:
059: import java.io.*;
060:
061: /**
062: * This class implements a scalar dequantizer with deadzone. The output can be
063: * either integer ('int') or floating-point ('float') data. The dequantization
064: * step sizes and other parameters are taken from a StdDequantizerParams
065: * class, which inherits from DequantizerParams.
066: *
067: * <P>Sign magnitude representation is used (instead of two's complement) for
068: * the input data. The most significant bit is used for the sign (0 if
069: * positive, 1 if negative). Then the magnitude of the quantized coefficient
070: * is stored in the next most significat bits. The most significant magnitude
071: * bit corresponds to the most significant bit-plane and so on.
072: *
073: * <P>When reversible quantization is used, this class only converts between
074: * the sign-magnitude representation and the integer (or eventually
075: * fixed-point) output, since there is no true quantization.
076: *
077: * <P>The output data is fixed-point two's complement for 'int' output and
078: * floating-point for 'float' output. The type of output and the number number
079: * of fractional bits for 'int' output are defined at the constructor. Each
080: * component may have a different number of fractional bits.
081: *
082: * <P>The reconstruction levels used by the dequantizer are exactly what is
083: * received from the entropy decoder. It is assumed that the entropy decoder
084: * always returns codewords that are midways in the decoded intervals. In this
085: * way the dequantized values will always lie midways in the quantization
086: * intervals.
087: * */
088: public class StdDequantizer extends Dequantizer {
089:
090: /** The quantizer type spec */
091: private QuantTypeSpec qts;
092:
093: /** The quantizer step sizes spec */
094: private QuantStepSizeSpec qsss;
095:
096: /** The number of guard bits spec */
097: private GuardBitsSpec gbs;
098:
099: /** The decoding parameters of the dequantizer */
100: private StdDequantizerParams params;
101:
102: /** The 'DataBlkInt' object used to request data, used when output data is
103: * not int */
104: private DataBlkInt inblk;
105:
106: /** Type of the current output data */
107: private int outdtype;
108:
109: /**
110: * Initializes the source of compressed data. And sets the number of range
111: * bits and fraction bits and receives the parameters for the dequantizer.
112: *
113: * @param src From where to obtain the quantized data.
114: *
115: * @param rb The number of "range bits" (bitdepth) for each component
116: * (must be the "range bits" of the un-transformed components). For a
117: * definition of "range bits" see the getNomRangeBits() method.
118: *
119: * @param qts The quantizer type spec
120: *
121: * @param qsss The dequantizer step sizes spec
122: *
123: * @see Dequantizer#getNomRangeBits
124: *
125: * @exception IllegalArgumentException Thrown if 'outdt' is neither
126: * TYPE_FLOAT nor TYPE_INT, or if 'param' specify reversible quantization
127: * and 'outdt' is not TYPE_INT or 'fp' has non-zero values, or if 'outdt'
128: * is TYPE_FLOAT and 'fp' has non-zero values.
129: * */
130: public StdDequantizer(CBlkQuantDataSrcDec src, int[] utrb,
131: DecoderSpecs decSpec) {
132: super (src, utrb, decSpec);
133:
134: if (utrb.length != src.getNumComps()) {
135: throw new IllegalArgumentException("Invalid rb argument");
136: }
137: this .qsss = decSpec.qsss;
138: this .qts = decSpec.qts;
139: this .gbs = decSpec.gbs;
140: }
141:
142: /**
143: * Returns the position of the fixed point in the output data for the
144: * specified component. This is the position of the least significant
145: * integral (i.e. non-fractional) bit, which is equivalent to the number
146: * of fractional bits. For instance, for fixed-point values with 2
147: * fractional bits, 2 is returned. For floating-point data this value does
148: * not apply and 0 should be returned. Position 0 is the position of the
149: * least significant bit in the data. If the output data is 'float' then 0
150: * is always returned.
151: *
152: * <P><u>Note:</u> Fractional bits are no more supported by JJ2000.
153: *
154: * @param c The index of the component.
155: *
156: * @return The position of the fixed-point, which is the same as
157: * the number of fractional bits. For floating-point data 0 is
158: * returned.
159: * */
160: public int getFixedPoint(int c) {
161: return 0;
162: }
163:
164: /**
165: * Returns the specified code-block in the current tile for the specified
166: * component, as a copy (see below).
167: *
168: * <P>The returned code-block may be progressive, which is indicated by
169: * the 'progressive' variable of the returned 'DataBlk' object. If a
170: * code-block is progressive it means that in a later request to this
171: * method for the same code-block it is possible to retrieve data which is
172: * a better approximation, since meanwhile more data to decode for the
173: * code-block could have been received. If the code-block is not
174: * progressive then later calls to this method for the same code-block
175: * will return the exact same data values.
176: *
177: * <P>The data returned by this method is always a copy of the internal
178: * data of this object, if any, and it can be modified "in place" without
179: * any problems after being returned. The 'offset' of the returned data is
180: * 0, and the 'scanw' is the same as the code-block width. See the
181: * 'DataBlk' class.
182: *
183: * @param c The component for which to return the next code-block.
184: *
185: * @param m The vertical index of the code-block to return, in the
186: * specified subband.
187: *
188: * @param n The horizontal index of the code-block to return, in the
189: * specified subband.
190: *
191: * @param sb The subband in which the code-block to return is.
192: *
193: * @param cblk If non-null this object will be used to return the new
194: * code-block. If null a new one will be allocated and returned. If the
195: * "data" array of the object is non-null it will be reused, if possible,
196: * to return the data.
197: *
198: * @return The next code-block in the current tile for component 'n', or
199: * null if all code-blocks for the current tile have been returned.
200: *
201: * @see DataBlk
202: * */
203: public final DataBlk getCodeBlock(int c, int m, int n,
204: SubbandSyn sb, DataBlk cblk) {
205: return getInternCodeBlock(c, m, n, sb, cblk);
206: }
207:
208: /**
209: * Returns the specified code-block in the current tile for the specified
210: * component (as a reference or copy).
211: *
212: * <P>The returned code-block may be progressive, which is indicated by
213: * the 'progressive' variable of the returned 'DataBlk'
214: * object. If a code-block is progressive it means that in a later request
215: * to this method for the same code-block it is possible to retrieve data
216: * which is a better approximation, since meanwhile more data to decode
217: * for the code-block could have been received. If the code-block is not
218: * progressive then later calls to this method for the same code-block
219: * will return the exact same data values.
220: *
221: * <P>The data returned by this method can be the data in the internal
222: * buffer of this object, if any, and thus can not be modified by the
223: * caller. The 'offset' and 'scanw' of the returned data can be
224: * arbitrary. See the 'DataBlk' class.
225: *
226: * @param c The component for which to return the next code-block.
227: *
228: * @param m The vertical index of the code-block to return, in the
229: * specified subband.
230: *
231: * @param n The horizontal index of the code-block to return, in the
232: * specified subband.
233: *
234: * @param sb The subband in which the code-block to return is.
235: *
236: * @param cblk If non-null this object will be used to return the new
237: * code-block. If null a new one will be allocated and returned. If the
238: * "data" array of the object is non-null it will be reused, if possible,
239: * to return the data.
240: *
241: * @return The next code-block in the current tile for component 'n', or
242: * null if all code-blocks for the current tile have been returned.
243: *
244: * @see DataBlk
245: * */
246: public final DataBlk getInternCodeBlock(int c, int m, int n,
247: SubbandSyn sb, DataBlk cblk) {
248: // This method is declared final since getNextCodeBlock() relies on
249: // the actual implementation of this method.
250: int j, jmin, k;
251: int temp;
252: float step;
253: int shiftBits;
254: int magBits;
255: int[] outiarr, inarr;
256: float[] outfarr;
257: int w, h;
258: boolean reversible = qts.isReversible(tIdx, c);
259: boolean derived = qts.isDerived(tIdx, c);
260: StdDequantizerParams params = (StdDequantizerParams) qsss
261: .getTileCompVal(tIdx, c);
262: int G = ((Integer) gbs.getTileCompVal(tIdx, c)).intValue();
263:
264: outdtype = cblk.getDataType();
265:
266: if (reversible && outdtype != DataBlk.TYPE_INT) {
267: throw new IllegalArgumentException(
268: "Reversible quantizations " + "must use int data");
269: }
270:
271: // To get compiler happy
272: outiarr = null;
273: outfarr = null;
274: inarr = null;
275:
276: // Get source data and initialize output DataBlk object.
277: switch (outdtype) {
278: case DataBlk.TYPE_INT:
279: // With int data we can use the same DataBlk object to get the
280: // data from the source and return the dequantized data, and we
281: // can also work "in place" (i.e. same buffer).
282: cblk = src.getCodeBlock(c, m, n, sb, cblk);
283: // Input and output arrays are the same
284: outiarr = (int[]) cblk.getData();
285: break;
286: case DataBlk.TYPE_FLOAT:
287: // With float data we must use a different DataBlk objects to get
288: // the data from the source and to return the dequantized data.
289: inblk = (DataBlkInt) src.getInternCodeBlock(c, m, n, sb,
290: inblk);
291: inarr = inblk.getDataInt();
292: if (cblk == null) {
293: cblk = new DataBlkFloat();
294: }
295: // Copy the attributes of the CodeBlock object
296: cblk.ulx = inblk.ulx;
297: cblk.uly = inblk.uly;
298: cblk.w = inblk.w;
299: cblk.h = inblk.h;
300: cblk.offset = 0;
301: cblk.scanw = cblk.w;
302: cblk.progressive = inblk.progressive;
303: // Get output data array and check its size
304: outfarr = (float[]) cblk.getData();
305: if (outfarr == null || outfarr.length < cblk.w * cblk.h) {
306: outfarr = new float[cblk.w * cblk.h];
307: cblk.setData(outfarr);
308: }
309: break;
310: }
311:
312: magBits = sb.magbits;
313:
314: // Calculate quantization step and number of magnitude bits
315: // depending on reversibility and derivedness and perform
316: // inverse quantization
317: if (reversible) {
318: shiftBits = 31 - magBits;
319: // For int data Inverse quantization happens "in-place". The input
320: // array has an offset of 0 and scan width equal to the code-block
321: // width.
322: for (j = outiarr.length - 1; j >= 0; j--) {
323: temp = outiarr[j]; // input array is same as output one
324: outiarr[j] = (temp >= 0) ? (temp >> shiftBits)
325: : -((temp & 0x7FFFFFFF) >> shiftBits);
326: }
327: } else {// Not reversible
328: if (derived) {
329: // Max resolution level
330: int mrl = src.getSynSubbandTree(getTileIdx(), c).resLvl;
331: step = params.nStep[0][0]
332: * (1L << (rb[c] + sb.anGainExp + mrl - sb.level));
333: } else {
334: step = params.nStep[sb.resLvl][sb.sbandIdx]
335: * (1L << (rb[c] + sb.anGainExp));
336: }
337: shiftBits = 31 - magBits;
338:
339: // Adjust step to the number of shiftBits
340: step /= (1 << shiftBits);
341:
342: switch (outdtype) {
343: case DataBlk.TYPE_INT:
344: // For int data Inverse quantization happens "in-place". The
345: // input array has an offset of 0 and scan width equal to the
346: // code-block width.
347: for (j = outiarr.length - 1; j >= 0; j--) {
348: temp = outiarr[j]; // input array is same as output one
349: outiarr[j] = (int) (((float) ((temp >= 0) ? temp
350: : -(temp & 0x7FFFFFFF))) * step);
351: }
352: break;
353: case DataBlk.TYPE_FLOAT:
354: // For float data the inverse quantization can not happen
355: // "in-place".
356: w = cblk.w;
357: h = cblk.h;
358: for (j = w * h - 1, k = inblk.offset + (h - 1)
359: * inblk.scanw + w - 1, jmin = w * (h - 1); j >= 0; jmin -= w) {
360: for (; j >= jmin; k--, j--) {
361: temp = inarr[k];
362: outfarr[j] = ((float) ((temp >= 0) ? temp
363: : -(temp & 0x7FFFFFFF)))
364: * step;
365: }
366: // Jump to beggining of previous line in input
367: k -= inblk.scanw - w;
368: }
369: break;
370: }
371: }
372: // Return the output code-block
373: return cblk;
374: }
375: }
|