Beispiel #1
0
		/// <summary> Performs the cleanup pass on the specified data and bit-plane. It codes
		/// all insignificant samples which have its "visited" state bit off, using
		/// the ZC, SC, and RLC primitives. It toggles the "visited" state bit to 0
		/// (off) for all samples in the code-block.
		/// 
		/// </summary>
		/// <param name="srcblk">The code-block data to code
		/// 
		/// </param>
		/// <param name="mq">The MQ-coder to use
		/// 
		/// </param>
		/// <param name="doterm">If true it performs an MQ-coder termination after the end
		/// of the pass
		/// 
		/// </param>
		/// <param name="bp">The bit-plane to code
		/// 
		/// </param>
		/// <param name="state">The state information for the code-block
		/// 
		/// </param>
		/// <param name="fs">The distortion estimation lookup table for SC
		/// 
		/// </param>
		/// <param name="zc_lut">The ZC lookup table to use in ZC.
		/// 
		/// </param>
		/// <param name="symbuf">The buffer to hold symbols to send to the MQ coder
		/// 
		/// </param>
		/// <param name="ctxtbuf">A buffer to hold the contexts to use in sending the
		/// buffered symbols to the MQ coder.
		/// 
		/// </param>
		/// <param name="ratebuf">The buffer where to store the rate (i.e. coded lenth) at 
		/// the end of this coding pass.
		/// 
		/// </param>
		/// <param name="pidx">The coding pass index. Is the index in the 'ratebuf' array
		/// where to store the coded length after this coding pass.
		/// 
		/// </param>
		/// <param name="ltpidx">The index of the last pass that was terminated, or
		/// negative if none.
		/// 
		/// </param>
		/// <param name="options">The bitmask of entropy coding options to apply to the
		/// code-block
		/// 
		/// </param>
		/// <returns> The decrease in distortion for this pass, in the fixed-point
		/// normalized representation of the 'FS_LOSSY' and 'FS_LOSSLESS' tables.
		/// 
		/// </returns>
		static private int cleanuppass(CBlkWTData srcblk, MQCoder mq, bool doterm, int bp, int[] state, int[] fs, int[] zc_lut, int[] symbuf, int[] ctxtbuf, int[] ratebuf, int pidx, int ltpidx, int options)
		{
			// NOTE: The speedup mode of the MQ coder has been briefly tried to
			// speed up the coding of insignificants RLCs, without any success
			// (i.e. no speedup whatsoever). The use of the speedup mode should be
			// revisisted more in depth and the implementationn of it in MQCoder
			// should be reviewed for optimization opportunities.
			int j, sj; // The state index for line and stripe
			int k, sk; // The data index for line and stripe
			int nsym = 0; // Symbol counter for symbol and context buffers
			int dscanw; // The data scan-width
			int sscanw; // The state scan-width
			int jstep; // Stripe to stripe step for 'sj'
			int kstep; // Stripe to stripe step for 'sk'
			int stopsk; // The loop limit on the variable sk
			int csj; // Local copy (i.e. cached) of 'state[j]'
			int mask; // The mask for the current bit-plane
			int sym; // The symbol to code
			int rlclen; // Length of RLC
			int ctxt; // The context to use
			int[] data; // The data buffer
			int dist; // The distortion reduction for this pass
			int shift; // Shift amount for distortion
			int upshift; // Shift left amount for distortion
			int downshift; // Shift right amount for distortion
			int normval; // The normalized sample magnitude value
			int s; // The stripe index
			bool causal; // Flag to indicate if stripe-causal context
			// formation is to be used
			int nstripes; // The number of stripes in the code-block
			int sheight; // Height of the current stripe
			int off_ul, off_ur, off_dr, off_dl; // offsets
			
			// Initialize local variables
			dscanw = srcblk.scanw;
			sscanw = srcblk.w + 2;
			jstep = sscanw * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT / 2 - srcblk.w;
			kstep = dscanw * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT - srcblk.w;
			mask = 1 << bp;
			data = (int[]) srcblk.Data;
			nstripes = (srcblk.h + CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT - 1) / CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT;
			dist = 0;
			// We use the MSE_LKP_BITS-1 bits below the bit just coded for
			// distortion estimation.
			shift = bp - (MSE_LKP_BITS - 1);
			upshift = (shift >= 0)?0:- shift;
			downshift = (shift <= 0)?0:shift;
			causal = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_VERT_STR_CAUSAL) != 0;
			
			// Pre-calculate offsets in 'state' for diagonal neighbors
			off_ul = - sscanw - 1; // up-left
			off_ur = - sscanw + 1; // up-right
			off_dr = sscanw + 1; // down-right
			off_dl = sscanw - 1; // down-left
			
			// Code stripe by stripe
			sk = srcblk.offset;
			sj = sscanw + 1;
			for (s = nstripes - 1; s >= 0; s--, sk += kstep, sj += jstep)
			{
				sheight = (s != 0)?CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT:srcblk.h - (nstripes - 1) * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT;
				stopsk = sk + srcblk.w;
				// Scan by set of 1 stripe column at a time
				for (nsym = 0; sk < stopsk; sk++, sj++)
				{
					// Start column
					j = sj;
					csj = state[j];
					{
						// Check for RLC: if all samples are not significant, not
						// visited and do not have a non-zero context, and column
						// is full height, we do RLC.
						if (csj == 0 && state[j + sscanw] == 0 && sheight == CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT)
						{
							k = sk;
							if ((data[k] & mask) != 0)
							{
								rlclen = 0;
							}
							else if ((data[k += dscanw] & mask) != 0)
							{
								rlclen = 1;
							}
							else if ((data[k += dscanw] & mask) != 0)
							{
								rlclen = 2;
								j += sscanw;
								csj = state[j];
							}
							else if ((data[k += dscanw] & mask) != 0)
							{
								rlclen = 3;
								j += sscanw;
								csj = state[j];
							}
							else
							{
								// Code insignificant RLC
								symbuf[nsym] = 0;
								ctxtbuf[nsym++] = RLC_CTXT;
								// Goto next column
								continue;
							}
							// Code significant RLC
							symbuf[nsym] = 1;
							ctxtbuf[nsym++] = RLC_CTXT;
							// Send MSB bit index
							symbuf[nsym] = rlclen >> 1;
							ctxtbuf[nsym++] = UNIF_CTXT;
							// Send LSB bit index
							symbuf[nsym] = rlclen & 0x01;
							ctxtbuf[nsym++] = UNIF_CTXT;
							// Code sign of sample that became significant
							// Update distortion
							normval = (data[k] >> downshift) << upshift;
							dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
							// Apply sign coding
							sym = SupportClass.URShift(data[k], 31);
							if ((rlclen & 0x01) == 0)
							{
								// Sample that became significant is first row of
								// its column half
								ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R1)) & SC_MASK];
								symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
								ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
								// Update state information (significant bit,
								// visited bit, neighbor significant bit of
								// neighbors, non zero context of neighbors, sign
								// of neighbors)
								if (rlclen != 0 || !causal)
								{
									// If in causal mode do not change contexts of 
									// previous stripe.
									state[j + off_ul] |= STATE_NZ_CTXT_R2 | STATE_D_DR_R2;
									state[j + off_ur] |= STATE_NZ_CTXT_R2 | STATE_D_DL_R2;
								}
								// Update sign state information of neighbors
								if (sym != 0)
								{
									csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2 | STATE_V_U_SIGN_R2;
									if (rlclen != 0 || !causal)
									{
										// If in causal mode do not change
										// contexts of previous stripe.
										state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2 | STATE_V_D_SIGN_R2;
									}
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_H_L_SIGN_R1 | STATE_D_UL_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_H_R_SIGN_R1 | STATE_D_UR_R2;
								}
								else
								{
									csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2;
									if (rlclen != 0 || !causal)
									{
										// If in causal mode do not change
										// contexts of previous stripe.
										state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2;
									}
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_D_UL_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_D_UR_R2;
								}
								// Changes to csj are saved later
								if ((rlclen >> 1) != 0)
								{
									// Sample that became significant is in bottom
									// half of column => jump to bottom half
									//UPGRADE_NOTE: Labeled break statement was changed to a goto statement. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1012'"
									goto top_half_brk;
								}
								// Otherwise sample that became significant is in
								// top half of column => continue on top half
							}
							else
							{
								// Sample that became significant is second row of
								// its column half
								ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R2)) & SC_MASK];
								symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
								ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
								// Update state information (significant bit,
								// neighbor significant bit of neighbors, non zero
								// context of neighbors, sign of neighbors)
								state[j + off_dl] |= STATE_NZ_CTXT_R1 | STATE_D_UR_R1;
								state[j + off_dr] |= STATE_NZ_CTXT_R1 | STATE_D_UL_R1;
								// Update sign state information of neighbors
								if (sym != 0)
								{
									csj |= STATE_SIG_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1 | STATE_V_D_SIGN_R1;
									state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1 | STATE_V_U_SIGN_R1;
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2 | STATE_H_L_SIGN_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2 | STATE_H_R_SIGN_R2;
								}
								else
								{
									csj |= STATE_SIG_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1;
									state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1;
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2;
								}
								// Save changes to csj
								state[j] = csj;
								if ((rlclen >> 1) != 0)
								{
									// Sample that became significant is in bottom
									// half of column => we're done with this
									// column
									continue;
								}
								// Otherwise sample that became significant is in
								// top half of column => we're done with top
								// column
								j += sscanw;
								csj = state[j];
								//UPGRADE_NOTE: Labeled break statement was changed to a goto statement. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1012'"
								goto top_half_brk;
							}
						}
						// Do half top of column
						// If any of the two samples is not significant and has
						// not been visited in the current bit-plane we can not
						// skip them
						if ((((csj >> 1) | csj) & VSTD_MASK_R1R2) != VSTD_MASK_R1R2)
						{
							k = sk;
							// Scan first row
							if ((csj & (STATE_SIG_R1 | STATE_VISITED_R1)) == 0)
							{
								// Apply zero coding
								ctxtbuf[nsym] = zc_lut[csj & ZC_MASK];
								if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
								{
									// Became significant
									// Apply sign coding
									sym = SupportClass.URShift(data[k], 31);
									ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R1)) & SC_MASK];
									symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
									ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
									// Update state information (significant bit,
									// visited bit, neighbor significant bit of
									// neighbors, non zero context of neighbors,
									// sign of neighbors)
									if (!causal)
									{
										// If in causal mode do not change
										// contexts of previous stripe.
										state[j + off_ul] |= STATE_NZ_CTXT_R2 | STATE_D_DR_R2;
										state[j + off_ur] |= STATE_NZ_CTXT_R2 | STATE_D_DL_R2;
									}
									// Update sign state information of neighbors
									if (sym != 0)
									{
										csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2 | STATE_V_U_SIGN_R2;
										if (!causal)
										{
											// If in causal mode do not change
											// contexts of previous stripe.
											state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2 | STATE_V_D_SIGN_R2;
										}
										state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_H_L_SIGN_R1 | STATE_D_UL_R2;
										state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_H_R_SIGN_R1 | STATE_D_UR_R2;
									}
									else
									{
										csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2;
										if (!causal)
										{
											// If in causal mode do not change
											// contexts of previous stripe.
											state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2;
										}
										state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_D_UL_R2;
										state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_D_UR_R2;
									}
									// Update distortion
									normval = (data[k] >> downshift) << upshift;
									dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
								}
							}
							if (sheight < 2)
							{
								csj &= ~ (STATE_VISITED_R1 | STATE_VISITED_R2);
								state[j] = csj;
								continue;
							}
							// Scan second row
							if ((csj & (STATE_SIG_R2 | STATE_VISITED_R2)) == 0)
							{
								k += dscanw;
								// Apply zero coding
								ctxtbuf[nsym] = zc_lut[(SupportClass.URShift(csj, STATE_SEP)) & ZC_MASK];
								if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
								{
									// Became significant
									// Apply sign coding
									sym = SupportClass.URShift(data[k], 31);
									ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R2)) & SC_MASK];
									symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
									ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
									// Update state information (significant bit,
									// visited bit, neighbor significant bit of
									// neighbors, non zero context of neighbors,
									// sign of neighbors)
									state[j + off_dl] |= STATE_NZ_CTXT_R1 | STATE_D_UR_R1;
									state[j + off_dr] |= STATE_NZ_CTXT_R1 | STATE_D_UL_R1;
									// Update sign state information of neighbors
									if (sym != 0)
									{
										csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1 | STATE_V_D_SIGN_R1;
										state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1 | STATE_V_U_SIGN_R1;
										state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2 | STATE_H_L_SIGN_R2;
										state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2 | STATE_H_R_SIGN_R2;
									}
									else
									{
										csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1;
										state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1;
										state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2;
										state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2;
									}
									// Update distortion
									normval = (data[k] >> downshift) << upshift;
									dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
								}
							}
						}
						csj &= ~ (STATE_VISITED_R1 | STATE_VISITED_R2);
						state[j] = csj;
						// Do half bottom of column
						if (sheight < 3)
							continue;
						j += sscanw;
						csj = state[j];
					}
					//UPGRADE_NOTE: Label 'top_half_brk' was added. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1011'"

