Example #1
0
		/// <summary> Returns the next code-block in the current tile for the specified
		/// component. The order in which code-blocks are returned is not
		/// specified. However each code-block is returned only once and all
		/// code-blocks will be returned if the method is called 'N' times, where
		/// 'N' is the number of code-blocks in the tile. After all the code-blocks
		/// have been returned for the current tile calls to this method will
		/// return 'null'.
		/// 
		/// <p>When changing the current tile (through 'setTile()' or 'nextTile()')
		/// this method will always return the first code-block, as if this method
		/// was never called before for the new current tile.</p>
		/// 
		/// <p>The data returned by this method can be the data in the internal
		/// buffer of this object, if any, and thus can not be modified by the
		/// caller. The 'offset' and 'scanw' of the returned data can be
		/// arbitrary. See the 'CBlkWTData' class.</p>
		/// 
		/// <p>The 'ulx' and 'uly' members of the returned 'CBlkWTData' object
		/// contain the coordinates of the top-left corner of the block, with
		/// respect to the tile, not the subband.</p>
		/// 
		/// </summary>
		/// <param name="c">The component for which to return the next code-block.
		/// 
		/// </param>
		/// <param name="cblk">If non-null this object will be used to return the new
		/// code-block. If null a new one will be allocated and returned. If the
		/// "data" array of the object is non-null it will be reused, if possible,
		/// to return the data.
		/// 
		/// </param>
		/// <returns> The next code-block in the current tile for component 'n', or
		/// null if all code-blocks for the current tile have been returned.
		/// 
		/// </returns>
		/// <seealso cref="CBlkWTData">
		/// 
		/// </seealso>
		public override CBlkWTData getNextInternCodeBlock(int c, CBlkWTData cblk)
		{
			// NOTE: this method is declared final since getNextCodeBlock() relies
			// on this particular implementation
			int k, j;
			int tmp, shiftBits, jmin;
			int w, h;
			int[] outarr;
			float[] infarr = null;
			CBlkWTDataFloat infblk;
			float invstep; // The inverse of the quantization step size
			bool intq; // flag for quantizig ints
			SubbandAn sb;
			float stepUDR; // The quantization step size (for a dynamic
			// range of 1, or unit)
			int g = ((System.Int32) gbs.getTileCompVal(tIdx, c));
			
			// Are we quantizing ints or floats?
			intq = (src.getDataType(tIdx, c) == DataBlk.TYPE_INT);
			
			// Check that we have an output object
			if (cblk == null)
			{
				cblk = new CBlkWTDataInt();
			}
			
			// Cache input float code-block
			infblk = this.infblk;
			
			// Get data to quantize. When quantizing int data 'cblk' is used to
			// get the data to quantize and to return the quantized data as well,
			// that's why 'getNextCodeBlock()' is used. This can not be done when
			// quantizing float data because of the different data types, that's
			// why 'getNextInternCodeBlock()' is used in that case.
			if (intq)
			{
				// Source data is int
				cblk = src.getNextCodeBlock(c, cblk);
				if (cblk == null)
				{
					return null; // No more code-blocks in current tile for comp.
				}
				// Input and output arrays are the same (for "in place" quant.)
				outarr = (int[]) cblk.Data;
			}
			else
			{
				// Source data is float
				// Can not use 'cblk' to get float data, use 'infblk'
				infblk = (CBlkWTDataFloat) src.getNextInternCodeBlock(c, infblk);
				if (infblk == null)
				{
					// Release buffer from infblk: this enables to garbage collect
					// the big buffer when we are done with last code-block of
					// component.
					this.infblk.Data = null;
					return null; // No more code-blocks in current tile for comp.
				}
				this.infblk = infblk; // Save local cache
				infarr = (float[]) infblk.Data;
				// Get output data array and check that there is memory to put the
				// quantized coeffs in
				outarr = (int[]) cblk.Data;
				if (outarr == null || outarr.Length < infblk.w * infblk.h)
				{
					outarr = new int[infblk.w * infblk.h];
					cblk.Data = outarr;
				}
				cblk.m = infblk.m;
				cblk.n = infblk.n;
				cblk.sb = infblk.sb;
				cblk.ulx = infblk.ulx;
				cblk.uly = infblk.uly;
				cblk.w = infblk.w;
				cblk.h = infblk.h;
				cblk.wmseScaling = infblk.wmseScaling;
				cblk.offset = 0;
				cblk.scanw = cblk.w;
			}
			
			// Cache width, height and subband of code-block
			w = cblk.w;
			h = cblk.h;
			sb = cblk.sb;
			
			if (isReversible(tIdx, c))
			{
				// Reversible only for int data
				cblk.magbits = g - 1 + src.getNomRangeBits(c) + sb.anGainExp;
				shiftBits = 31 - cblk.magbits;
				
				// Update the convertFactor field
				cblk.convertFactor = (1 << shiftBits);
				
				// Since we used getNextCodeBlock() to get the int data then
				// 'offset' is 0 and 'scanw' is the width of the code-block The
				// input and output arrays are the same (i.e. "in place")
				for (j = w * h - 1; j >= 0; j--)
				{
					tmp = (outarr[j] << shiftBits);
					outarr[j] = ((tmp < 0)?(1 << 31) | (- tmp):tmp);
				}
			}
			else
			{
				// Non-reversible, use step size
				//UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Float.floatValue' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
				float baseStep = (float) ((System.Single) qsss.getTileCompVal(tIdx, c));
				
				// Calculate magnitude bits and quantization step size 
				if (isDerived(tIdx, c))
				{
					//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
					cblk.magbits = g - 1 + sb.level - (int) System.Math.Floor(System.Math.Log(baseStep) / log2);
					stepUDR = baseStep / (1 << sb.level);
				}
				else
				{
					//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
					cblk.magbits = g - 1 - (int) System.Math.Floor(System.Math.Log(baseStep / (sb.l2Norm * (1 << sb.anGainExp))) / log2);
					stepUDR = baseStep / (sb.l2Norm * (1 << sb.anGainExp));
				}
				shiftBits = 31 - cblk.magbits;
				// Calculate step that decoder will get and use that one.
				stepUDR = convertFromExpMantissa(convertToExpMantissa(stepUDR));
				invstep = 1.0f / ((1L << (src.getNomRangeBits(c) + sb.anGainExp)) * stepUDR);
				// Normalize to magnitude bits (output fractional point)
				invstep *= (1 << (shiftBits - src.getFixedPoint(c)));
				
				// Update convertFactor and stepSize fields
				cblk.convertFactor = invstep;
				cblk.stepSize = ((1L << (src.getNomRangeBits(c) + sb.anGainExp)) * stepUDR);
				
				if (intq)
				{
					// Quantizing int data
					// Since we used getNextCodeBlock() to get the int data then
					// 'offset' is 0 and 'scanw' is the width of the code-block
					// The input and output arrays are the same (i.e. "in place")
					for (j = w * h - 1; j >= 0; j--)
					{
						//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
						tmp = (int) (outarr[j] * invstep);
						outarr[j] = ((tmp < 0)?(1 << 31) | (- tmp):tmp);
					}
				}
				else
				{
					// Quantizing float data
					for (j = w * h - 1, k = infblk.offset + (h - 1) * infblk.scanw + w - 1, jmin = w * (h - 1); j >= 0; jmin -= w)
					{
						for (; j >= jmin; k--, j--)
						{
							//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
							tmp = (int) (infarr[k] * invstep);
							outarr[j] = ((tmp < 0)?(1 << 31) | (- tmp):tmp);
						}
						// Jump to beggining of previous line in input
						k -= (infblk.scanw - w);
					}
				}
			}
			// Return the quantized code-block
			return cblk;
		}
Example #2
0
		/// <summary> Returns the next code-block in the current tile for the specified
		/// component. The order in which code-blocks are returned is not
		/// specified. However each code-block is returned only once and all
		/// code-blocks will be returned if the method is called 'N' times, where
		/// 'N' is the number of code-blocks in the tile. After all the code-blocks
		/// have been returned for the current tile calls to this method will
		/// return 'null'.
		/// 
		/// <p>When changing the current tile (through 'setTile()' or 'nextTile()')
		/// this method will always return the first code-block, as if this method
		/// was never called before for the new current tile.</p>
		/// 
		/// <p>The data returned by this method is the data in the internal buffer
		/// of this object, and thus can not be modified by the caller. The
		/// 'offset' and 'scanw' of the returned data have, in general, some
		/// non-zero value. The 'magbits' of the returned data is not set by this
		/// method and should be ignored. See the 'CBlkWTData' class.</p>
		/// 
		/// <p>The 'ulx' and 'uly' members of the returned 'CBlkWTData' object
		/// contain the coordinates of the top-left corner of the block, with
		/// respect to the tile, not the subband.</p>
		/// 
		/// </summary>
		/// <param name="c">The component for which to return the next code-block.
		/// 
		/// </param>
		/// <param name="cblk">If non-null this object will be used to return the new
		/// code-block. If null a new one will be allocated and returned.
		/// 
		/// </param>
		/// <returns> The next code-block in the current tile for component 'n', or
		/// null if all code-blocks for the current tile have been returned.
		/// 
		/// </returns>
		/// <seealso cref="CBlkWTData">
		/// 
		/// </seealso>
		public override CBlkWTData getNextInternCodeBlock(int c, CBlkWTData cblk)
		{
			int cbm, cbn, cn, cm;
			int acb0x, acb0y;
			SubbandAn sb;
			intData = (filters.getWTDataType(tIdx, c) == DataBlk.TYPE_INT);
			
			//If the source image has not been decomposed 
			if (decomposedComps[c] == null)
			{
				int k, w, h;
				DataBlk bufblk;
				System.Object dst_data;
				
				w = getTileCompWidth(tIdx, c);
				h = getTileCompHeight(tIdx, c);
				
				//Get the source image data
				if (intData)
				{
					decomposedComps[c] = new DataBlkInt(0, 0, w, h);
					bufblk = new DataBlkInt();
				}
				else
				{
					decomposedComps[c] = new DataBlkFloat(0, 0, w, h);
					bufblk = new DataBlkFloat();
				}
				
				// Get data from source line by line (this diminishes the memory
				// requirements on the data source)
				dst_data = decomposedComps[c].Data;
				int lstart = getCompULX(c);
				bufblk.ulx = lstart;
				bufblk.w = w;
				bufblk.h = 1;
				int kk = getCompULY(c);
				for (k = 0; k < h; k++, kk++)
				{
					bufblk.uly = kk;
					bufblk.ulx = lstart;
					bufblk = src.getInternCompData(bufblk, c);
                    // CONVERSION PROBLEM?
					Array.Copy((System.Array)bufblk.Data, bufblk.offset, (System.Array)dst_data, k * w, w);
				}
				
				//Decompose source image
				waveletTreeDecomposition(decomposedComps[c], getAnSubbandTree(tIdx, c), c);
				
				// Make the first subband the current one
				currentSubband[c] = getNextSubband(c);
				
				lastn[c] = - 1;
				lastm[c] = 0;
			}
			
			// Get the next code-block to "send"
			do 
			{
				// Calculate number of code-blocks in current subband
				ncblks = currentSubband[c].numCb;
				// Goto next code-block
				lastn[c]++;
				if (lastn[c] == ncblks.x)
				{
					// Got to end of this row of
					// code-blocks
					lastn[c] = 0;
					lastm[c]++;
				}
				if (lastm[c] < ncblks.y)
				{
					// Not past the last code-block in the subband, we can return
					// this code-block
					break;
				}
				// If we get here we already sent all code-blocks in this subband,
				// goto next subband
				currentSubband[c] = getNextSubband(c);
				lastn[c] = - 1;
				lastm[c] = 0;
				if (currentSubband[c] == null)
				{
					// We don't need the transformed data any more (a priori)
					decomposedComps[c] = null;
					// All code-blocks from all subbands in the current
					// tile have been returned so we return a null
					// reference
					return null;
				}
				// Loop to find the next code-block
			}
			while (true);
			
			
			// Project code-block partition origin to subband. Since the origin is
			// always 0 or 1, it projects to the low-pass side (throught the ceil
			// operator) as itself (i.e. no change) and to the high-pass side
			// (through the floor operator) as 0, always.
			acb0x = cb0x;
			acb0y = cb0y;
			switch (currentSubband[c].sbandIdx)
			{
				
				case Subband.WT_ORIENT_LL: 
					// No need to project since all low-pass => nothing to do
					break;
				
				case Subband.WT_ORIENT_HL: 
					acb0x = 0;
					break;
				
				case Subband.WT_ORIENT_LH: 
					acb0y = 0;
					break;
				
				case Subband.WT_ORIENT_HH: 
					acb0x = 0;
					acb0y = 0;
					break;
				
				default: 
					throw new System.ApplicationException("Internal JJ2000 error");
				
			}
			
			// Initialize output code-block
			if (cblk == null)
			{
				if (intData)
				{
					cblk = new CBlkWTDataInt();
				}
				else
				{
					cblk = new CBlkWTDataFloat();
				}
			}
			cbn = lastn[c];
			cbm = lastm[c];
			sb = currentSubband[c];
			cblk.n = cbn;
			cblk.m = cbm;
			cblk.sb = sb;
			// Calculate the indexes of first code-block in subband with respect
			// to the partitioning origin, to then calculate the position and size
			// NOTE: when calculating "floor()" by integer division the dividend
			// and divisor must be positive, we ensure that by adding the divisor
			// to the dividend and then substracting 1 to the result of the
			// division
			cn = (sb.ulcx - acb0x + sb.nomCBlkW) / sb.nomCBlkW - 1;
			cm = (sb.ulcy - acb0y + sb.nomCBlkH) / sb.nomCBlkH - 1;
			if (cbn == 0)
			{
				// Left-most code-block, starts where subband starts
				cblk.ulx = sb.ulx;
			}
			else
			{
				// Calculate starting canvas coordinate and convert to subb. coords
				cblk.ulx = (cn + cbn) * sb.nomCBlkW - (sb.ulcx - acb0x) + sb.ulx;
			}
			if (cbm == 0)
			{
				// Bottom-most code-block, starts where subband starts
				cblk.uly = sb.uly;
			}
			else
			{
				cblk.uly = (cm + cbm) * sb.nomCBlkH - (sb.ulcy - acb0y) + sb.uly;
			}
			if (cbn < ncblks.x - 1)
			{
				// Calculate where next code-block starts => width
				cblk.w = (cn + cbn + 1) * sb.nomCBlkW - (sb.ulcx - acb0x) + sb.ulx - cblk.ulx;
			}
			else
			{
				// Right-most code-block, ends where subband ends
				cblk.w = sb.ulx + sb.w - cblk.ulx;
			}
			if (cbm < ncblks.y - 1)
			{
				// Calculate where next code-block starts => height
				cblk.h = (cm + cbm + 1) * sb.nomCBlkH - (sb.ulcy - acb0y) + sb.uly - cblk.uly;
			}
			else
			{
				// Bottom-most code-block, ends where subband ends
				cblk.h = sb.uly + sb.h - cblk.uly;
			}
			cblk.wmseScaling = 1f;
			
			// Since we are in getNextInternCodeBlock() we can return a
			// reference to the internal buffer, no need to copy. Just initialize
			// the 'offset' and 'scanw'
			cblk.offset = cblk.uly * decomposedComps[c].w + cblk.ulx;
			cblk.scanw = decomposedComps[c].w;
			
			// For the data just put a reference to our buffer
			cblk.Data = decomposedComps[c].Data;
			// Return code-block
			return cblk;
		}
