⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 quantutil.c

📁 基于小波的图像压缩
💻 C
📖 第 1 页 / 共 2 页
字号:
/******
*
*	<>
*
*	these routines are obsoleted by "quantim" and need to make calls
*	to the quantizeImage routines with passed-in qtypes and whatnot
*
*******/

#define NEVER_QUANT_LL	// seems to be a winner

#define FASTQUANT_SHIFT 8
#define FASTQUANT_ONE (1<<FASTQUANT_SHIFT)
#define FASTQUANT_HALF (1<<(FASTQUANT_SHIFT-1))

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <crblib/inc.h>

#include "image.h"
#include "codeimage.h"
#include "quantutil.h"

/*************/

#define quantizeBands	quantizeBandsDZ		// not very cool to do this
#define quantizeBandsU	quantizeBandsDZU	// not very cool to do this
	// quantizeBands() is used by the fiddle() and whatnot routines

#define VAL_SCALE		16
#define INV_VAL_SCALE	(1.0/VAL_SCALE)
#define MAX_VAL			128
#define MAX_VAL_SCALED	(MAX_VAL * VAL_SCALE)
#define TOP_VAL_SCALED	(MAX_VAL_SCALED - 1)
#define SCALE_Q_UP	1.125
#define SCALE_Q_DN	0.9375

typedef struct {
	int size;
	int num_of_val[MAX_VAL_SCALED];

	// used in fiddle:
	int dD_up,dD_dn,dR_up,dR_dn;
	double RoD_dn,RoD_up;
} bandInfo;

int distortion(int *num_of_val,double quantizer);
void infoBand(double *ptr,int w,int h,int fullw,bandInfo *bi);
ulong packedQuantizedImageSize(imageFloat *imf,coder *coder_template,int levels,float *quantizers);
ulong packedQuantizedImageStopErr(imageFloat *imf,coder *coder_template,int levels,double quantizer,int stopSize);

/*******

seekStoppedQ : scale the quantizers[] to get a desired rate.

	this routine is imperfect, in that we almost always miss the target by
		about 100 bytes.  This is *not* a failure of the routine, but
		actually a failure of the concept : sometimes you just don't get
		rate changes when you move the quantizers a teeny bit - the image
		is not floating-point.

********/

#define MIN_STEP	0.1
#define MAX_SEEK_Q	100

