const Array2D inverse_quantise_block(const Array2D& block, int q) {
  // Construct a new array with same size as block
  Array2D inverseQuantisedBlock(block.ranges());
  const int blockHeight = block.shape()[0];
  const int blockWidth = block.shape()[1];
  for (int y=0; y<blockHeight; ++y) {
    for (int x=0; x<blockWidth; ++x) {
      inverseQuantisedBlock[y][x] = scale(block[y][x], q);
    }
  }
  return inverseQuantisedBlock;
}
const Array2D clip(const Array2D& values, const int min_value, const int max_value) {
  Array2D result(values.ranges());
  const Index height = values.shape()[0];
  const Index width = values.shape()[1];
  for (int y=0; y<height; ++y) {
    for (int x=0; x<width; ++x) {
      if (values[y][x]<min_value) result[y][x] = min_value;
      else if (values[y][x]>max_value) result[y][x] =  max_value;
      else result[y][x] = values[y][x];
    }
  }
  return result;
}
// Inverse quantise a block of quantised coefficients using an array of quantisers.
// The block to be inverse quantised may correspond either to the transform of the whole picture
// or to a subband. In the former case this function will inverse quantise slices, in the 
// latter case this function will inverse quantise codeblocks
const Array2D inverse_quantise_block(const ConstView2D& block,
                                     const Array2D& qIndices) {
  // Construct a new array with same size as block
  Array2D invQuantisedBlock(block.ranges());
  const int blockHeight = block.shape()[0];
  const int blockWidth = block.shape()[1];
  const int yBlocks = qIndices.shape()[0];
  const int xBlocks = qIndices.shape()[1];
  // Loop through the slices or codeblocks
  // Note Range(left, right) defines the half open range [left, right),
  // i.e. the rightmost element is not included
  for (int y=0, top=0, bottom=blockHeight/yBlocks;
       y<yBlocks;
       ++y, top=bottom, bottom=((y+1)*blockHeight/yBlocks) ) {
    for (int x=0, left=0, right=blockWidth/xBlocks;
         x<xBlocks;
         ++x, left=right, right=((x+1)*blockWidth/xBlocks) ) {
           const ArrayIndices2D sliceIndices = // Define the samples within the curent slice/codeblock
             indices[Range(top,bottom)][Range(left,right)];
           invQuantisedBlock[sliceIndices] =
             inverse_quantise_block(block[sliceIndices], qIndices[y][x]);
    }
  }
  return invQuantisedBlock;
}
// Quantise a subband in in-place transform order
// This version of quantise_subbands assumes multiple quantisers per subband.
// It may be used for either quantising slices or for quantising subbands with codeblocks
const Array2D quantise_subbands(const Array2D& coefficients, const BlockVector& qIndices) {
  const Index transformHeight = coefficients.shape()[0];
  const Index transformWidth = coefficients.shape()[1];
  // TO DO: Check numberOfSubbands=3n+1 ?
  const int numberOfSubbands = qIndices.size();
  const int waveletDepth = (numberOfSubbands-1)/3;
  Index stride, offset; // stride is subsampling factor, offset is subsampling phase
  Array2D result(coefficients.ranges());

  // Create a view of the coefficients, representing the LL subband, quantise it,
  // then assign the result a view of the results array. This puts the quantised
  // LL subband into the result array in in-place transform order.
  // ArrayIndices2D objects specify the subset of array elements within a view,
  // that is they specify the subsampling factor and subsampling phase.
  stride = pow(2, waveletDepth);
  const ArrayIndices2D LLindices = // LLindices specifies the samples in the LL subband
    indices[Range(0,transformHeight,stride)][Range(0,transformWidth,stride)];
  result[LLindices] =
    quantise_LLSubband(coefficients[LLindices], qIndices[0]);

  // Next quantise the other subbands
  // Note: Level numbers go from zero for the lowest ("DC") frequencies to depth for
  // the high frequencies. This corresponds to the convention in the VC-2 specification.
  // Subands go from zero ("DC") to numberOfSubbands-1 for HH at the highest level
  for (char level=1, band=1; level<=waveletDepth; ++level) {
    stride = pow(2, waveletDepth+1-level);
    offset = stride/2;
    // Create a view of coefficients corresponding to a subband, then quantise it
    //Quantise HL subband
    const ArrayIndices2D HLindices = // HLindices specifies the samples in the HL subband
      indices[Range(0,transformHeight,stride)][Range(offset,transformWidth,stride)];
    result[HLindices] = quantise_block(coefficients[HLindices], qIndices[band++]);
    //Quantise LH subband
    const ArrayIndices2D LHindices = // LHindices specifies the samples in the LH subband
      indices[Range(offset,transformHeight,stride)][Range(0,transformWidth,stride)];
    result[LHindices] = quantise_block(coefficients[LHindices], qIndices[band++]);
    //Quantise HH subband
    const ArrayIndices2D HHindices = // HHindices specifies the samples in the HH subband
      indices[Range(offset,transformHeight,stride)][Range(offset,transformWidth,stride)];
    result[HHindices] = quantise_block(coefficients[HHindices], qIndices[band++]);
  }

  return result;
}
// Splits a large 2D array into an array of smaller 2D arrays (blocks)
// Note that if the number of blocks is not a sub-multiple of the input array dimensions then
// the blocks will have different sizes!
// yBlocks and xBlocks are the number of blocks in the vertical and horizontal dimension respectively.
// Splits a picture into slices or a subband into codeblocks.
const BlockArray split_into_blocks(const Array2D& picture, int yBlocks, int xBlocks) {
  // Define array of yBlocks by xBlocks
  BlockArray blocks(extents[yBlocks][xBlocks]);
  const int pictureHeight = picture.shape()[0];
  const int pictureWidth = picture.shape()[1];
  // Note Range(left, right) defines the half open range [left, right),
  // i.e. the rightmost element is not included
  for (int y=0, top=0, bottom=pictureHeight/yBlocks;
       y<yBlocks;
       ++y, top=bottom, bottom=((y+1)*pictureHeight/yBlocks) ) {
    for (int x=0, left=0, right=pictureWidth/xBlocks;
         x<xBlocks;
         ++x, left=right, right=((x+1)*pictureWidth/xBlocks) ) {
      // Assign region of picture to block
      blocks[y][x] = picture[indices[Range(top,bottom)][Range(left,right)]];
    }
  }
  return blocks;
}
Esempio n. 6
0
static void medianCut( const Array2D &luminance, const Array2D &summedLuminance, MedianCutSampler::Projection projection, const Box2i &area, vector<Box2i> &areas, vector<V2f> &centroids, int depth, int maxDepth )
{
	float radiansPerPixel = M_PI / (luminance.shape()[1]);

	if( depth==maxDepth )
	{
		float totalEnergy = 0.0f;
		V2f position( 0.0f );
		for( int y=area.min.y; y<=area.max.y; y++ )
		{
			for( int x=area.min.x; x<=area.max.x; x++ )
			{
				float e = luminance[x][y];
				position += V2f( x, y ) * e;
				totalEnergy += e;
			}
		}

		position /= totalEnergy;
		centroids.push_back( position );
		areas.push_back( area );
	}
	else
	{
		// find cut dimension
		V2f size = area.size();
		if( projection==MedianCutSampler::LatLong )
		{
			float centreY = (area.max.y + area.min.y) / 2.0f;
			float centreAngle = (M_PI - radiansPerPixel) / 2.0f - centreY * radiansPerPixel;
			size.x *= cosf( centreAngle );
		}
		int cutAxis = size.x > size.y ? 0 : 1;
		float e = energy( summedLuminance, area );
		float halfE = e / 2.0f;
		Box2i lowArea = area;
		while( e > halfE )
		{
			lowArea.max[cutAxis] -= 1;
			e = energy( summedLuminance, lowArea );
		}
		Box2i highArea = area;
		highArea.min[cutAxis] = lowArea.max[cutAxis] + 1;
		medianCut( luminance, summedLuminance, projection, lowArea, areas, centroids, depth + 1, maxDepth );
		medianCut( luminance, summedLuminance, projection, highArea, areas, centroids, depth + 1, maxDepth );
	}
}
// Inverse quantise an LL (DC) subband, including prediction
// This version either inverse quantises the LL subband for low delay mode or
// inverse quantises the LL subband for core syntax using codeblocks
const Array2D inverse_quantise_LLSubband(const ConstView2D& llSubband,
                                         const Array2D& qIndices) {
  const int LLHeight = llSubband.shape()[0]; // Height of the LL subband
  const int LLWidth = llSubband.shape()[1]; // Width of the LL subband
  const int yBlocks = qIndices.shape()[0]; // Number of vertical slices/codeblocks in the LL subband
  const int xBlocks = qIndices.shape()[1]; // Number of horizontal slices/codeblocks in the LL subband
  Array2D invQuantisedLL(llSubband.ranges());
  for (int y=0; y<LLHeight; ++y) {
    for (int x=0; x<LLWidth; ++x) {
      // TO DO: Implement more efficient calculation of yb/xb.
      // Calculate (y+1)*yBlocks by incrementing previous version by yBlocks
      // Do division by shift (width is always a power of 2)
      const int yb = ((y+1)*yBlocks-1)/LLHeight; // vertical slice/codeblock number
      const int xb = ((x+1)*xBlocks-1)/LLWidth; // horizontal slice/codeblock number
      const int prediction = predictDC(invQuantisedLL, y, x);
      invQuantisedLL[y][x] = scale(llSubband[y][x], qIndices[yb][xb])+prediction;
    }
  }
  return invQuantisedLL;
}
// Get the shape of a 2D array
const Shape2D shape(const Array2D& arg) {
  const Shape2D result = {{static_cast<Index>(arg.shape()[0]), static_cast<Index>(arg.shape()[1])}};
  return result;
}