top_half_brk: ;
					 // end of 'top_half' block
					// If any of the two samples is not significant and has
					// not been visited in the current bit-plane we can not
					// skip them
					if ((((csj >> 1) | csj) & VSTD_MASK_R1R2) != VSTD_MASK_R1R2)
					{
						k = sk + (dscanw << 1);
						// Scan first row
						if ((csj & (STATE_SIG_R1 | STATE_VISITED_R1)) == 0)
						{
							// Apply zero coding
							ctxtbuf[nsym] = zc_lut[csj & ZC_MASK];
							if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
							{
								// Became significant
								// Apply sign coding
								sym = SupportClass.URShift(data[k], 31);
								ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R1)) & SC_MASK];
								symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
								ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
								// Update state information (significant bit,
								// visited bit, neighbor significant bit of
								// neighbors, non zero context of neighbors,
								// sign of neighbors)
								state[j + off_ul] |= STATE_NZ_CTXT_R2 | STATE_D_DR_R2;
								state[j + off_ur] |= STATE_NZ_CTXT_R2 | STATE_D_DL_R2;
								// Update sign state information of neighbors
								if (sym != 0)
								{
									csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2 | STATE_V_U_SIGN_R2;
									state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2 | STATE_V_D_SIGN_R2;
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_H_L_SIGN_R1 | STATE_D_UL_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_H_R_SIGN_R1 | STATE_D_UR_R2;
								}
								else
								{
									csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2;
									state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2;
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_D_UL_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_D_UR_R2;
								}
								// Update distortion
								normval = (data[k] >> downshift) << upshift;
								dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
							}
						}
						if (sheight < 4)
						{
							csj &= ~ (STATE_VISITED_R1 | STATE_VISITED_R2);
							state[j] = csj;
							continue;
						}
						// Scan second row
						if ((csj & (STATE_SIG_R2 | STATE_VISITED_R2)) == 0)
						{
							k += dscanw;
							// Apply zero coding
							ctxtbuf[nsym] = zc_lut[(SupportClass.URShift(csj, STATE_SEP)) & ZC_MASK];
							if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
							{
								// Became significant
								// Apply sign coding
								sym = SupportClass.URShift(data[k], 31);
								ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R2)) & SC_MASK];
								symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
								ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
								// Update state information (significant bit,
								// visited bit, neighbor significant bit of
								// neighbors, non zero context of neighbors,
								// sign of neighbors)
								state[j + off_dl] |= STATE_NZ_CTXT_R1 | STATE_D_UR_R1;
								state[j + off_dr] |= STATE_NZ_CTXT_R1 | STATE_D_UL_R1;
								// Update sign state information of neighbors
								if (sym != 0)
								{
									csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1 | STATE_V_D_SIGN_R1;
									state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1 | STATE_V_U_SIGN_R1;
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2 | STATE_H_L_SIGN_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2 | STATE_H_R_SIGN_R2;
								}
								else
								{
									csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1;
									state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1;
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2;
								}
								// Update distortion
								normval = (data[k] >> downshift) << upshift;
								dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
							}
						}
					}
					csj &= ~ (STATE_VISITED_R1 | STATE_VISITED_R2);
					state[j] = csj;
				}
				// Code all buffered symbols, if any
				if (nsym > 0)
					mq.codeSymbols(symbuf, ctxtbuf, nsym);
			}
			
			// Insert a segment marker if we need to
			if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_SEG_SYMBOLS) != 0)
			{
				mq.codeSymbols(SEG_SYMBOLS, SEG_SYMB_CTXTS, SEG_SYMBOLS.Length);
			}
			
			// Reset the MQ context states if we need to
			if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_RESET_MQ) != 0)
			{
				mq.resetCtxts();
			}
			
			// Terminate the MQ bit stream if we need to
			if (doterm)
			{
				ratebuf[pidx] = mq.terminate(); // Termination has special length
			}
			else
			{
				// Use normal length calculation
				ratebuf[pidx] = mq.NumCodedBytes;
			}
			// Add length of previous segments, if any
			if (ltpidx >= 0)
			{
				ratebuf[pidx] += ratebuf[ltpidx];
			}
			// Finish length calculation if needed
			if (doterm)
			{
				mq.finishLengthCalculation(ratebuf, pidx);
			}
			// Return the reduction in distortion
			return dist;
		}