void seekStoppedQuantizers_Fast(imageFloat *imF,int levels,float * quantizers,int stopSize,
	coder *coder_template)
{
int nextErr_up,nextErr_dn,curErr;
int i,nbands;
double L,R,Lold,Rold,Lold_old,Rold_old;
int L_y,R_y,Lold_y,Rold_y;
double Lslope,Rslope,last_guess,guess;

#if 0	/** generate a plot **/
	if ( 1 ) {
		double sizer = 1.0 / imF->tot_size;
		for(L=1.0;L<MAX_SEEK_Q;L += MIN_STEP) {
			L_y = packedQuantizedImageStopErr(imF,coder_template,levels,L,stopSize);
			printf("%2.2f %f\n",L,L_y*sizer);
		}
		return;
	}
#endif

/******************
****
*		this is an implementation of the tangent-intersection search.
*			it converges in log(N) time.
		Unfortunately it only works on data whose second derivative has
			the same sign everywhere, and if you run the plots above you
			see that's not us !
		
		this search is like a binary search; we start with a L and R
			which we hope are on either side of the minimum.  We find
			the tangent at each, then the intersection of the tangents.
		This intersection is the "guess".
		We then contract L & R to converge towards the guess.

		There is one subtlety: after contraction we may have done a
			bad step, in which case the two tangets will have the same
*			sign of slope (they should always have opposite sign,
*			indicating the trough or hill).  When this happens we try
*			to "reset" to resume the search.
**
**	->	This algorithm is useless for me, because the actually shape
**			of Error(Quantizer) is nearly chaotic.
***
 **************/

	nbands=3*levels+1;

	Lold = 1.0;
	Rold = MAX_SEEK_Q;

	Lold_y = packedQuantizedImageStopErr(imF,coder_template,levels,Lold,stopSize);
	Rold_y = packedQuantizedImageStopErr(imF,coder_template,levels,Rold,stopSize);

	last_guess = guess = (Lold + Rold) * 0.5;
	
	for(;;) {

		last_guess = guess;
		L = (Lold + guess)*0.5;
		R = (Rold + guess)*0.5;
	
	resetted:

		L_y = packedQuantizedImageStopErr(imF,coder_template,levels,L,stopSize);
		R_y = packedQuantizedImageStopErr(imF,coder_template,levels,R,stopSize);

		Lslope = (L_y - Lold_y)/(L - Lold);
		Rslope = (R_y - Rold_y)/(R - Rold);

		fprintf(stderr,"Lold=%f, L=%f, guess=%f, R=%f, Rold=%f\n",Lold,L,guess,R,Rold);
		fprintf(stderr,"Lold_y=%d, L_y=%d, R_y=%d, Rold_y=%d\n",Lold_y,L_y,R_y,Rold_y);

		if ( Lslope > 0 ) {	/** screwed up, must re-try **/
			errputs("warning : reset left!");
			R = Lold;
			Rold = L;
			L = (Lold + Lold_old)*0.5;
			Lold = Lold_old;
			if ( L == Lold || R == Rold ) {
				errputs("warning : step size is zero; exiting");
				break;
			}
			guess = (L + R) * 0.5;
			goto resetted;
		} else if ( Rslope < 0 ) {
			errputs("warning : reset right!");
			L = Rold;
			Lold = R;
			R = (Rold + Rold_old)*0.5;
			Rold = Rold_old;
			if ( L == Lold || R == Rold ) {
				errputs("warning : step size is zero; exiting");
				break;
			}
			guess = (L + R) * 0.5;
			goto resetted;
		}

		guess = (Lslope * L - Rslope * R + R_y - L_y)/(Lslope - Rslope);

		if ( fabs(last_guess - guess) < MIN_STEP ) {
			break;
		}

		Lold_old = Lold;	Lold = L;	Lold_y = L_y;
		Rold_old = Rold;	Rold = R;	Rold_y = R_y;	
	}

	fprintf(stderr,"chose : %f\n",guess);

	for(i=0;i<nbands;i++) quantizers[i] = guess;
}

void seekStoppedQuantizers_Slow(imageFloat *imF,int levels,float * quantizers,int stopSize,
	coder *coder_template)
{
double Q,best_Q;
ulong err,best_err,last_err;
int i;
image *im_work;

	errputs("doing seek slow...");

	best_err = LONG_MAX; best_Q = 1.0;

#if 0
	for(Q=1.0;Q<MAX_SEEK_Q;Q += MIN_STEP) {
		err = packedQuantizedImageStopErr(imF,coder_template,levels,Q,stopSize);
		if ( err < best_err ) {
			best_err = err;
			best_Q = Q;
		}
	}
#else	/** with a local copy of StopErr **/

	if ( (im_work = newImageFromFloat(imF)) == NULL ) errexit("copyimage failed");

	last_err =0;
	for(Q=1.0;Q<MAX_SEEK_Q;Q += MIN_STEP) {
		int p,r,qv,v;
		double *dp,f,dv;
		double quantme;

		fprintf(stderr,"."); fflush(stderr);

		quantizeBandsU(imF,im_work,levels,Q);
		err = packedImageStopErr(im_work,coder_template,levels,stopSize);

		quantme = 1.0 / Q;

		v = (int)(LONG_MAX*quantme*quantme);
		if ( err >= v ) err = LONG_MAX;
		else err *= Q*Q;

		for(p=0;p<imF->planes;p++) {
			dp = imF->data[p][0];
			for(r= imF->plane_size;r--;) {
				f = *dp++; if ( f < 0 ) f = -f;
				qv = (int)(f * quantme);
				if ( qv == 0 ) dv = 0;
				else dv = ((double)qv + 0.5) * Q;
				err += (ulong)((dv - f)*(dv - f) + 0.5);
			}
		}

		if ( err < best_err ) {
			if ( err >= last_err ) { /* make sure it's stable */
				best_err = err;
				best_Q = Q;
			}
		}
		last_err = err;
	}

	printf("chose Q = %f , best err = %d\n",best_Q,best_err);

	freeImage(im_work);
#endif

	for(i=0;i<=3*levels;i++) quantizers[i] = best_Q;
}

