001: /*
002: * $RCSfile: StdQuantizer.java,v $
003: * $Revision: 1.1 $
004: * $Date: 2005/02/11 05:02:20 $
005: * $State: Exp $
006: *
007: * Class: StdQuantizer
008: *
009: * Description: Scalar deadzone quantizer of integer or float
010: * data.
011: *
012: * Mergerd from StdQuantizerInt and
013: * StdQuantizerFloat from Joel Askelof.
014: *
015: *
016: * COPYRIGHT:
017: *
018: * This software module was originally developed by Raphaël Grosbois and
019: * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
020: * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
021: * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
022: * Centre France S.A) in the course of development of the JPEG2000
023: * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
024: * software module is an implementation of a part of the JPEG 2000
025: * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
026: * Systems AB and Canon Research Centre France S.A (collectively JJ2000
027: * Partners) agree not to assert against ISO/IEC and users of the JPEG
028: * 2000 Standard (Users) any of their rights under the copyright, not
029: * including other intellectual property rights, for this software module
030: * with respect to the usage by ISO/IEC and Users of this software module
031: * or modifications thereof for use in hardware or software products
032: * claiming conformance to the JPEG 2000 Standard. Those intending to use
033: * this software module in hardware or software products are advised that
034: * their use may infringe existing patents. The original developers of
035: * this software module, JJ2000 Partners and ISO/IEC assume no liability
036: * for use of this software module or modifications thereof. No license
037: * or right to this software module is granted for non JPEG 2000 Standard
038: * conforming products. JJ2000 Partners have full right to use this
039: * software module for his/her own purpose, assign or donate this
040: * software module to any third party and to inhibit third parties from
041: * using this software module for non JPEG 2000 Standard conforming
042: * products. This copyright notice must be included in all copies or
043: * derivative works of this software module.
044: *
045: * Copyright (c) 1999/2000 JJ2000 Partners.
046: * */
047: package jj2000.j2k.quantization.quantizer;
048:
049: import jj2000.j2k.codestream.writer.*;
050: import jj2000.j2k.wavelet.analysis.*;
051: import jj2000.j2k.quantization.*;
052: import jj2000.j2k.wavelet.*;
053: import jj2000.j2k.image.*;
054: import jj2000.j2k.*;
055:
056: import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriteParamJava;
057:
058: /**
059: * This class implements scalar quantization of integer or floating-point
060: * valued source data. The source data is the wavelet transformed image data
061: * and the output is the quantized wavelet coefficients represented in
062: * sign-magnitude (see below).
063: *
064: * <P>Sign magnitude representation is used (instead of two's complement) for
065: * the output data. The most significant bit is used for the sign (0 if
066: * positive, 1 if negative). Then the magnitude of the quantized coefficient
067: * is stored in the next M most significat bits. The rest of the bits (least
068: * significant bits) can contain a fractional value of the quantized
069: * coefficient. This fractional value is not to be coded by the entropy
070: * coder. However, it can be used to compute rate-distortion measures with
071: * greater precision.
072: *
073: * <P>The value of M is determined for each subband as the sum of the number
074: * of guard bits G and the nominal range of quantized wavelet coefficients in
075: * the corresponding subband (Rq), minus 1:
076: *
077: * <P>M = G + Rq -1
078: *
079: * <P>The value of G should be the same for all subbands. The value of Rq
080: * depends on the quantization step size, the nominal range of the component
081: * before the wavelet transform and the analysis gain of the subband (see
082: * Subband).
083: *
084: * <P>The blocks of data that are requested should not cross subband
085: * boundaries.
086: *
087: * @see Subband
088: *
089: * @see Quantizer
090: * */
091: public class StdQuantizer extends Quantizer {
092:
093: /** The number of mantissa bits for the quantization steps */
094: public final static int QSTEP_MANTISSA_BITS = 11;
095:
096: /** The number of exponent bits for the quantization steps */
097: // NOTE: formulas in 'convertFromExpMantissa()' and
098: // 'convertToExpMantissa()' methods do not support more than 5 bits.
099: public final static int QSTEP_EXPONENT_BITS = 5;
100:
101: /** The maximum value of the mantissa for the quantization steps */
102: public final static int QSTEP_MAX_MANTISSA = (1 << QSTEP_MANTISSA_BITS) - 1;
103:
104: /** The maximum value of the exponent for the quantization steps */
105: public final static int QSTEP_MAX_EXPONENT = (1 << QSTEP_EXPONENT_BITS) - 1;
106:
107: /** Natural log of 2, used as a convenience variable */
108: private static double log2 = Math.log(2);
109:
110: /** The quantization type specifications */
111: private QuantTypeSpec qts;
112:
113: /** The quantization step size specifications */
114: private QuantStepSizeSpec qsss;
115:
116: /** The guard bits specifications */
117: private GuardBitsSpec gbs;
118:
119: /** The 'CBlkWTDataFloat' object used to request data, used when
120: * quantizing floating-point data. */
121: // This variable makes the class thread unsafe, but it avoids allocating
122: // new objects for code-block that is quantized.
123: private CBlkWTDataFloat infblk;
124:
125: /**
126: * Initializes the source of wavelet transform coefficients. The
127: * constructor takes information on whether the quantizer is in
128: * reversible, derived or expounded mode. If the quantizer is reversible
129: * the value of 'derived' is ignored. If the source data is not integer
130: * (int) then the quantizer can not be reversible.
131: *
132: * <P> After initializing member attributes, getAnSubbandTree is called for
133: * all components setting the 'stepWMSE' for all subbands in the current
134: * tile.
135: *
136: * @param src The source of wavelet transform coefficients.
137: *
138: * @param encSpec The encoder specifications
139: * */
140: public StdQuantizer(CBlkWTDataSrc src, J2KImageWriteParamJava wp) {
141: super (src);
142: qts = wp.getQuantizationType();
143: qsss = wp.getQuantizationStep();
144: gbs = wp.getGuardBits();
145: }
146:
147: /**
148: * Returns the quantization type spec object associated to the quantizer.
149: *
150: * @return The quantization type spec
151: * */
152: public QuantTypeSpec getQuantTypeSpec() {
153: return qts;
154: }
155:
156: /**
157: * Returns the number of guard bits used by this quantizer in the given
158: * tile-component.
159: *
160: * @param t Tile index
161: *
162: * @param c Component index
163: *
164: * @return The number of guard bits
165: * */
166: public int getNumGuardBits(int t, int c) {
167: return ((Integer) gbs.getTileCompVal(t, c)).intValue();
168: }
169:
170: /**
171: * Returns true if the quantized data is reversible, for the specified
172: * tile-component. For the quantized data to be reversible it is necessary
173: * and sufficient that the quantization is reversible.
174: *
175: * @param t The tile to test for reversibility
176: *
177: * @param c The component to test for reversibility
178: *
179: * @return True if the quantized data is reversible, false if not.
180: * */
181: public boolean isReversible(int t, int c) {
182: return qts.isReversible(t, c);
183: }
184:
185: /**
186: * Returns true if given tile-component uses derived quantization step
187: * sizes.
188: *
189: * @param t Tile index
190: *
191: * @param c Component index
192: *
193: * @return True if derived
194: *
195: */
196: public boolean isDerived(int t, int c) {
197: return qts.isDerived(t, c);
198: }
199:
200: /**
201: * Returns the next code-block in the current tile for the specified
202: * component, as a copy (see below). The order in which code-blocks are
203: * returned is not specified. However each code-block is returned only
204: * once and all code-blocks will be returned if the method is called 'N'
205: * times, where 'N' is the number of code-blocks in the tile. After all
206: * the code-blocks have been returned for the current tile calls to this
207: * method will return 'null'.
208: *
209: * <P>When changing the current tile (through 'setTile()' or 'nextTile()')
210: * this method will always return the first code-block, as if this method
211: * was never called before for the new current tile.
212: *
213: * <P>The data returned by this method is always a copy of the
214: * data. Therfore it can be modified "in place" without any problems after
215: * being returned. The 'offset' of the returned data is 0, and the 'scanw'
216: * is the same as the code-block width. See the 'CBlkWTData' class.
217: *
218: * <P>The 'ulx' and 'uly' members of the returned 'CBlkWTData' object
219: * contain the coordinates of the top-left corner of the block, with
220: * respect to the tile, not the subband.
221: *
222: * @param c The component for which to return the next code-block.
223: *
224: * @param cblk If non-null this object will be used to return the new
225: * code-block. If null a new one will be allocated and returned. If the
226: * "data" array of the object is non-null it will be reused, if possible,
227: * to return the data.
228: *
229: * @return The next code-block in the current tile for component 'n', or
230: * null if all code-blocks for the current tile have been returned.
231: *
232: * @see CBlkWTData
233: * */
234: public CBlkWTData getNextCodeBlock(int c, CBlkWTData cblk) {
235: return getNextInternCodeBlock(c, cblk);
236: }
237:
238: /**
239: * Returns the next code-block in the current tile for the specified
240: * component. The order in which code-blocks are returned is not
241: * specified. However each code-block is returned only once and all
242: * code-blocks will be returned if the method is called 'N' times, where
243: * 'N' is the number of code-blocks in the tile. After all the code-blocks
244: * have been returned for the current tile calls to this method will
245: * return 'null'.
246: *
247: * <P>When changing the current tile (through 'setTile()' or 'nextTile()')
248: * this method will always return the first code-block, as if this method
249: * was never called before for the new current tile.
250: *
251: * <P>The data returned by this method can be the data in the internal
252: * buffer of this object, if any, and thus can not be modified by the
253: * caller. The 'offset' and 'scanw' of the returned data can be
254: * arbitrary. See the 'CBlkWTData' class.
255: *
256: * <P>The 'ulx' and 'uly' members of the returned 'CBlkWTData' object
257: * contain the coordinates of the top-left corner of the block, with
258: * respect to the tile, not the subband.
259: *
260: * @param c The component for which to return the next code-block.
261: *
262: * @param cblk If non-null this object will be used to return the new
263: * code-block. If null a new one will be allocated and returned. If the
264: * "data" array of the object is non-null it will be reused, if possible,
265: * to return the data.
266: *
267: * @return The next code-block in the current tile for component 'n', or
268: * null if all code-blocks for the current tile have been returned.
269: *
270: * @see CBlkWTData
271: * */
272: public final CBlkWTData getNextInternCodeBlock(int c,
273: CBlkWTData cblk) {
274: // NOTE: this method is declared final since getNextCodeBlock() relies
275: // on this particular implementation
276: int k, j;
277: int tmp, shiftBits, jmin;
278: int w, h;
279: int outarr[];
280: float infarr[] = null;
281: CBlkWTDataFloat infblk;
282: float invstep; // The inverse of the quantization step size
283: boolean intq; // flag for quantizig ints
284: SubbandAn sb;
285: float stepUDR; // The quantization step size (for a dynamic
286: // range of 1, or unit)
287: int g = ((Integer) gbs.getTileCompVal(tIdx, c)).intValue();
288:
289: // Are we quantizing ints or floats?
290: intq = (src.getDataType(tIdx, c) == DataBlk.TYPE_INT);
291:
292: // Check that we have an output object
293: if (cblk == null) {
294: cblk = new CBlkWTDataInt();
295: }
296:
297: // Cache input float code-block
298: infblk = this .infblk;
299:
300: // Get data to quantize. When quantizing int data 'cblk' is used to
301: // get the data to quantize and to return the quantized data as well,
302: // that's why 'getNextCodeBlock()' is used. This can not be done when
303: // quantizing float data because of the different data types, that's
304: // why 'getNextInternCodeBlock()' is used in that case.
305: if (intq) { // Source data is int
306: cblk = src.getNextCodeBlock(c, cblk);
307: if (cblk == null) {
308: return null; // No more code-blocks in current tile for comp.
309: }
310: // Input and output arrays are the same (for "in place" quant.)
311: outarr = (int[]) cblk.getData();
312: } else { // Source data is float
313: // Can not use 'cblk' to get float data, use 'infblk'
314: infblk = (CBlkWTDataFloat) src.getNextInternCodeBlock(c,
315: infblk);
316: if (infblk == null) {
317: // Release buffer from infblk: this enables to garbage collect
318: // the big buffer when we are done with last code-block of
319: // component.
320: this .infblk.setData(null);
321: return null; // No more code-blocks in current tile for comp.
322: }
323: this .infblk = infblk; // Save local cache
324: infarr = (float[]) infblk.getData();
325: // Get output data array and check that there is memory to put the
326: // quantized coeffs in
327: outarr = (int[]) cblk.getData();
328: if (outarr == null || outarr.length < infblk.w * infblk.h) {
329: outarr = new int[infblk.w * infblk.h];
330: cblk.setData(outarr);
331: }
332: cblk.m = infblk.m;
333: cblk.n = infblk.n;
334: cblk.sb = infblk.sb;
335: cblk.ulx = infblk.ulx;
336: cblk.uly = infblk.uly;
337: cblk.w = infblk.w;
338: cblk.h = infblk.h;
339: cblk.wmseScaling = infblk.wmseScaling;
340: cblk.offset = 0;
341: cblk.scanw = cblk.w;
342: }
343:
344: // Cache width, height and subband of code-block
345: w = cblk.w;
346: h = cblk.h;
347: sb = cblk.sb;
348:
349: if (isReversible(tIdx, c)) { // Reversible only for int data
350: cblk.magbits = g - 1 + src.getNomRangeBits(c)
351: + sb.anGainExp;
352: shiftBits = 31 - cblk.magbits;
353:
354: // Update the convertFactor field
355: cblk.convertFactor = (1 << shiftBits);
356:
357: // Since we used getNextCodeBlock() to get the int data then
358: // 'offset' is 0 and 'scanw' is the width of the code-block The
359: // input and output arrays are the same (i.e. "in place")
360: for (j = w * h - 1; j >= 0; j--) {
361: tmp = (outarr[j] << shiftBits);
362: outarr[j] = ((tmp < 0) ? (1 << 31) | (-tmp) : tmp);
363: }
364: } else { // Non-reversible, use step size
365: float baseStep = ((Float) qsss.getTileCompVal(tIdx, c))
366: .floatValue();
367:
368: // Calculate magnitude bits and quantization step size
369: if (isDerived(tIdx, c)) {
370: cblk.magbits = g - 1 + sb.level
371: - (int) Math.floor(Math.log(baseStep) / log2);
372: stepUDR = baseStep / (1 << sb.level);
373: } else {
374: cblk.magbits = g
375: - 1
376: - (int) Math.floor(Math.log(baseStep
377: / (sb.l2Norm * (1 << sb.anGainExp)))
378: / log2);
379: stepUDR = baseStep / (sb.l2Norm * (1 << sb.anGainExp));
380: }
381: shiftBits = 31 - cblk.magbits;
382: // Calculate step that decoder will get and use that one.
383: stepUDR = convertFromExpMantissa(convertToExpMantissa(stepUDR));
384: invstep = 1.0f / ((1L << (src.getNomRangeBits(c) + sb.anGainExp)) * stepUDR);
385: // Normalize to magnitude bits (output fractional point)
386: invstep *= (1 << (shiftBits - src.getFixedPoint(c)));
387:
388: // Update convertFactor and stepSize fields
389: cblk.convertFactor = invstep;
390: cblk.stepSize = ((1L << (src.getNomRangeBits(c) + sb.anGainExp)) * stepUDR);
391:
392: if (intq) { // Quantizing int data
393: // Since we used getNextCodeBlock() to get the int data then
394: // 'offset' is 0 and 'scanw' is the width of the code-block
395: // The input and output arrays are the same (i.e. "in place")
396: for (j = w * h - 1; j >= 0; j--) {
397: tmp = (int) (outarr[j] * invstep);
398: outarr[j] = ((tmp < 0) ? (1 << 31) | (-tmp) : tmp);
399: }
400: } else { // Quantizing float data
401: for (j = w * h - 1, k = infblk.offset + (h - 1)
402: * infblk.scanw + w - 1, jmin = w * (h - 1); j >= 0; jmin -= w) {
403: for (; j >= jmin; k--, j--) {
404: tmp = (int) (infarr[k] * invstep);
405: outarr[j] = ((tmp < 0) ? (1 << 31) | (-tmp)
406: : tmp);
407: }
408: // Jump to beggining of previous line in input
409: k -= infblk.scanw - w;
410: }
411: }
412: }
413: // Return the quantized code-block
414: return cblk;
415: }
416:
417: /**
418: * Calculates the parameters of the SubbandAn objects that depend on the
419: * Quantizer. The 'stepWMSE' field is calculated for each subband which is
420: * a leaf in the tree rooted at 'sb', for the specified component. The
421: * subband tree 'sb' must be the one for the component 'n'.
422: *
423: * @param sb The root of the subband tree.
424: *
425: * @param c The component index
426: *
427: * @see SubbandAn#stepWMSE
428: * */
429: protected void calcSbParams(SubbandAn sb, int c) {
430: float baseStep;
431:
432: if (sb.stepWMSE > 0f) // parameters already calculated
433: return;
434: if (!sb.isNode) {
435: if (isReversible(tIdx, c)) {
436: sb.stepWMSE = (float) Math.pow(2, -(src
437: .getNomRangeBits(c) << 1))
438: * sb.l2Norm * sb.l2Norm;
439: } else {
440: baseStep = ((Float) qsss.getTileCompVal(tIdx, c))
441: .floatValue();
442: if (isDerived(tIdx, c)) {
443: sb.stepWMSE = baseStep
444: * baseStep
445: * (float) Math.pow(2,
446: (sb.anGainExp - sb.level) << 1)
447: * sb.l2Norm * sb.l2Norm;
448: } else {
449: sb.stepWMSE = baseStep * baseStep;
450: }
451: }
452: } else {
453: calcSbParams((SubbandAn) sb.getLL(), c);
454: calcSbParams((SubbandAn) sb.getHL(), c);
455: calcSbParams((SubbandAn) sb.getLH(), c);
456: calcSbParams((SubbandAn) sb.getHH(), c);
457: sb.stepWMSE = 1f; // Signal that we already calculated this branch
458: }
459: }
460:
461: /**
462: * Converts the floating point value to its exponent-mantissa
463: * representation. The mantissa occupies the 11 least significant bits
464: * (bits 10-0), and the exponent the previous 5 bits (bits 15-11).
465: *
466: * @param step The quantization step, normalized to a dynamic range of 1.
467: *
468: * @return The exponent mantissa representation of the step.
469: * */
470: public static int convertToExpMantissa(float step) {
471: int exp;
472:
473: exp = (int) Math.ceil(-Math.log(step) / log2);
474: if (exp > QSTEP_MAX_EXPONENT) {
475: // If step size is too small for exponent representation, use the
476: // minimum, which is exponent QSTEP_MAX_EXPONENT and mantissa 0.
477: return (QSTEP_MAX_EXPONENT << QSTEP_MANTISSA_BITS);
478: }
479: // NOTE: this formula does not support more than 5 bits for the
480: // exponent, otherwise (-1<<exp) might overflow (the - is used to be
481: // able to represent 2**31)
482: return (exp << QSTEP_MANTISSA_BITS)
483: | ((int) ((-step * (-1 << exp) - 1f)
484: * (1 << QSTEP_MANTISSA_BITS) + 0.5f));
485: }
486:
487: /**
488: * Converts the exponent-mantissa representation to its floating-point
489: * value. The mantissa occupies the 11 least significant bits (bits 10-0),
490: * and the exponent the previous 5 bits (bits 15-11).
491: *
492: * @param ems The exponent-mantissa representation of the step.
493: *
494: * @return The floating point representation of the step, normalized to a
495: * dynamic range of 1.
496: * */
497: private static float convertFromExpMantissa(int ems) {
498: // NOTE: this formula does not support more than 5 bits for the
499: // exponent, otherwise (-1<<exp) might overflow (the - is used to be
500: // able to represent 2**31)
501: return (-1f - ((float) (ems & QSTEP_MAX_MANTISSA))
502: / ((float) (1 << QSTEP_MANTISSA_BITS)))
503: / (float) (-1 << ((ems >> QSTEP_MANTISSA_BITS) & QSTEP_MAX_EXPONENT));
504: }
505:
506: /**
507: * Returns the maximum number of magnitude bits in any subband of the
508: * current tile.
509: *
510: * @param c the component number
511: *
512: * @return The maximum number of magnitude bits in all subbands of the
513: * current tile.
514: * */
515: public int getMaxMagBits(int c) {
516: Subband sb = getAnSubbandTree(tIdx, c);
517: if (isReversible(tIdx, c)) {
518: return getMaxMagBitsRev(sb, c);
519: } else {
520: if (isDerived(tIdx, c)) {
521: return getMaxMagBitsDerived(sb, tIdx, c);
522: } else {
523: return getMaxMagBitsExpounded(sb, tIdx, c);
524: }
525: }
526: }
527:
528: /**
529: * Returns the maximum number of magnitude bits in any subband of the
530: * current tile if reversible quantization is used
531: *
532: * @param sb The root of the subband tree of the current tile
533: *
534: * @param c the component number
535: *
536: * @return The highest number of magnitude bit-planes
537: * */
538: private int getMaxMagBitsRev(Subband sb, int c) {
539: int tmp, max = 0;
540: int g = ((Integer) gbs.getTileCompVal(tIdx, c)).intValue();
541:
542: if (!sb.isNode)
543: return g - 1 + src.getNomRangeBits(c) + sb.anGainExp;
544:
545: max = getMaxMagBitsRev(sb.getLL(), c);
546: tmp = getMaxMagBitsRev(sb.getLH(), c);
547: if (tmp > max)
548: max = tmp;
549: tmp = getMaxMagBitsRev(sb.getHL(), c);
550: if (tmp > max)
551: max = tmp;
552: tmp = getMaxMagBitsRev(sb.getHH(), c);
553: if (tmp > max)
554: max = tmp;
555:
556: return max;
557: }
558:
559: /**
560: * Returns the maximum number of magnitude bits in any subband in the
561: * given tile-component if derived quantization is used
562: *
563: * @param sb The root of the subband tree of the tile-component
564: *
565: * @param t Tile index
566: *
567: * @param c Component index
568: *
569: * @return The highest number of magnitude bit-planes
570: * */
571: private int getMaxMagBitsDerived(Subband sb, int t, int c) {
572: int tmp, max = 0;
573: int g = ((Integer) gbs.getTileCompVal(t, c)).intValue();
574:
575: if (!sb.isNode) {
576: float baseStep = ((Float) qsss.getTileCompVal(t, c))
577: .floatValue();
578: return g - 1 + sb.level
579: - (int) Math.floor(Math.log(baseStep) / log2);
580: }
581:
582: max = getMaxMagBitsDerived(sb.getLL(), t, c);
583: tmp = getMaxMagBitsDerived(sb.getLH(), t, c);
584: if (tmp > max)
585: max = tmp;
586: tmp = getMaxMagBitsDerived(sb.getHL(), t, c);
587: if (tmp > max)
588: max = tmp;
589: tmp = getMaxMagBitsDerived(sb.getHH(), t, c);
590: if (tmp > max)
591: max = tmp;
592:
593: return max;
594: }
595:
596: /**
597: * Returns the maximum number of magnitude bits in any subband in the
598: * given tile-component if expounded quantization is used
599: *
600: * @param sb The root of the subband tree of the tile-component
601: *
602: * @param t Tile index
603: *
604: * @param c Component index
605: *
606: * @return The highest number of magnitude bit-planes
607: * */
608: private int getMaxMagBitsExpounded(Subband sb, int t, int c) {
609: int tmp, max = 0;
610: int g = ((Integer) gbs.getTileCompVal(t, c)).intValue();
611:
612: if (!sb.isNode) {
613: float baseStep = ((Float) qsss.getTileCompVal(t, c))
614: .floatValue();
615: return g
616: - 1
617: - (int) Math
618: .floor(Math
619: .log(baseStep
620: / (((SubbandAn) sb).l2Norm * (1 << sb.anGainExp)))
621: / log2);
622: }
623:
624: max = getMaxMagBitsExpounded(sb.getLL(), t, c);
625: tmp = getMaxMagBitsExpounded(sb.getLH(), t, c);
626: if (tmp > max)
627: max = tmp;
628: tmp = getMaxMagBitsExpounded(sb.getHL(), t, c);
629: if (tmp > max)
630: max = tmp;
631: tmp = getMaxMagBitsExpounded(sb.getHH(), t, c);
632: if (tmp > max)
633: max = tmp;
634:
635: return max;
636: }
637: }
|