Beispiel #2
0
		/// <summary> Compresses the code-block in 'srcblk' and puts the results in 'ccb',
		/// using the specified options and temporary storage.
		/// 
		/// </summary>
		/// <param name="c">The component for which to return the next code-block.
		/// 
		/// </param>
		/// <param name="ccb">The object where the compressed data will be stored. If the
		/// 'data' array of 'cbb' is not null it may be reused to return the
		/// compressed data.
		/// 
		/// </param>
		/// <param name="srcblk">The code-block data to code
		/// 
		/// </param>
		/// <param name="mq">The MQ-coder to use
		/// 
		/// </param>
		/// <param name="bout">The bit level output to use. Used only if 'OPT_BYPASS' is
		/// turned on in the 'options' argument.
		/// 
		/// </param>
		/// <param name="out">The byte buffer trough which the compressed data is stored.
		/// 
		/// </param>
		/// <param name="state">The state information for the code-block
		/// 
		/// </param>
		/// <param name="distbuf">The buffer where to store the distortion  at 
		/// the end of each coding pass.
		/// 
		/// </param>
		/// <param name="ratebuf">The buffer where to store the rate (i.e. coded lenth) at 
		/// the end of each coding pass.
		/// 
		/// </param>
		/// <param name="istermbuf">The buffer where to store the terminated flag for each 
		/// coding pass.
		/// 
		/// </param>
		/// <param name="symbuf">The buffer to hold symbols to send to the MQ coder
		/// 
		/// </param>
		/// <param name="ctxtbuf">A buffer to hold the contexts to use in sending the
		/// buffered symbols to the MQ coder.
		/// 
		/// </param>
		/// <param name="options">The options to use when coding this code-block
		/// 
		/// </param>
		/// <param name="rev">The reversible flag. Should be true if the source of this
		/// code-block's data is reversible.
		/// 
		/// </param>
		/// <param name="lcType">The type of length calculation to use with the MQ coder.
		/// 
		/// </param>
		/// <param name="tType">The type of termination to use with the MQ coder.
		/// 
		/// </param>
		/// <seealso cref="getNextCodeBlock">
		/// 
		/// </seealso>
		static private void  compressCodeBlock(int c, CBlkRateDistStats ccb, CBlkWTData srcblk, MQCoder mq, BitToByteOutput bout, ByteOutputBuffer out_Renamed, int[] state, double[] distbuf, int[] ratebuf, bool[] istermbuf, int[] symbuf, int[] ctxtbuf, int options, bool rev, int lcType, int tType)
		{
			// NOTE: This method should not access any non-final instance or
			// static variables, either directly or indirectly through other
			// methods in order to be sure that the method is thread safe.
			
			int[] zc_lut; // The ZC lookup table to use
			int skipbp; // The number of non-significant bit-planes to skip
			int curbp; // The current magnitude bit-plane (starts at 30)
			int[] fm; // The distortion estimation lookup table for MR
			int[] fs; // The distortion estimation lookup table for SC
			int lmb; // The least significant magnitude bit
			int npass; // The number of coding passes, for R-D statistics
			double msew; // The distortion (MSE weight) for the current bit-plane
			double totdist; // The total cumulative distortion decrease
			int ltpidx; // The index of the last pass which is terminated
			
			// Check error-resilient termination
			if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_PRED_TERM) != 0 && tType != MQCoder.TERM_PRED_ER)
			{
				throw new System.ArgumentException("Embedded error-resilient info " + "in MQ termination option " + "specified but incorrect MQ " + "termination " + "policy specified");
			}
			// Set MQ flags
			mq.LenCalcType = lcType;
			mq.TermType = tType;
			
			lmb = 30 - srcblk.magbits + 1;
			// If there are more bit-planes to code than the implementation
			// bit-depth set lmb to 0
			lmb = (lmb < 0)?0:lmb;
			
			// Reset state
			ArrayUtil.intArraySet(state, 0);
			
			// Find the most significant bit-plane
			skipbp = calcSkipMSBP(srcblk, lmb);
			
			// Initialize output code-block
			ccb.m = srcblk.m;
			ccb.n = srcblk.n;
			ccb.sb = srcblk.sb;
			ccb.nROIcoeff = srcblk.nROIcoeff;
			ccb.skipMSBP = skipbp;
			if (ccb.nROIcoeff != 0)
			{
				ccb.nROIcp = 3 * (srcblk.nROIbp - skipbp - 1) + 1;
			}
			else
			{
				ccb.nROIcp = 0;
			}
			
			// Choose correct ZC lookup table for global orientation
			switch (srcblk.sb.orientation)
			{
				
				case Subband.WT_ORIENT_HL: 
					zc_lut = ZC_LUT_HL;
					break;
				
				case Subband.WT_ORIENT_LL: 
				case Subband.WT_ORIENT_LH: 
					zc_lut = ZC_LUT_LH;
					break;
				
				case Subband.WT_ORIENT_HH: 
					zc_lut = ZC_LUT_HH;
					break;
				
				default: 
					throw new System.InvalidOperationException("JJ2000 internal error");
				
			}
			
			// Loop on significant magnitude bit-planes doing the 3 passes
			curbp = 30 - skipbp;
			fs = FS_LOSSY;
			fm = FM_LOSSY;
			msew = System.Math.Pow(2, ((curbp - lmb) << 1) - MSE_LKP_FRAC_BITS) * srcblk.sb.stepWMSE * srcblk.wmseScaling;
			totdist = 0f;
			npass = 0;
			ltpidx = - 1;
			
			// First significant bit-plane has only the pass pass
			if (curbp >= lmb)
			{
				// Do we need the "lossless" 'fs' table ?
				if (rev && curbp == lmb)
				{
					fs = FM_LOSSLESS;
				}
				// We terminate if regular termination, last bit-plane, or next
				// bit-plane is "raw".
				istermbuf[npass] = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || curbp == lmb || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - skipbp) >= curbp);
				totdist += cleanuppass(srcblk, mq, istermbuf[npass], curbp, state, fs, zc_lut, symbuf, ctxtbuf, ratebuf, npass, ltpidx, options) * msew;
				distbuf[npass] = totdist;
				if (istermbuf[npass])
					ltpidx = npass;
				npass++;
				msew *= 0.25;
				curbp--;
			}
			// Other bit-planes have all passes
			while (curbp >= lmb)
			{
				// Do we need the "lossless" 'fs' and 'fm' tables ?
				if (rev && curbp == lmb)
				{
					fs = FS_LOSSLESS;
					fm = FM_LOSSLESS;
				}
				
				// Do the significance propagation pass
				// We terminate if regular termination only
				istermbuf[npass] = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0;
				if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) == 0 || (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - skipbp <= curbp))
				{
					// No bypass coding
					totdist += sigProgPass(srcblk, mq, istermbuf[npass], curbp, state, fs, zc_lut, symbuf, ctxtbuf, ratebuf, npass, ltpidx, options) * msew;
				}
				else
				{
					// Bypass ("raw") coding
					bout.PredTerm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_PRED_TERM) != 0;
					totdist += rawSigProgPass(srcblk, bout, istermbuf[npass], curbp, state, fs, ratebuf, npass, ltpidx, options) * msew;
				}
				distbuf[npass] = totdist;
				if (istermbuf[npass])
					ltpidx = npass;
				npass++;
				
				// Do the magnitude refinement pass
				// We terminate if regular termination or bypass ("raw") coding
				istermbuf[npass] = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - skipbp > curbp));
				if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) == 0 || (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - skipbp <= curbp))
				{
					// No bypass coding
					totdist += magRefPass(srcblk, mq, istermbuf[npass], curbp, state, fm, symbuf, ctxtbuf, ratebuf, npass, ltpidx, options) * msew;
				}
				else
				{
					// Bypass ("raw") coding
					bout.PredTerm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_PRED_TERM) != 0;
					totdist += rawMagRefPass(srcblk, bout, istermbuf[npass], curbp, state, fm, ratebuf, npass, ltpidx, options) * msew;
				}
				distbuf[npass] = totdist;
				if (istermbuf[npass])
					ltpidx = npass;
				npass++;
				
				// Do the clenup pass
				// We terminate if regular termination, last bit-plane, or next
				// bit-plane is "raw".
				istermbuf[npass] = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || curbp == lmb || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - skipbp) >= curbp);
				totdist += cleanuppass(srcblk, mq, istermbuf[npass], curbp, state, fs, zc_lut, symbuf, ctxtbuf, ratebuf, npass, ltpidx, options) * msew;
				distbuf[npass] = totdist;
				
				if (istermbuf[npass])
					ltpidx = npass;
				npass++;
				
				// Goto next bit-plane
				msew *= 0.25;
				curbp--;
			}
			
			// Copy compressed data and rate-distortion statistics to output
			ccb.data = new byte[out_Renamed.size()];
			out_Renamed.toByteArray(0, out_Renamed.size(), ccb.data, 0);
			checkEndOfPassFF(ccb.data, ratebuf, istermbuf, npass);
			ccb.selectConvexHull(ratebuf, distbuf, (options & (CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS | CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS)) != 0?istermbuf:null, npass, rev);
			
			// Reset MQ coder and bit output for next code-block
			mq.reset();
			if (bout != null)
				bout.reset();
		}