void fiddleInfoBand(bandInfo *bic,double quantizer,float *quant_work,float *quant_spot,int R_cur,
	imageFloat *imF,coder *coder_template,int levels);

void fiddleQuantizers(imageFloat *imF,int levels,float * quantizers,
	coder *coder_template)
{
int nbands,b,p,l,D_cur,best_up,best_dn,dR,dD,best_dD;
int R_cur,R_new,R_orig,maxErr;
double **rows;
bool didFiddle;
double best_RoD;
bandInfo *bic;
bandInfo * bi = NULL; //alloc'ed
float *quant_work;

	nbands = 3*levels + 1;

/**********
	<> there's still some screw-up in the "distortion" measure
		where we think the distortion is going down, but it
		actually goes *UP* .  In fact, the distortion almost
		always goes up as a result of this fiddling, even
		though we supposedly gaurantee it goes down. :(

	A classic example :

		barb.256.raw 256 256 -tw -qu20 -s1
		barb.256.raw      :   65536 ->    8192 =  1.000 bpb =  8.000 to 1
		error: av= 5.03,max= 45,mse= 45.528,rmse= 6.75,psnr= 31.58

			got option: fiddle quantizers
		fiddle : band 1 up, 7 down
		fiddle : got dR = 22, dD = -17365
		fiddle : band 1 up, 8 down
		fiddle : got dR = -10, dD = -11373
		barb.256.raw      :   65536 ->    8202 =  1.001 bpb =  7.990 to 1
		error: av= 5.05,max= 46,mse= 46.232,rmse= 6.80,psnr= 31.52

	the "dR" estimate is good, but it claims we made a huge distortion
	improvement, while in reality we made the distortion WORSE !

**********/

	if ( (bi = newarray(bandInfo,nbands)) == NULL )
		errexit("malloc failed");

	if ( (quant_work = newarray(float,nbands)) == NULL )
		errexit("malloc failed");

	/** fiddle needs the infoBands to compute the distortions quickly **/

	for(p=0;p<imF->planes;p++) {
		rows = imF->data[p]; b=0;
		for (l = levels; l > 0; l--) {
			int sizeX,sizeY;

			sizeX = imF->width >> l;
			sizeY = imF->height >> l;

			if (l == levels)
				infoBand(rows[0], 		sizeX, sizeY, imF->width, &bi[b++]);

			infoBand(rows[0] + sizeX, 	sizeX, sizeY, imF->width, &bi[b++]);
			infoBand(rows[sizeY], 		sizeX, sizeY, imF->width, &bi[b++]);
			infoBand(rows[sizeY]+sizeX,	sizeX, sizeY, imF->width, &bi[b++]);
		}
	}

	errputs("fiddle : starting");

	R_orig = R_cur = packedQuantizedImageSize(imF,coder_template,levels,quantizers);

#if 0
	maxErr = (imF->tot_size) >> 11;	if ( maxErr < 5 ) maxErr = 5;
	R_orig += maxErr;
#endif

	/** compute current distortions **/
	for(b=0;b<nbands;b++) {
		bic = &bi[b];
		memcpy(quant_work,quantizers,sizeof(float)*nbands);
		fiddleInfoBand(&bi[b],quantizers[b],quant_work,&quant_work[b],
			R_cur,imF,coder_template,levels);
	}

	do {
		didFiddle = false;

		/** find the best RoD for increasing a quantizer **/
		best_RoD = 0; best_up = 0;
#ifdef NEVER_QUANT_LL
		for(b=1;b<nbands;b++) {
#else
		for(b=0;b<nbands;b++) {
#endif
			bic = &bi[b];
			if ( bic->RoD_up > best_RoD ) {
				best_RoD = bic->RoD_up; best_up = b;
			}
		}

		/** now find a way to decrease a quantizer so that there is
			no net rate change, but an improved distortion **/

		best_dD = 0; best_dn = -1;
#ifdef NEVER_QUANT_LL
		for(b=1;b<nbands;b++) {
#else
		for(b=0;b<nbands;b++) {
#endif
			if ( b == best_up ) continue; /** can't do up & down on same band **/
			bic = &bi[b];
			dR = bi[best_up].dR_up + bic->dR_dn;
			dD = bi[best_up].dD_up + bic->dD_dn;
			R_new = R_cur + dR;
			if ( R_new < R_orig && dD < best_dD ) {
				best_dn = b; best_dD = dD;
			}
		}

		if ( best_dD < 0 ) {
			didFiddle = true;
			dR = bi[best_up].dR_up + bi[best_dn].dR_dn;
			dD = bi[best_up].dD_up + bi[best_dn].dD_dn;
			R_cur += dR;

			printf("fiddle : band %d up, %d down\n",best_up,best_dn);
			printf("fiddle : got dR = %d, dD = %d\n",dR,dD);

			/** must now update the changed entries **/

			quantizers[best_up] *= SCALE_Q_UP;

			memcpy(quant_work,quantizers,sizeof(float)*nbands);
			fiddleInfoBand(&bi[best_up],quantizers[best_up],quant_work,&quant_work[best_up],
				R_cur,imF,coder_template,levels);

			if ( quantizers[best_dn] > 1 ) {
				quantizers[best_dn] *= SCALE_Q_DN;

				memcpy(quant_work,quantizers,sizeof(float)*nbands);
				fiddleInfoBand(&bi[best_dn],quantizers[best_dn],quant_work,&quant_work[best_dn],
					R_cur,imF,coder_template,levels);
			}
		}

	} while ( didFiddle );

	errputs("fiddle : done");

	free(quant_work);
	free(bi);

}

void fiddleInfoBand(bandInfo *bic,double quantizer,float *quant_work,float *quant_spot,int R_cur,
	imageFloat *imF,coder *coder_template,int levels)
{
int D_cur;

	D_cur		= distortion(bic->num_of_val,quantizer);
	bic->dD_up	= distortion(bic->num_of_val,quantizer*SCALE_Q_UP) - D_cur;
	if ( quantizer <= 1 ) bic->dD_dn = 0;
	else bic->dD_dn	= distortion(bic->num_of_val,quantizer*SCALE_Q_DN) - D_cur;

	*quant_spot = quantizer * SCALE_Q_UP;

	bic->dR_up = packedQuantizedImageSize(imF,coder_template,levels,quant_work) - R_cur;

	if ( quantizer <= 1 ) {
		bic->dR_dn = 0;
	} else {
		*quant_spot = quantizer * SCALE_Q_DN;

		bic->dR_dn = packedQuantizedImageSize(imF,coder_template,levels,quant_work) - R_cur;
	}

	/** dD_up > 0 and dR_up < 0 **/
	/** dD_dn < 0 and dR_dn > 0 **/

	if ( bic->dD_up <= 0 ) bic->RoD_up = - (bic->dR_up<<16);
	else	bic->RoD_up = - (bic->dR_up)/(double)(bic->dD_up);

	if ( bic->dD_dn >= 0 ) bic->RoD_dn = - (bic->dR_dn<<16);
	else	bic->RoD_dn = - (bic->dR_dn)/(double)(bic->dD_dn);
}

void infoBand(double *ptr,int w,int h,int fullw,bandInfo *bi)
{
int x,y,rowpad = fullw-w;
int v;
double val;

	bi->size = w*h;

	for(y=0;y<h;y++) {
		for(x=0;x<w;x++) {
			val = *ptr++;
			if ( val < 0 ) val = - val;
			if ( val >= MAX_VAL ) bi->num_of_val[TOP_VAL_SCALED] ++;
			else { 
				v = (int)(val * VAL_SCALE + 0.5);
				bi->num_of_val[v] ++;
			}
		}
		ptr += rowpad;
	}
}

ulong packedQuantizedImageSize(imageFloat *imf,coder *coder_template,int levels,float *quantizers)
{
image *im_work;
ulong size;

	if ( (im_work = newImageFromFloat(imf)) == NULL ) errexit("copyimage failed");
	quantizeBands(imf,im_work,levels,quantizers);
	size = packedImageSize(im_work,coder_template,levels);
	freeImage(im_work);

return size;
}

ulong packedQuantizedImageStopErr(imageFloat *imf,coder *coder_template,int levels,double quantizer,int stopSize)
{
image *im_work;
ulong err,maxerr;
int p,r,qv,v,nbands,i;
double *dp,f,dv;
double quantme;
float *quant_work; //alloced

	nbands = 3*levels+1;

	if ( (quant_work = newarray(float,nbands)) == NULL )
		errexit("malloc failed");

	for(i=0;i<nbands;i++) quant_work[i] = quantizer;

	if ( (im_work = newImageFromFloat(imf)) == NULL ) errexit("copyimage failed");
	quantizeBands(imf,im_work,levels,quant_work);
	err = packedImageStopErr(im_work,coder_template,levels,stopSize);
	freeImage(im_work);

	/** this doesn't count the error from the quantizing !!! **/

	quantme = 1.0 / quantizer;

	maxerr = (double)ULONG_MAX * quantme * quantme;
	if ( err > maxerr ) err = LONG_MAX;
	else err *= quantizer*quantizer;

	for(p=0;p<imf->planes;p++) {
		dp = imf->data[p][0];
		for(r= imf->plane_size;r--;) {
			f = *dp++; if ( f < 0 ) f = -f;
			qv = (int)(f * quantme);
			if ( qv == 0 ) dv = 0;
			else dv = ((double)qv + 0.5) * quantizer;
			err += (ulong)((dv - f)*(dv - f) + 0.5);
		}
	}

	free(quant_work);

return err;
}

int distortion(int *num_of_val,double quantizer)
{
double invquant,t,val,D;
int qv,n,v;

	invquant = 1.0 / quantizer;

	D = 0;
	for(v=1;v<TOP_VAL_SCALED;v++) {
		n = num_of_val[v];
		if ( n == 0 ) continue;
		val = (double)v*INV_VAL_SCALE;
#if 0
	/** this is JPEG-standard (ESZZ) quantizer ,
	**/
		qv = (int)(val * invquant + 0.5); // quantize
		t = val - (qv * quantizer);	// dequantize & get difference
#else
	/** this is the wavelet-common DeadZone quantizer
	**/
		qv = (int)(val * invquant);
		if ( qv == 0 ) t = val;
		else t = val - ((qv + 0.5)*quantizer);
#endif
		D += n*t*t;
	}
	D += (num_of_val[TOP_VAL_SCALED] * quantizer * quantizer)/4;	// maximum error on these

return (int)D;
}

/***************************************************************** $$

"dead zone quantizers" :

	quantized = val * (1.0/quantizer)

	val = sign * floor( quantizer * ( abs(val) + 0.5 ) );

	(btw, Intel rounds negative floats towards zero)

-----------------

	mussing with these in any way introduces a lot of error
		(for example, adding 0.5 to the quantized value to round it
		in the quantization step)

see quantizers.txt

**********************/

void dequantizeBandDZ(int *fmptr,double *toptr,int w,int h,int fullw,double factor)
{
int x,y,rowpad = fullw-w;
int sign,v;

	for(y=0;y<h;y++) {
		for(x=0;x<w;x++) {
			v = *fmptr++;
			if ( v == 0 ) { 
				*toptr++ = 0; 
			} else {
				if ( v < 0 ) { sign = -1; v = -v; }
				else sign = 1;
				*toptr++ = sign * factor * ((double)v + 0.5);
			}
		}
		fmptr += rowpad;
		toptr += rowpad;
	}
}

void quantizeBandDZ(double *fmptr,int *toptr,int w,int h,int fullw,double factor)
{
int x,y,rowpad = fullw-w;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -