[XviD-devel] adaptive quant improvement

Edouard Gomez xvid-devel@xvid.org
Wed, 29 Jan 2003 21:10:28 +0100


--jL2BoiuKMElzg3CS
Content-Type: multipart/mixed; boundary="DIOMP1UsTsWJauNi"
Content-Disposition: inline


--DIOMP1UsTsWJauNi
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hello again,

i worked a bit on the code to understand it from the "math" point of
view, i cleaned it up a bit making clearer math formulas.

One of the formulas is also an optimization because it avoids some
substraction and allows variance and mean values computation at the same
time.

Now i'll perform some tests

@marco: where do these magic numbers come from ?
        the 256 divisor and thresholds ?

--=20
Edouard Gomez

--DIOMP1UsTsWJauNi
Content-Type: text/x-csrc; charset=us-ascii
Content-Disposition: attachment; filename="adapt.c"

int
adaptive_quantization(unsigned char *buf,
					  int stride,
					  int *intquant,
					  int framequant,
					  int min_quant,
					  int max_quant,
					  int mb_width,
					  int mb_height)
{
	int i, j, k, l;

	float *quant;
	unsigned char *ptr;
	float *avg;
	float *var;

	const float min_level    = 0.0001;
	const float medium_level = 0.0003;
	const float mh_level     = 0.003;
	const float high_level   = 0.009;

	float result;

	/* Allocate buffers */
	if ((quant = (float *)malloc(mb_width*mb_height*sizeof(float))) == NULL)
		return(-1);

	if((var = (float *)malloc(mb_width*mb_height*sizeof(float))) == NULL) {
		free(quant);
		return(-1);
	}

	if((avg = (float *)malloc(mb_width*mb_height*sizeof(float))) == NULL) {
		free(quant);
		free(var);
		return(-1);
	}

	/* Do luminance masking for all MBs */
	for(k = 0; k < mb_height; k++) {

		for(l = 0; l < mb_width; l++) {

			quant[MB] = (float)framequant;

			/* Get current MB */
			ptr = &buf[16 * k * stride + 16 * l];

			/* Initialize average and variance */
			avg[k*mb_width + l] = 0.;
			var[k*mb_width + l] = 0.;

			/*
			 * Compute both at a time using the relation :
			 * E[(X-m)^2] = E[X^2] - m^2
			 *
			 * where m = E[X] == average(mean?) value
			 */
			for (i = 0; i < 16; i++) {
				for (j = 0; j < 16; j++) {

					/* Accumulate E[X] */
					avg[k*mb_width + l] += ptr[i*stride + j];

					/* Accumulate E[X^2] */
					var[k*mb_width + l] += ptr[i*stride + j]*ptr[i*stride + j];
				}
			}

			/* Finishes to compute the average == E[X]*/
			avg[k*mb_width + l] /= 16.0*16.0;

			/* Finishes to compute the sum of square values == E[X^2] */
			var[k*mb_width + l] /= 16.0*16.0;

			/* Now turn it into variance == E[(X-m)^2] */
			var[k*mb_width + l]-=avg[k*mb_width + l]*avg[k*mb_width + l];

			/* Compute the result */
			result = var[k*mb_width + l]/(256.0*avg[k*mb_width + l]);

			/* Ok - Boost or Penalize quantizer */
			if(result < min_level) {
				quant[k*mb_width + l] += 4;
			} else if(result < medium_level) {
				quant[k*mb_width + l] += 2;
			} else if(result < mh_level) {

			} else if(result < high_level) {
				quant[k*mb_width + l] -= 2;
			} else {
				quant[k*mb_width + l] -= 4;
			}

			/* Clamp the result to valid range */
			if(quant[k*mb_width + l] < min_quant)
			   	quant[k*mb_width + l] = min_quant;

			if(quant[k*mb_width + l] > max_quant)
				quant[k*mb_width + l]=max_quant;

		}
	}


	/* Normalize the quantizer field */
	i = normalize_quantizer_field(quant,
								  intquant,
								  mb_width * mb_height,
								  min_quant,
								  max_quant);

	/* Free memory */
	free(avg);
	free(var);
	free(quant);

	return(i);

}

--DIOMP1UsTsWJauNi--

--jL2BoiuKMElzg3CS
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQE+ODU0R5dTYz5sWMcRAh/+AJ9sEFQLxd1I/PmoJZOgT3ACmmIkHgCfQ0Vd
Hi6ea34PyTJDHeClq0XIAng=
=jHeA
-----END PGP SIGNATURE-----

--jL2BoiuKMElzg3CS--