Beispiel #3
0
		/// <summary> Performs the magnitude refinement pass on the specified data and
		/// bit-plane. It codes the samples which are significant and which do not
		/// have the "visited" state bit turned on, using the MR primitive. The
		/// "visited" state bit is not mofified for any samples.
		/// 
		/// </summary>
		/// <param name="srcblk">The code-block data to code
		/// 
		/// </param>
		/// <param name="mq">The MQ-coder to use
		/// 
		/// </param>
		/// <param name="doterm">If true it performs an MQ-coder termination after the end
		/// of the pass
		/// 
		/// </param>
		/// <param name="bp">The bit-plane to code
		/// 
		/// </param>
		/// <param name="state">The state information for the code-block
		/// 
		/// </param>
		/// <param name="fm">The distortion estimation lookup table for MR
		/// 
		/// </param>
		/// <param name="symbuf">The buffer to hold symbols to send to the MQ coder
		/// 
		/// </param>
		/// <param name="ctxtbuf">A buffer to hold the contexts to use in sending the
		/// buffered symbols to the MQ coder.
		/// 
		/// </param>
		/// <param name="ratebuf">The buffer where to store the rate (i.e. coded lenth) at 
		/// the end of this coding pass.
		/// 
		/// </param>
		/// <param name="pidx">The coding pass index. Is the index in the 'ratebuf' array
		/// where to store the coded length after this coding pass.
		/// 
		/// </param>
		/// <param name="ltpidx">The index of the last pass that was terminated, or
		/// negative if none.
		/// 
		/// </param>
		/// <param name="options">The bitmask of entropy coding options to apply to the
		/// code-block
		/// 
		/// </param>
		/// <returns> The decrease in distortion for this pass, in the fixed-point
		/// normalized representation of the 'FS_LOSSY' and 'FS_LOSSLESS' tables.
		/// 
		/// </returns>
		static private int magRefPass(CBlkWTData srcblk, MQCoder mq, bool doterm, int bp, int[] state, int[] fm, int[] symbuf, int[] ctxtbuf, int[] ratebuf, int pidx, int ltpidx, int options)
		{
			int j, sj; // The state index for line and stripe
			int k, sk; // The data index for line and stripe
			int nsym = 0; // Symbol counter for symbol and context buffers
			int dscanw; // The data scan-width
			int sscanw; // The state scan-width
			int jstep; // Stripe to stripe step for 'sj'
			int kstep; // Stripe to stripe step for 'sk'
			int stopsk; // The loop limit on the variable sk
			int csj; // Local copy (i.e. cached) of 'state[j]'
			int mask; // The mask for the current bit-plane
			int[] data; // The data buffer
			int dist; // The distortion reduction for this pass
			int shift; // Shift amount for distortion
			int upshift; // Shift left amount for distortion
			int downshift; // Shift right amount for distortion
			int normval; // The normalized sample magnitude value
			int s; // The stripe index
			int nstripes; // The number of stripes in the code-block
			int sheight; // Height of the current stripe
			
			// Initialize local variables
			dscanw = srcblk.scanw;
			sscanw = srcblk.w + 2;
			jstep = sscanw * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT / 2 - srcblk.w;
			kstep = dscanw * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT - srcblk.w;
			mask = 1 << bp;
			data = (int[]) srcblk.Data;
			nstripes = (srcblk.h + CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT - 1) / CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT;
			dist = 0;
			// We use the bit just coded plus MSE_LKP_BITS-1 bits below the bit
			// just coded for distortion estimation.
			shift = bp - (MSE_LKP_BITS - 1);
			upshift = (shift >= 0)?0:- shift;
			downshift = (shift <= 0)?0:shift;
			
			// Code stripe by stripe
			sk = srcblk.offset;
			sj = sscanw + 1;
			for (s = nstripes - 1; s >= 0; s--, sk += kstep, sj += jstep)
			{
				sheight = (s != 0)?CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT:srcblk.h - (nstripes - 1) * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT;
				stopsk = sk + srcblk.w;
				// Scan by set of 1 stripe column at a time
				for (nsym = 0; sk < stopsk; sk++, sj++)
				{
					// Do half top of column
					j = sj;
					csj = state[j];
					// If any of the two samples is significant and not yet
					// visited in the current bit-plane we can not skip them
					if ((((SupportClass.URShift(csj, 1)) & (~ csj)) & VSTD_MASK_R1R2) != 0)
					{
						k = sk;
						// Scan first row
						if ((csj & (STATE_SIG_R1 | STATE_VISITED_R1)) == STATE_SIG_R1)
						{
							// Apply MR primitive
							symbuf[nsym] = SupportClass.URShift((data[k] & mask), bp);
							ctxtbuf[nsym++] = MR_LUT[csj & MR_MASK];
							// Update the STATE_PREV_MR bit
							csj |= STATE_PREV_MR_R1;
							// Update distortion
							normval = (data[k] >> downshift) << upshift;
							dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
						}
						if (sheight < 2)
						{
							state[j] = csj;
							continue;
						}
						// Scan second row
						if ((csj & (STATE_SIG_R2 | STATE_VISITED_R2)) == STATE_SIG_R2)
						{
							k += dscanw;
							// Apply MR primitive
							symbuf[nsym] = SupportClass.URShift((data[k] & mask), bp);
							ctxtbuf[nsym++] = MR_LUT[(SupportClass.URShift(csj, STATE_SEP)) & MR_MASK];
							// Update the STATE_PREV_MR bit
							csj |= STATE_PREV_MR_R2;
							// Update distortion
							normval = (data[k] >> downshift) << upshift;
							dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
						}
						state[j] = csj;
					}
					// Do half bottom of column
					if (sheight < 3)
						continue;
					j += sscanw;
					csj = state[j];
					// If any of the two samples is significant and not yet
					// visited in the current bit-plane we can not skip them
					if ((((SupportClass.URShift(csj, 1)) & (~ csj)) & VSTD_MASK_R1R2) != 0)
					{
						k = sk + (dscanw << 1);
						// Scan first row
						if ((csj & (STATE_SIG_R1 | STATE_VISITED_R1)) == STATE_SIG_R1)
						{
							// Apply MR primitive
							symbuf[nsym] = SupportClass.URShift((data[k] & mask), bp);
							ctxtbuf[nsym++] = MR_LUT[csj & MR_MASK];
							// Update the STATE_PREV_MR bit
							csj |= STATE_PREV_MR_R1;
							// Update distortion
							normval = (data[k] >> downshift) << upshift;
							dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
						}
						if (sheight < 4)
						{
							state[j] = csj;
							continue;
						}
						// Scan second row
						if ((state[j] & (STATE_SIG_R2 | STATE_VISITED_R2)) == STATE_SIG_R2)
						{
							k += dscanw;
							// Apply MR primitive
							symbuf[nsym] = SupportClass.URShift((data[k] & mask), bp);
							ctxtbuf[nsym++] = MR_LUT[(SupportClass.URShift(csj, STATE_SEP)) & MR_MASK];
							// Update the STATE_PREV_MR bit
							csj |= STATE_PREV_MR_R2;
							// Update distortion
							normval = (data[k] >> downshift) << upshift;
							dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
						}
						state[j] = csj;
					}
				}
				// Code all buffered symbols, if any
				if (nsym > 0)
					mq.codeSymbols(symbuf, ctxtbuf, nsym);
			}
			
			// Reset the MQ context states if we need to
			if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_RESET_MQ) != 0)
			{
				mq.resetCtxts();
			}
			
			// Terminate the MQ bit stream if we need to
			if (doterm)
			{
				ratebuf[pidx] = mq.terminate(); // Termination has special length
			}
			else
			{
				// Use normal length calculation
				ratebuf[pidx] = mq.NumCodedBytes;
			}
			// Add length of previous segments, if any
			if (ltpidx >= 0)
			{
				ratebuf[pidx] += ratebuf[ltpidx];
			}
			// Finish length calculation if needed
			if (doterm)
			{
				mq.finishLengthCalculation(ratebuf, pidx);
			}
			
			// Return the reduction in distortion
			return dist;
		}