Example #3
0
        /// <summary> Returns the next code-block in the current tile for the specified
        /// component. The order in which code-blocks are returned is not
        /// specified. However each code-block is returned only once and all
        /// code-blocks will be returned if the method is called 'N' times, where
        /// 'N' is the number of code-blocks in the tile. After all the code-blocks
        /// have been returned for the current tile calls to this method will
        /// return 'null'.
        ///
        /// <p>When changing the current tile (through 'setTile()' or 'nextTile()')
        /// this method will always return the first code-block, as if this method
        /// was never called before for the new current tile.</p>
        ///
        /// <p>The data returned by this method is the data in the internal buffer
        /// of this object, and thus can not be modified by the caller. The
        /// 'offset' and 'scanw' of the returned data have, in general, some
        /// non-zero value. The 'magbits' of the returned data is not set by this
        /// method and should be ignored. See the 'CBlkWTData' class.</p>
        ///
        /// <p>The 'ulx' and 'uly' members of the returned 'CBlkWTData' object
        /// contain the coordinates of the top-left corner of the block, with
        /// respect to the tile, not the subband.</p>
        ///
        /// </summary>
        /// <param name="c">The component for which to return the next code-block.
        ///
        /// </param>
        /// <param name="cblk">If non-null this object will be used to return the new
        /// code-block. If null a new one will be allocated and returned.
        ///
        /// </param>
        /// <returns> The next code-block in the current tile for component 'n', or
        /// null if all code-blocks for the current tile have been returned.
        ///
        /// </returns>
        /// <seealso cref="CBlkWTData">
        ///
        /// </seealso>
        public override CBlkWTData getNextInternCodeBlock(int c, CBlkWTData cblk)
        {
            int       cbm, cbn, cn, cm;
            int       acb0x, acb0y;
            SubbandAn sb;

            intData = (filters.getWTDataType(tIdx, c) == DataBlk.TYPE_INT);

            //If the source image has not been decomposed
            if (decomposedComps[c] == null)
            {
                int           k, w, h;
                DataBlk       bufblk;
                System.Object dst_data;

                w = getTileCompWidth(tIdx, c);
                h = getTileCompHeight(tIdx, c);

                //Get the source image data
                if (intData)
                {
                    decomposedComps[c] = new DataBlkInt(0, 0, w, h);
                    bufblk             = new DataBlkInt();
                }
                else
                {
                    decomposedComps[c] = new DataBlkFloat(0, 0, w, h);
                    bufblk             = new DataBlkFloat();
                }

                // Get data from source line by line (this diminishes the memory
                // requirements on the data source)
                dst_data = decomposedComps[c].Data;
                int lstart = getCompULX(c);
                bufblk.ulx = lstart;
                bufblk.w   = w;
                bufblk.h   = 1;
                int kk = getCompULY(c);
                for (k = 0; k < h; k++, kk++)
                {
                    bufblk.uly = kk;
                    bufblk.ulx = lstart;
                    bufblk     = src.getInternCompData(bufblk, c);
                    // CONVERSION PROBLEM?
                    Array.Copy((System.Array)bufblk.Data, bufblk.offset, (System.Array)dst_data, k * w, w);
                }

                //Decompose source image
                waveletTreeDecomposition(decomposedComps[c], getAnSubbandTree(tIdx, c), c);

                // Make the first subband the current one
                currentSubband[c] = getNextSubband(c);

                lastn[c] = -1;
                lastm[c] = 0;
            }

            // Get the next code-block to "send"
            do
            {
                // Calculate number of code-blocks in current subband
                ncblks = currentSubband[c].numCb;
                // Goto next code-block
                lastn[c]++;
                if (lastn[c] == ncblks.x)
                {
                    // Got to end of this row of
                    // code-blocks
                    lastn[c] = 0;
                    lastm[c]++;
                }
                if (lastm[c] < ncblks.y)
                {
                    // Not past the last code-block in the subband, we can return
                    // this code-block
                    break;
                }
                // If we get here we already sent all code-blocks in this subband,
                // goto next subband
                currentSubband[c] = getNextSubband(c);
                lastn[c]          = -1;
                lastm[c]          = 0;
                if (currentSubband[c] == null)
                {
                    // We don't need the transformed data any more (a priori)
                    decomposedComps[c] = null;
                    // All code-blocks from all subbands in the current
                    // tile have been returned so we return a null
                    // reference
                    return(null);
                }
                // Loop to find the next code-block
            }while (true);


            // Project code-block partition origin to subband. Since the origin is
            // always 0 or 1, it projects to the low-pass side (throught the ceil
            // operator) as itself (i.e. no change) and to the high-pass side
            // (through the floor operator) as 0, always.
            acb0x = cb0x;
            acb0y = cb0y;
            switch (currentSubband[c].sbandIdx)
            {
            case Subband.WT_ORIENT_LL:
                // No need to project since all low-pass => nothing to do
                break;

            case Subband.WT_ORIENT_HL:
                acb0x = 0;
                break;

            case Subband.WT_ORIENT_LH:
                acb0y = 0;
                break;

            case Subband.WT_ORIENT_HH:
                acb0x = 0;
                acb0y = 0;
                break;

            default:
                throw new System.ApplicationException("Internal JJ2000 error");
            }

            // Initialize output code-block
            if (cblk == null)
            {
                if (intData)
                {
                    cblk = new CBlkWTDataInt();
                }
                else
                {
                    cblk = new CBlkWTDataFloat();
                }
            }
            cbn     = lastn[c];
            cbm     = lastm[c];
            sb      = currentSubband[c];
            cblk.n  = cbn;
            cblk.m  = cbm;
            cblk.sb = sb;
            // Calculate the indexes of first code-block in subband with respect
            // to the partitioning origin, to then calculate the position and size
            // NOTE: when calculating "floor()" by integer division the dividend
            // and divisor must be positive, we ensure that by adding the divisor
            // to the dividend and then substracting 1 to the result of the
            // division
            cn = (sb.ulcx - acb0x + sb.nomCBlkW) / sb.nomCBlkW - 1;
            cm = (sb.ulcy - acb0y + sb.nomCBlkH) / sb.nomCBlkH - 1;
            if (cbn == 0)
            {
                // Left-most code-block, starts where subband starts
                cblk.ulx = sb.ulx;
            }
            else
            {
                // Calculate starting canvas coordinate and convert to subb. coords
                cblk.ulx = (cn + cbn) * sb.nomCBlkW - (sb.ulcx - acb0x) + sb.ulx;
            }
            if (cbm == 0)
            {
                // Bottom-most code-block, starts where subband starts
                cblk.uly = sb.uly;
            }
            else
            {
                cblk.uly = (cm + cbm) * sb.nomCBlkH - (sb.ulcy - acb0y) + sb.uly;
            }
            if (cbn < ncblks.x - 1)
            {
                // Calculate where next code-block starts => width
                cblk.w = (cn + cbn + 1) * sb.nomCBlkW - (sb.ulcx - acb0x) + sb.ulx - cblk.ulx;
            }
            else
            {
                // Right-most code-block, ends where subband ends
                cblk.w = sb.ulx + sb.w - cblk.ulx;
            }
            if (cbm < ncblks.y - 1)
            {
                // Calculate where next code-block starts => height
                cblk.h = (cm + cbm + 1) * sb.nomCBlkH - (sb.ulcy - acb0y) + sb.uly - cblk.uly;
            }
            else
            {
                // Bottom-most code-block, ends where subband ends
                cblk.h = sb.uly + sb.h - cblk.uly;
            }
            cblk.wmseScaling = 1f;

            // Since we are in getNextInternCodeBlock() we can return a
            // reference to the internal buffer, no need to copy. Just initialize
            // the 'offset' and 'scanw'
            cblk.offset = cblk.uly * decomposedComps[c].w + cblk.ulx;
            cblk.scanw  = decomposedComps[c].w;

            // For the data just put a reference to our buffer
            cblk.Data = decomposedComps[c].Data;
            // Return code-block
            return(cblk);
        }