Beispiel #4
0
		/// <summary> Performs the magnitude refinement pass on the specified data and
		/// bit-plane, without using the arithmetic coder. It codes the samples
		/// which are significant and which do not have the "visited" state bit
		/// turned on, using the MR primitive. The "visited" state bit is not
		/// mofified for any samples.
		/// 
		/// <p>In this method, the arithmetic coder is bypassed, and raw bits are
		/// directly written in the bit stream (useful when distribution are close
		/// to uniform, for intance, at high bit-rates and at lossless
		/// compression). The 'STATE_PREV_MR_R1' and 'STATE_PREV_MR_R2' bits are
		/// not set because they are used only when the arithmetic coder is not
		/// bypassed.</p>
		/// 
		/// </summary>
		/// <param name="srcblk">The code-block data to code
		/// 
		/// </param>
		/// <param name="bout">The bit based output
		/// 
		/// </param>
		/// <param name="doterm">If true the bit based output is byte aligned after the
		/// end of the pass.
		/// 
		/// </param>
		/// <param name="bp">The bit-plane to code
		/// 
		/// </param>
		/// <param name="state">The state information for the code-block
		/// 
		/// </param>
		/// <param name="fm">The distortion estimation lookup table for MR
		/// 
		/// </param>
		/// <param name="ratebuf">The buffer where to store the rate (i.e. coded lenth) at 
		/// the end of this coding pass.
		/// 
		/// </param>
		/// <param name="pidx">The coding pass index. Is the index in the 'ratebuf' array
		/// where to store the coded length after this coding pass.
		/// 
		/// </param>
		/// <param name="ltpidx">The index of the last pass that was terminated, or
		/// negative if none.
		/// 
		/// </param>
		/// <param name="options">The bitmask of entropy coding options to apply to the
		/// code-block
		/// 
		/// </param>
		/// <returns> The decrease in distortion for this pass, in the fixed-point
		/// normalized representation of the 'FS_LOSSY' and 'FS_LOSSLESS' tables.
		/// 
		/// </returns>
		static private int rawMagRefPass(CBlkWTData srcblk, BitToByteOutput bout, bool doterm, int bp, int[] state, int[] fm, int[] ratebuf, int pidx, int ltpidx, int options)
		{
			int j, sj; // The state index for line and stripe
			int k, sk; // The data index for line and stripe
			int dscanw; // The data scan-width
			int sscanw; // The state scan-width
			int jstep; // Stripe to stripe step for 'sj'
			int kstep; // Stripe to stripe step for 'sk'
			int stopsk; // The loop limit on the variable sk
			int csj; // Local copy (i.e. cached) of 'state[j]'
			int mask; // The mask for the current bit-plane
			int[] data; // The data buffer
			int dist; // The distortion reduction for this pass
			int shift; // Shift amount for distortion
			int upshift; // Shift left amount for distortion
			int downshift; // Shift right amount for distortion
			int normval; // The normalized sample magnitude value
			int s; // The stripe index
			int nstripes; // The number of stripes in the code-block
			int sheight; // Height of the current stripe
			int nsym = 0;
			
			// Initialize local variables
			dscanw = srcblk.scanw;
			sscanw = srcblk.w + 2;
			jstep = sscanw * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT / 2 - srcblk.w;
			kstep = dscanw * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT - srcblk.w;
			mask = 1 << bp;
			data = (int[]) srcblk.Data;
			nstripes = (srcblk.h + CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT - 1) / CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT;
			dist = 0;
			// We use the bit just coded plus MSE_LKP_BITS-1 bits below the bit
			// just coded for distortion estimation.
			shift = bp - (MSE_LKP_BITS - 1);
			upshift = (shift >= 0)?0:- shift;
			downshift = (shift <= 0)?0:shift;
			
			// Code stripe by stripe
			sk = srcblk.offset;
			sj = sscanw + 1;
			for (s = nstripes - 1; s >= 0; s--, sk += kstep, sj += jstep)
			{
				sheight = (s != 0)?CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT:srcblk.h - (nstripes - 1) * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT;
				stopsk = sk + srcblk.w;
				// Scan by set of 1 stripe column at a time
				for (; sk < stopsk; sk++, sj++)
				{
					// Do half top of column
					j = sj;
					csj = state[j];
					// If any of the two samples is significant and not yet
					// visited in the current bit-plane we can not skip them
					if ((((SupportClass.URShift(csj, 1)) & (~ csj)) & VSTD_MASK_R1R2) != 0)
					{
						k = sk;
						// Scan first row
						if ((csj & (STATE_SIG_R1 | STATE_VISITED_R1)) == STATE_SIG_R1)
						{
							// Code bit "raw"
							bout.writeBit(SupportClass.URShift((data[k] & mask), bp));
							nsym++;
							// No need to set STATE_PREV_MR_R1 since all magnitude 
							// refinement passes to follow are "raw"
							// Update distortion
							normval = (data[k] >> downshift) << upshift;
							dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
						}
						if (sheight < 2)
							continue;
						// Scan second row
						if ((csj & (STATE_SIG_R2 | STATE_VISITED_R2)) == STATE_SIG_R2)
						{
							k += dscanw;
							// Code bit "raw"
							bout.writeBit(SupportClass.URShift((data[k] & mask), bp));
							nsym++;
							// No need to set STATE_PREV_MR_R2 since all magnitude 
							// refinement passes to follow are "raw"
							// Update distortion
							normval = (data[k] >> downshift) << upshift;
							dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
						}
					}
					// Do half bottom of column
					if (sheight < 3)
						continue;
					j += sscanw;
					csj = state[j];
					// If any of the two samples is significant and not yet
					// visited in the current bit-plane we can not skip them
					if ((((SupportClass.URShift(csj, 1)) & (~ csj)) & VSTD_MASK_R1R2) != 0)
					{
						k = sk + (dscanw << 1);
						// Scan first row
						if ((csj & (STATE_SIG_R1 | STATE_VISITED_R1)) == STATE_SIG_R1)
						{
							// Code bit "raw"
							bout.writeBit(SupportClass.URShift((data[k] & mask), bp));
							nsym++;
							// No need to set STATE_PREV_MR_R1 since all magnitude 
							// refinement passes to follow are "raw"
							// Update distortion
							normval = (data[k] >> downshift) << upshift;
							dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
						}
						if (sheight < 4)
							continue;
						// Scan second row
						if ((state[j] & (STATE_SIG_R2 | STATE_VISITED_R2)) == STATE_SIG_R2)
						{
							k += dscanw;
							// Code bit "raw"
							bout.writeBit(SupportClass.URShift((data[k] & mask), bp));
							nsym++;
							// No need to set STATE_PREV_MR_R2 since all magnitude 
							// refinement passes to follow are "raw"
							// Update distortion
							normval = (data[k] >> downshift) << upshift;
							dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
						}
					}
				}
			}
			
			// Get length and terminate if needed
			if (doterm)
			{
				ratebuf[pidx] = bout.terminate();
			}
			else
			{
				ratebuf[pidx] = bout.length();
			}
			
			// Add length of previous segments, if any
			if (ltpidx >= 0)
			{
				ratebuf[pidx] += ratebuf[ltpidx];
			}
			
			// Return the reduction in distortion
			return dist;
		}
Beispiel #5
0
		/// <summary> Calculates the number of magnitude bit-planes that are to be skipped,
		/// because they are non-significant. The algorithm looks for the largest
		/// magnitude and calculates the most significant bit-plane of it.
		/// 
		/// </summary>
		/// <param name="cblk">The code-block of data to scan
		/// 
		/// </param>
		/// <param name="lmb">The least significant magnitude bit in the data
		/// 
		/// </param>
		/// <returns> The number of magnitude bit-planes to skip (i.e. all zero most
		/// significant bit-planes).
		/// 
		/// </returns>
		static private int calcSkipMSBP(CBlkWTData cblk, int lmb)
		{
			int k, kmax, mask;
			int[] data;
			int maxmag;
			int mag;
			int w, h;
			int msbp;
			int l;
			
			data = (int[]) cblk.Data;
			w = cblk.w;
			h = cblk.h;
			
			// First look for the maximum magnitude in the code-block
			maxmag = 0;
			// Consider only magnitude bits that are in non-fractional bit-planes.
			mask = 0x7FFFFFFF & (~ ((1 << lmb) - 1));
			for (l = h - 1, k = cblk.offset; l >= 0; l--)
			{
				for (kmax = k + w; k < kmax; k++)
				{
					mag = data[k] & mask;
					if (mag > maxmag)
						maxmag = mag;
				}
				k += cblk.scanw - w;
			}
			// Now calculate the number of all zero most significant
			// bit-planes for the maximum magnitude.
			msbp = 30;
			do 
			{
				if (((1 << msbp) & maxmag) != 0)
					break;
				msbp--;
			}
			while (msbp >= lmb);
			
			// Return the number of non-significant bit-planes to skip
			return 30 - msbp;
		}
Beispiel #6
0
		/// <summary> Performs the significance propagation pass on the specified data and
		/// bit-plane, without using the arithmetic coder. It codes all
		/// insignificant samples which have, at least, one of its immediate eight
		/// neighbors already significant, using the ZC and SC primitives as
		/// needed. It toggles the "visited" state bit to 1 for all those samples.
		/// 
		/// <p>In this method, the arithmetic coder is bypassed, and raw bits are
		/// directly written in the bit stream (useful when distribution are close
		/// to uniform, for intance, at high bit-rates and at lossless
		/// compression).</p>
		/// 
		/// </summary>
		/// <param name="srcblk">The code-block data to code
		/// 
		/// </param>
		/// <param name="bout">The bit based output
		/// 
		/// </param>
		/// <param name="doterm">If true the bit based output is byte aligned after the
		/// end of the pass.
		/// 
		/// </param>
		/// <param name="bp">The bit-plane to code
		/// 
		/// </param>
		/// <param name="state">The state information for the code-block
		/// 
		/// </param>
		/// <param name="fs">The distortion estimation lookup table for SC
		/// 
		/// </param>
		/// <param name="ratebuf">The buffer where to store the rate (i.e. coded lenth) at 
		/// the end of this coding pass.
		/// 
		/// </param>
		/// <param name="pidx">The coding pass index. Is the index in the 'ratebuf' array
		/// where to store the coded length after this coding pass.
		/// 
		/// </param>
		/// <param name="ltpidx">The index of the last pass that was terminated, or
		/// negative if none.
		/// 
		/// </param>
		/// <param name="options">The bitmask of entropy coding options to apply to the
		/// code-block
		/// 
		/// </param>
		/// <returns> The decrease in distortion for this pass, in the fixed-point
		/// normalized representation of the 'FS_LOSSY' and 'FS_LOSSLESS' tables.
		/// 
		/// </returns>
		static private int rawSigProgPass(CBlkWTData srcblk, BitToByteOutput bout, bool doterm, int bp, int[] state, int[] fs, int[] ratebuf, int pidx, int ltpidx, int options)
		{
			int j, sj; // The state index for line and stripe
			int k, sk; // The data index for line and stripe
			int dscanw; // The data scan-width
			int sscanw; // The state scan-width
			int jstep; // Stripe to stripe step for 'sj'
			int kstep; // Stripe to stripe step for 'sk'
			int stopsk; // The loop limit on the variable sk
			int csj; // Local copy (i.e. cached) of 'state[j]'
			int mask; // The mask for the current bit-plane
			int nsym = 0; // Number of symbol
			int sym; // The symbol to code
			int[] data; // The data buffer
			int dist; // The distortion reduction for this pass
			int shift; // Shift amount for distortion
			int upshift; // Shift left amount for distortion
			int downshift; // Shift right amount for distortion
			int normval; // The normalized sample magnitude value
			int s; // The stripe index
			bool causal; // Flag to indicate if stripe-causal context
			// formation is to be used
			int nstripes; // The number of stripes in the code-block
			int sheight; // Height of the current stripe
			int off_ul, off_ur, off_dr, off_dl; // offsets
			
			// Initialize local variables
			dscanw = srcblk.scanw;
			sscanw = srcblk.w + 2;
			jstep = sscanw * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT / 2 - srcblk.w;
			kstep = dscanw * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT - srcblk.w;
			mask = 1 << bp;
			data = (int[]) srcblk.Data;
			nstripes = (srcblk.h + CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT - 1) / CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT;
			dist = 0;
			// We use the MSE_LKP_BITS-1 bits below the bit just coded for
			// distortion estimation.
			shift = bp - (MSE_LKP_BITS - 1);
			upshift = (shift >= 0)?0:- shift;
			downshift = (shift <= 0)?0:shift;
			causal = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_VERT_STR_CAUSAL) != 0;
			
			// Pre-calculate offsets in 'state' for neighbors
			off_ul = - sscanw - 1; // up-left
			off_ur = - sscanw + 1; // up-right
			off_dr = sscanw + 1; // down-right
			off_dl = sscanw - 1; // down-left
			
			// Code stripe by stripe
			sk = srcblk.offset;
			sj = sscanw + 1;
			for (s = nstripes - 1; s >= 0; s--, sk += kstep, sj += jstep)
			{
				sheight = (s != 0)?CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT:srcblk.h - (nstripes - 1) * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT;
				stopsk = sk + srcblk.w;
				// Scan by set of 1 stripe column at a time
				for (; sk < stopsk; sk++, sj++)
				{
					// Do half top of column
					j = sj;
					csj = state[j];
					// If any of the two samples is not significant and has a
					// non-zero context (i.e. some neighbor is significant) we can 
					// not skip them
					if ((((~ csj) & (csj << 2)) & SIG_MASK_R1R2) != 0)
					{
						k = sk;
						// Scan first row
						if ((csj & (STATE_SIG_R1 | STATE_NZ_CTXT_R1)) == STATE_NZ_CTXT_R1)
						{
							// Apply zero coding
							sym = SupportClass.URShift((data[k] & mask), bp);
							bout.writeBit(sym);
							nsym++;
							if (sym != 0)
							{
								// Became significant
								// Apply sign coding
								sym = SupportClass.URShift(data[k], 31);
								bout.writeBit(sym);
								nsym++;
								// Update state information (significant bit,
								// visited bit, neighbor significant bit of
								// neighbors, non zero context of neighbors, sign
								// of neighbors)
								if (!causal)
								{
									// If in causal mode do not change contexts of 
									// previous stripe.
									state[j + off_ul] |= STATE_NZ_CTXT_R2 | STATE_D_DR_R2;
									state[j + off_ur] |= STATE_NZ_CTXT_R2 | STATE_D_DL_R2;
								}
								// Update sign state information of neighbors
								if (sym != 0)
								{
									csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2 | STATE_V_U_SIGN_R2;
									if (!causal)
									{
										// If in causal mode do not change
										// contexts of previous stripe.
										state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2 | STATE_V_D_SIGN_R2;
									}
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_H_L_SIGN_R1 | STATE_D_UL_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_H_R_SIGN_R1 | STATE_D_UR_R2;
								}
								else
								{
									csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2;
									if (!causal)
									{
										// If in causal mode do not change
										// contexts of previous stripe.
										state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2;
									}
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_D_UL_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_D_UR_R2;
								}
								// Update distortion
								normval = (data[k] >> downshift) << upshift;
								dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
							}
							else
							{
								csj |= STATE_VISITED_R1;
							}
						}
						if (sheight < 2)
						{
							state[j] = csj;
							continue;
						}
						// Scan second row
						if ((csj & (STATE_SIG_R2 | STATE_NZ_CTXT_R2)) == STATE_NZ_CTXT_R2)
						{
							k += dscanw;
							// Apply zero coding
							sym = SupportClass.URShift((data[k] & mask), bp);
							bout.writeBit(sym);
							nsym++;
							if (sym != 0)
							{
								// Became significant
								// Apply sign coding
								sym = SupportClass.URShift(data[k], 31);
								bout.writeBit(sym);
								nsym++;
								// Update state information (significant bit,
								// visited bit, neighbor significant bit of
								// neighbors, non zero context of neighbors, sign
								// of neighbors)
								state[j + off_dl] |= STATE_NZ_CTXT_R1 | STATE_D_UR_R1;
								state[j + off_dr] |= STATE_NZ_CTXT_R1 | STATE_D_UL_R1;
								// Update sign state information of neighbors
								if (sym != 0)
								{
									csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1 | STATE_V_D_SIGN_R1;
									state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1 | STATE_V_U_SIGN_R1;
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2 | STATE_H_L_SIGN_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2 | STATE_H_R_SIGN_R2;
								}
								else
								{
									csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1;
									state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1;
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2;
								}
								// Update distortion
								normval = (data[k] >> downshift) << upshift;
								dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
							}
							else
							{
								csj |= STATE_VISITED_R2;
							}
						}
						state[j] = csj;
					}
					// Do half bottom of column
					if (sheight < 3)
						continue;
					j += sscanw;
					csj = state[j];
					// If any of the two samples is not significant and has a
					// non-zero context (i.e. some neighbor is significant) we can 
					// not skip them
					if ((((~ csj) & (csj << 2)) & SIG_MASK_R1R2) != 0)
					{
						k = sk + (dscanw << 1);
						// Scan first row
						if ((csj & (STATE_SIG_R1 | STATE_NZ_CTXT_R1)) == STATE_NZ_CTXT_R1)
						{
							sym = SupportClass.URShift((data[k] & mask), bp);
							bout.writeBit(sym);
							nsym++;
							if (sym != 0)
							{
								// Became significant
								// Apply sign coding
								sym = SupportClass.URShift(data[k], 31);
								bout.writeBit(sym);
								nsym++;
								// Update state information (significant bit,
								// visited bit, neighbor significant bit of
								// neighbors, non zero context of neighbors, sign
								// of neighbors)
								state[j + off_ul] |= STATE_NZ_CTXT_R2 | STATE_D_DR_R2;
								state[j + off_ur] |= STATE_NZ_CTXT_R2 | STATE_D_DL_R2;
								// Update sign state information of neighbors
								if (sym != 0)
								{
									csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2 | STATE_V_U_SIGN_R2;
									state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2 | STATE_V_D_SIGN_R2;
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_H_L_SIGN_R1 | STATE_D_UL_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_H_R_SIGN_R1 | STATE_D_UR_R2;
								}
								else
								{
									csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2;
									state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2;
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_D_UL_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_D_UR_R2;
								}
								// Update distortion
								normval = (data[k] >> downshift) << upshift;
								dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
							}
							else
							{
								csj |= STATE_VISITED_R1;
							}
						}
						if (sheight < 4)
						{
							state[j] = csj;
							continue;
						}
						if ((csj & (STATE_SIG_R2 | STATE_NZ_CTXT_R2)) == STATE_NZ_CTXT_R2)
						{
							k += dscanw;
							// Apply zero coding
							sym = SupportClass.URShift((data[k] & mask), bp);
							bout.writeBit(sym);
							nsym++;
							if (sym != 0)
							{
								// Became significant
								// Apply sign coding
								sym = SupportClass.URShift(data[k], 31);
								bout.writeBit(sym);
								nsym++;
								// Update state information (significant bit,
								// visited bit, neighbor significant bit of
								// neighbors, non zero context of neighbors, sign
								// of neighbors)
								state[j + off_dl] |= STATE_NZ_CTXT_R1 | STATE_D_UR_R1;
								state[j + off_dr] |= STATE_NZ_CTXT_R1 | STATE_D_UL_R1;
								// Update sign state information of neighbors
								if (sym != 0)
								{
									csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1 | STATE_V_D_SIGN_R1;
									state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1 | STATE_V_U_SIGN_R1;
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2 | STATE_H_L_SIGN_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2 | STATE_H_R_SIGN_R2;
								}
								else
								{
									csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1;
									state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1;
									state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2;
									state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2;
								}
								// Update distortion
								normval = (data[k] >> downshift) << upshift;
								dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
							}
							else
							{
								csj |= STATE_VISITED_R2;
							}
						}
						state[j] = csj;
					}
				}
			}
			
			// Get length and terminate if needed
			if (doterm)
			{
				ratebuf[pidx] = bout.terminate();
			}
			else
			{
				ratebuf[pidx] = bout.length();
			}
			// Add length of previous segments, if any
			if (ltpidx >= 0)
			{
				ratebuf[pidx] += ratebuf[ltpidx];
			}
			
			// Return the reduction in distortion
			return dist;
		}
Beispiel #7
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;
		}
Beispiel #8
0
		/// <summary> Returns the next code-block in the current tile for the specified
		/// component, as a copy (see below). 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 always a copy of the internal
		/// data of this object, and it can be modified "in place" without
		/// any problems after being returned. The 'offset' of the returned data is
		/// 0, and the 'scanw' is the same as the code-block width.  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. 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 'c', or
		/// null if all code-blocks for the current tile have been returned.
		/// 
		/// </returns>
		/// <seealso cref="CBlkWTData">
		/// 
		/// </seealso>
		public override CBlkWTData getNextCodeBlock(int c, CBlkWTData cblk)
		{
			// We can not directly use getNextInternCodeBlock() since that returns
			// a reference to the internal buffer, we have to copy that data
			
			int j, k;
			int w;
			System.Object dst_data; // a int[] or float[] object
			int[] dst_data_int;
			float[] dst_data_float;
			System.Object src_data; // a int[] or float[] object
			
			intData = (filters.getWTDataType(tIdx, c) == DataBlk.TYPE_INT);
			
			dst_data = null;
			
			// Cache the data array, if any
			if (cblk != null)
			{
				dst_data = cblk.Data;
			}
			
			// Get the next code-block
			cblk = getNextInternCodeBlock(c, cblk);
			
			if (cblk == null)
			{
				return null; // No more code-blocks in current tile for component
				// c
			}
			
			// Ensure size of output buffer
			if (intData)
			{
				// int data
				dst_data_int = (int[]) dst_data;
				if (dst_data_int == null || dst_data_int.Length < cblk.w * cblk.h)
				{
					dst_data = new int[cblk.w * cblk.h];
				}
			}
			else
			{
				// float data
				dst_data_float = (float[]) dst_data;
				if (dst_data_float == null || dst_data_float.Length < cblk.w * cblk.h)
				{
					dst_data = new float[cblk.w * cblk.h];
				}
			}
			
			// Copy data line by line
			src_data = cblk.Data;
			w = cblk.w;
			for (j = w * (cblk.h - 1), k = cblk.offset + (cblk.h - 1) * cblk.scanw; j >= 0; j -= w, k -= cblk.scanw)
			{
                // CONVERSION PROBLEM?
				Array.Copy((System.Array)src_data, k, (System.Array)dst_data, j, w);
			}
			cblk.Data = dst_data;
			cblk.offset = 0;
			cblk.scanw = w;
			
			return cblk;
		}
Beispiel #9
0
		/// <summary> This function gets a datablk from the entropy coder. The sample sin the
		/// block, which consists of  the quantized coefficients from the quantizer,
		/// are scaled by the values given for any ROIs specified.
		/// 
		/// <p>The function calls on a ROIMaskGenerator to get the mask for scaling
		/// the coefficients in the current block.</p>
		/// 
		/// <p>The data returned by this method is a copy of the orignal
		/// data. Therfore it can be modified "in place" without any problems after
		/// being returned. The 'offset' of the returned data is 0, and the 'scanw'
		/// is the same as the code-block width. See the 'CBlkWTData' class.</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 virtual CBlkWTData getNextCodeBlock(int c, CBlkWTData cblk)
		{
			return getNextInternCodeBlock(c, cblk);
		}
Beispiel #10
0
		/// <summary> This function gets a datablk from the entropy coder. The sample sin the
		/// block, which consists of  the quantized coefficients from the quantizer,
		/// are scaled by the values given for any ROIs specified.
		/// 
		/// <p>The function calls on a ROIMaskGenerator to get the mask for scaling
		/// the coefficients in the current block.</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 virtual CBlkWTData getNextInternCodeBlock(int c, CBlkWTData cblk)
		{
			int mi, i, j, k, wrap;
			int ulx, uly, w, h;
			DataBlkInt mask = roiMask; // local copy of mask
			int[] maskData; // local copy of mask data
			int[] data; // local copy of quantized data
			int tmp;
			int bitMask = 0x7FFFFFFF;
			SubbandAn root, sb;
			int maxBits = 0; // local copy
			bool roiInTile;
			bool sbInMask;
			int nROIcoeff = 0;
			
			// Get codeblock's data from quantizer
			cblk = src.getNextCodeBlock(c, cblk);
			
			// If there is no ROI in the image, or if we already got all
			// code-blocks
			if (!roi || cblk == null)
			{
				return cblk;
			}
			
			data = (int[]) cblk.Data;
			sb = cblk.sb;
			ulx = cblk.ulx;
			uly = cblk.uly;
			w = cblk.w;
			h = cblk.h;
			sbInMask = (sb.resLvl <= useStartLevel);
			
			// Check that there is an array for the mask and set it to zero
			maskData = mask.DataInt; // local copy of mask data
			if (maskData == null || w * h > maskData.Length)
			{
				maskData = new int[w * h];
				mask.DataInt = maskData;
			}
			else
			{
				for (i = w * h - 1; i >= 0; i--)
					maskData[i] = 0;
			}
			mask.ulx = ulx;
			mask.uly = uly;
			mask.w = w;
			mask.h = h;
			
			// Get ROI mask from generator
			root = src.getAnSubbandTree(tIdx, c);
			maxBits = maxMagBits[tIdx][c];
			roiInTile = mg.getROIMask(mask, root, maxBits, c);
			
			// If there is no ROI in this tile, return the code-block untouched
			if (!roiInTile && (!sbInMask))
			{
				cblk.nROIbp = 0;
				return cblk;
			}
			
			// Update field containing the number of ROI magnitude bit-planes
			cblk.nROIbp = cblk.magbits;
			
			// If the entire subband belongs to the ROI mask, The code-block is
			// set to belong entirely to the ROI with the highest scaling value
			if (sbInMask)
			{
				// Scale the wmse so that instead of scaling the coefficients, the
				// wmse is scaled.
				//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.wmseScaling *= (float) (1 << (maxBits << 1));
				cblk.nROIcoeff = w * h;
				return cblk;
			}
			
			// In 'block aligned' mode, the code-block is set to belong entirely
			// to the ROI with the highest scaling value if one coefficient, at
			// least, belongs to the ROI
			if (blockAligned)
			{
				wrap = cblk.scanw - w;
				mi = h * w - 1;
				i = cblk.offset + cblk.scanw * (h - 1) + w - 1;
				int nroicoeff = 0;
				for (j = h; j > 0; j--)
				{
					for (k = w - 1; k >= 0; k--, i--, mi--)
					{
						if (maskData[mi] != 0)
						{
							nroicoeff++;
						}
					}
					i -= wrap;
				}
				if (nroicoeff != 0)
				{
					// Include the subband
					//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.wmseScaling *= (float) (1 << (maxBits << 1));
					cblk.nROIcoeff = w * h;
				}
				return cblk;
			}
			
			// Scale background coefficients
			bitMask = (((1 << cblk.magbits) - 1) << (31 - cblk.magbits));
			wrap = cblk.scanw - w;
			mi = h * w - 1;
			i = cblk.offset + cblk.scanw * (h - 1) + w - 1;
			for (j = h; j > 0; j--)
			{
				for (k = w; k > 0; k--, i--, mi--)
				{
					tmp = data[i];
					if (maskData[mi] != 0)
					{
						// ROI coeff. We need to erase fractional bits to ensure
						// that they do not conflict with BG coeffs. This is only
						// strictly necessary for ROI coeffs. which non-fractional
						// magnitude is zero, but much better BG quality can be
						// achieved if done if reset to zero since coding zeros is
						// much more efficient (the entropy coder knows nothing
						// about ROI and cannot avoid coding the ROI fractional
						// bits, otherwise this would not be necessary).
						data[i] = (unchecked((int) 0x80000000) & tmp) | (tmp & bitMask);
						nROIcoeff++;
					}
					else
					{
						// BG coeff. it is not necessary to erase fractional bits
						data[i] = (unchecked((int) 0x80000000) & tmp) | ((tmp & 0x7FFFFFFF) >> maxBits);
					}
				}
				i -= wrap;
			}
			
			// Modify the number of significant bit-planes in the code-block
			cblk.magbits += maxBits;
			
			// Store the number of ROI coefficients present in the code-block
			cblk.nROIcoeff = nROIcoeff;
			
			return cblk;
		}
Beispiel #11
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;
		}
Beispiel #12
0
		/// <summary> Returns the next code-block in the current tile for the specified
		/// component, as a copy (see below). 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 always a copy of the
		/// data. Therfore it can be modified "in place" without any problems after
		/// being returned. The 'offset' of the returned data is 0, and the 'scanw'
		/// is the same as the code-block width. 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 getNextCodeBlock(int c, CBlkWTData cblk)
		{
			return getNextInternCodeBlock(c, cblk);
		}
Beispiel #13
0
        /// <summary> Returns the next code-block in the current tile for the specified
        /// component, as a copy (see below). 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 always a copy of the internal
        /// data of this object, and it can be modified "in place" without
        /// any problems after being returned. The 'offset' of the returned data is
        /// 0, and the 'scanw' is the same as the code-block width.  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. 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 'c', or
        /// null if all code-blocks for the current tile have been returned.
        ///
        /// </returns>
        /// <seealso cref="CBlkWTData">
        ///
        /// </seealso>
        public override CBlkWTData getNextCodeBlock(int c, CBlkWTData cblk)
        {
            // We can not directly use getNextInternCodeBlock() since that returns
            // a reference to the internal buffer, we have to copy that data

            int j, k;
            int w;

            System.Object dst_data; // a int[] or float[] object
            int[]         dst_data_int;
            float[]       dst_data_float;
            System.Object src_data; // a int[] or float[] object

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

            dst_data = null;

            // Cache the data array, if any
            if (cblk != null)
            {
                dst_data = cblk.Data;
            }

            // Get the next code-block
            cblk = getNextInternCodeBlock(c, cblk);

            if (cblk == null)
            {
                return(null); // No more code-blocks in current tile for component
                              // c
            }

            // Ensure size of output buffer
            if (intData)
            {
                // int data
                dst_data_int = (int[])dst_data;
                if (dst_data_int == null || dst_data_int.Length < cblk.w * cblk.h)
                {
                    dst_data = new int[cblk.w * cblk.h];
                }
            }
            else
            {
                // float data
                dst_data_float = (float[])dst_data;
                if (dst_data_float == null || dst_data_float.Length < cblk.w * cblk.h)
                {
                    dst_data = new float[cblk.w * cblk.h];
                }
            }

            // Copy data line by line
            src_data = cblk.Data;
            w        = cblk.w;
            for (j = w * (cblk.h - 1), k = cblk.offset + (cblk.h - 1) * cblk.scanw; j >= 0; j -= w, k -= cblk.scanw)
            {
                // CONVERSION PROBLEM?
                Array.Copy((System.Array)src_data, k, (System.Array)dst_data, j, w);
            }
            cblk.Data   = dst_data;
            cblk.offset = 0;
            cblk.scanw  = w;

            return(cblk);
        }
Beispiel #14
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);
        }
Beispiel #15
0
 public abstract CSJ2K.j2k.wavelet.analysis.CBlkWTData getNextCodeBlock(int param1, CSJ2K.j2k.wavelet.analysis.CBlkWTData param2);