www.pudn.com > xiaobo.zip.zip > coder_bpb.c


 
//#define ADD_CUR_WEIGHTS	// hurts !? 
//#define LOCAL_LENS		// hurts 
#define SCALEDOWN_LENS 
#define SCALEDOWN_SHIFT	0	// makes len* the very previous! 
 
//#define LOG 
 
#define FIFTH_SHAPE		// helps a peetle 
//#define XX_SHAPES		// hurts a tad 
//#define NO_XX			// X3 and X4 help an awful lot 
#define BIG_SHAPE_CNTX	// helps 0.006 
// #define BIG_SIGN_CONTEXT // hurts a teeny 
 
/***** 
 
	these are the weights for combining the various 
	moments to make an estimate	of the local activity 
 
context = ((CA * VD + CB * P + CC * N + CD * W + CE * NW + CF * NE + CG * X1 + CH * X2 + CI * X3 + CJ * X4)>>8) 
 
<>	these need to be trained on a test set	(not trivial) 
 
	and very important ! little random changes make 0.01 bpp diff 
 
******/ 
 
#define C1A 64 
#define C1B 64 
#define C1C 64 
#define C1D 64 
#define C1E 64 
#define C1F 64 
#define C1G 64 
#define C1H 64 
#define C1I 64 
#define C1J 64 
 
#define C2A 33 
#define C2B 33 
#define C2C 33 
#define C2D 33 
#define C2E 33 
#define C2F 33 
#define C2G 33 
#define C2H 33 
#define C2I 33 
#define C2J 33 
 
#define C3A 300 
#define C3B 170 
#define C3C 40 
#define C3D 40 
#define C3E 40 
#define C3F 40 
#define C3G 20 
#define C3H 20 
#define C3I 0 
#define C3J 0 
 
#define C4A 64 
#define C4B 32 
#define C4C 64 
#define C4D 64 
#define C4E 64 
#define C4F 64 
#define C4G 32 
#define C4H 32 
#define C4I 32 
#define C4J 32 
 
/***** 
 
binary version : codes each bit-pel as a separate binary event 
 
coding signs helps about 0.03 (better than the 0.02 observed 
	in earlier more primitive sign coders) 
 
our LOE : 
	don't actually compare the four contexts' MPS's, but just the four coders' 
	recent performance: choose the coder that had the lowest entropy on the 
	last N pixels. (some decaying record). 
 
instead of LOE, blend them based on confidence 
		(this is unusually easy because of the fact that 
		the alphabet is binary) 
	something like P_tot = W_tot * Sum P[n] / w[n] 
 
	where w is the weight = actual recent coded len 
		(TMW uses 2^(-w) instead of 1/w ) 
		(that may actually be better cuz we can do it with shifts; 
		you need some subtlety : find the smallest weight and factor it out first) 
 
* we're very similar to ECECOW, but getting stomped.  
  he beats us by almost 1.0 PSNR at the same bitrate 
 
--- 
 
e512 lossless, l6 
 
	lena : 4.141	(ececow : 4.06) 
	barb : 4.468	(ececow : 4.34) 
 
*****/ 
 
#include  
#include  
#include  
#include  
#include  
#include "coder.h" 
#include "subbands.h" 
 
extern int tune_param; 
 
#define	VAL_CONTEXTS		20 
#define	VAL_CONTEXT_MAX		(VAL_CONTEXTS -1) 
#define SHAPE_BASE			VAL_CONTEXTS 
#define SHAPE(x)			(SHAPE_BASE<<(x)) 
 
#ifdef BIG_SHAPE_CNTX 
#define NUM_SHAPES			5 
#else 
#define NUM_SHAPES			2 
#endif 
 
#define NUM_CONTEXTS		(VAL_CONTEXTS< TOTMAX ) { PT >>= 1; P0 >>= 1; P0++; PT += 2; } } while(0) 
#define bitEnc(bit,ari,P0,PT)	do { arithEncBit(ari,P0,PT,bit);	bitModel(bit,P0,PT); } while(0) 
#define bitDec(bit,ari,P0,PT)	do { bit = arithDecBit(ari,P0,PT);	bitModel(bit,P0,PT); } while(0) 
 
#define AddSignContext(context,val,mask) do { context *= 3; if( abs(val)&(mask) ) { if ( (val) > 0 ) context ++; else context += 2; } } while(0) 
 
#ifdef LOG 
int nbest1=0,nbest2=0,nbest3=0,nbest4=0; 
#endif 
 
typedef struct { 
	int p0,pt; 
} binContext; 
 
void coderBPbin_encodeSubbandBP(coder *me,subband_leaf *sb,int); 
void coderBPbin_decodeSubbandBP(coder *me,subband_leaf *sb,int); 
 
typedef struct { 
	binContext signs[SIGN_CONTEXTS]; 
	binContext	stats1[NUM_CONTEXTS], 
				stats2[NUM_CONTEXTS], 
				stats3[NUM_CONTEXTS], 
				stats4[NUM_CONTEXTS]; 
} myInfo; 
 
void coderBPbin_init(coder *c) 
{ 
myInfo *d; 
int i; 
 
	if ( (d = new(myInfo)) == NULL ) 
		errexit("ozero init failed"); 
 
	c->data = d; 
 
	for(i=0;istats1[i].p0 = P0_INIT+1; d->stats1[i].pt = 2+P0_INIT+P1_INIT; 
		d->stats2[i].p0 = P0_INIT+1; d->stats2[i].pt = 2+P0_INIT+P1_INIT; 
		d->stats3[i].p0 = P0_INIT+1; d->stats3[i].pt = 2+P0_INIT+P1_INIT; 
		d->stats4[i].p0 = P0_INIT+1; d->stats4[i].pt = 2+P0_INIT+P1_INIT; 
	} 
 
	for(i=0;isigns[i].p0 = 1; 
		d->signs[i].pt = 2; 
	} 
 
} 
 
void coderBPbin_free(coder *c) 
{ 
	if ( c->data ) { 
		myInfo *d; 
		d = c->data; 
		free(d); 
		c->data = NULL; 
	} 
} 
 
coder coderBPbin = { 
		"BitPlane Binary", 
		coderBPbin_init, 
		coderBPbin_free, 
		NULL,NULL,NULL,NULL,NULL,NULL, 
		coderBPbin_encodeSubbandBP, 
		coderBPbin_decodeSubbandBP 
	}; 
 
/********** 
 
lazy way to pass the state from getStats to fixStats 
	and also interacts with the codeBand() 
 
these are re-initialized at each codeBand() call, so this is 
	quite re-entrant as long as we aren't multi-threaded 
	(that is, no more than one call to codeBand() at a time) 
 
*********/ 
 
static int VD; 
static binContext *stats1,*stats2,*stats3,*stats4; 
static binContext *s1,*s2,*s3,*s4; 
static int len1,len2,len3,len4; 
static int *sister_x,*sister_y,sister_trans,*parent,parent_step,parent_mask,parent_shift; 
static int p0,pt,donemask,nextmask; 
 
int intentropy(int p0,int pt) 
{ 
return ((p0*(log2x16(pt) - log2x16(p0)) + (pt-p0)*(log2x16(pt) - log2x16(pt-p0)))<<3)/pt; 
} 
int LOEweight(int p0,int pt) 
{ 
if ( (pt - p0) < p0 ) p0 = (pt - p0); 
return log2x16(pt) - log2x16(p0); 
} 
 
static void getStats(int *dp,int *pp,int x,int y,int width,int height,int fullw) 
{ 
int shapes; 
int P,N,S,E,W,NE,NW,X1,X2,X3,X4; 
int diff,lena,lenb; 
binContext *sa,*sb; 
 
	/*** elaborate context-making ***/ 
 
	VD	= abs(*dp)&donemask;	// current val already done 
 
	P	= abs(*pp)&nextmask; 
 
	if ( y == 0 ) { 
		N = NW = NE = VD; 
		if ( x == 0 ) W = VD; else W = abs(dp[-1]) & nextmask; 
	} else if ( x == 0 ) { 
		W = NW = 0; 
		N  = abs(dp[-fullw])	& nextmask; 
		NE = abs(dp[1-fullw])	& nextmask; 
	} else { 
		N = abs(dp[-fullw])		& nextmask; 
		W = abs(dp[-1])			& nextmask; 
		NW = abs(dp[-1-fullw])	& nextmask; 
		if ( x == (width-1) ) NE = VD; 
		else NE = abs(dp[1-fullw]) & nextmask; 
	} 
 
	if ( y < (height-1) ) S = abs(dp[fullw]) & donemask; else S = VD; 
	if ( x < (width-1) ) E = abs(dp[1])	& donemask;	else E = VD; 
 
	if ( sister_x ) { 
			X1 = S; X2 = E; 
		switch(sister_trans) { 
			case 0: 
				X3 = abs( sister_x[ x + fullw*y ] ) & nextmask; 
				X4 = abs( sister_y[ x + fullw*y ] ) & nextmask; 
				break; 
			case 1: 
				X3 = abs( sister_x[ y + fullw*x ] ) & nextmask; 
				X4 = abs( sister_y[ x + fullw*y ] ) & nextmask; 
				break; 
			case 2: 
				X3 = abs( sister_x[ x + fullw*y ] ) & nextmask; 
				X4 = abs( sister_y[ y + fullw*x ] ) & nextmask; 
				break; 
			case 3: 
				X3 = abs( sister_x[ y + fullw*x ] ) & nextmask; 
				X4 = abs( sister_y[ y + fullw*x ] ) & nextmask; 
				break; 
		} 
	} else { 
 
		/** more vertical correlation (than horizontal) **/ 
 
		if ( y > 1 ) 			X1 = abs(dp[-fullw-fullw]) & nextmask; else X1 = VD;	//NN 
		X2 = S; 
		if ( y > parent_step ) 			X3 = abs(pp[-fullw])	& nextmask; else X3 = VD;		//PN 
		if ( y < (height - parent_step) )	X4 = abs(pp[fullw]) 	& nextmask; else X4 = VD;		//PS 
	} 
 
	shapes = 0; 
	if ( N > VD ) shapes += SHAPE(0); 
	if ( W > VD ) shapes += SHAPE(1); 
 
#ifdef BIG_SHAPE_CNTX 
#ifdef XX_SHAPES 
	if ( X1 > VD ) shapes += SHAPE(2); 
	if ( X2 > VD ) shapes += SHAPE(3); 
#else 
	if ( S > VD ) shapes += SHAPE(2); 
	if ( E > VD ) shapes += SHAPE(3); 
#endif 
#ifdef FIFTH_SHAPE 
	if ( (X3+X4+P) > 3*VD ) shapes += SHAPE(4); 
#endif 
#endif 
 
#ifdef NO_XX 
	X3 = X4 = 0; 
#endif 
 
	s1 = &stats1[ min(VAL_CONTEXT_MAX, ((C1A * VD + C1B * P + C1C * N + C1D * W + C1E * NW + C1F * NE + C1G * X1 + C1H * X2 + C1I * X3 + C1J * X4)>>8)) + shapes ]; 
	s2 = &stats2[ min(VAL_CONTEXT_MAX, ((C2A * VD + C2B * P + C2C * N + C2D * W + C2E * NW + C2F * NE + C2G * X1 + C2H * X2 + C2I * X3 + C2J * X4)>>8)) + shapes ]; 
	s3 = &stats3[ min(VAL_CONTEXT_MAX, ((C3A * VD + C3B * P + C3C * N + C3D * W + C3E * NW + C3F * NE + C3G * X1 + C3H * X2 + C3I * X3 + C3J * X4)>>8)) + shapes ]; 
	s4 = &stats4[ min(VAL_CONTEXT_MAX, ((C4A * VD + C4B * P + C4C * N + C4D * W + C4E * NW + C4F * NE + C4G * X1 + C4H * X2 + C4I * X3 + C4J * X4)>>8)) + shapes ]; 
 
	/** weighting  
	* 
	*	find the best two, then weight them by 2^(-entropy)  
	**/ 
 
#ifdef LOCAL_LENS 
	len1 = intentropy(s1->p0,s1->pt); 
	len2 = intentropy(s2->p0,s2->pt); 
	len3 = intentropy(s3->p0,s3->pt); 
	len4 = intentropy(s4->p0,s4->pt); 
#endif 
#ifdef ADD_CUR_WEIGHTS 
	len1 += LOEweight(s1->p0,s1->pt); 
	len2 += LOEweight(s2->p0,s2->pt); 
	len3 += LOEweight(s3->p0,s3->pt); 
	len4 += LOEweight(s4->p0,s4->pt); 
#endif 
 
	lena = len1; sa = s1; 
	if ( len2 < lena ) { lena = len2; sa = s2; } 
	if ( len3 < lena ) { lena = len3; sa = s3; } 
	if ( len4 < lena ) { lena = len4; sa = s4; } 
 
	lenb = INT_MAX; 
	if ( len1 < lenb && sa != s1 ) { lenb = len1; sb = s1; } 
	if ( len2 < lenb && sa != s2 ) { lenb = len2; sb = s2; } 
	if ( len3 < lenb && sa != s3 ) { lenb = len3; sb = s3; } 
	if ( len4 < lenb && sa != s4 ) { lenb = len4; sb = s4; } 
 
#ifdef LOG 
	     if ( sa == s1 ) nbest1++; 
	else if ( sa == s2 ) nbest2++; 
	else if ( sa == s3 ) nbest3++; 
	else if ( sa == s4 ) nbest4++; 
#endif 
 
	if ( lena == lenb ) { 
		p0 = (sa->p0 + sb->p0)>>1; 
		pt = (sa->pt + sb->pt)>>1; 
	} else if ( lenb < lena ) { 
		diff = 1 + ((lena-lenb+8)>>4); 
		if ( diff >= 18 ) { 
			p0 = sb->p0; 
			pt = sb->pt; 
		} else { 
			p0 = (((sb->p0)<p0))/((1<pt)<pt))/((1<>4); 
		if ( lenb-lena >= 18 ) { 
			p0 = sa->p0; 
			pt = sa->pt; 
		} else { 
			p0 = (((sa->p0)<p0))/((1<pt)<pt))/((1<>SCALEDOWN_SHIFT; 
	len2 -= len2>>SCALEDOWN_SHIFT; 
	len3 -= len3>>SCALEDOWN_SHIFT; 
	len4 -= len4>>SCALEDOWN_SHIFT; 
#endif 
 
	if ( bit ) { 
		len1 += log2x16( s1->pt ) - log2x16( s1->pt - s1->p0 ); 
		len2 += log2x16( s2->pt ) - log2x16( s2->pt - s2->p0 ); 
		len3 += log2x16( s3->pt ) - log2x16( s3->pt - s3->p0 ); 
		len4 += log2x16( s4->pt ) - log2x16( s4->pt - s4->p0 ); 
 
		if ( len1 > 40000 ) {	/** for safety **/ 
			len1 >>= 1; len2 >>= 1; len3 >>= 1; len4 >>= 1; 
		} 
	} else { 
		len1 += log2x16( s1->pt ) - log2x16( s1->p0 ); 
		len2 += log2x16( s2->pt ) - log2x16( s2->p0 ); 
		len3 += log2x16( s3->pt ) - log2x16( s3->p0 ); 
		len4 += log2x16( s4->pt ) - log2x16( s4->p0 ); 
	} 
#endif 
 
	bitModel(bit,s1->p0,s1->pt); 
	bitModel(bit,s2->p0,s2->pt); 
	bitModel(bit,s3->p0,s3->pt); 
	bitModel(bit,s4->p0,s4->pt); 
 
} 
 
static void codeBand_init(coder *me,subband_leaf *sb) 
{ 
myInfo *d; 
int i; 
 
	d = (myInfo *)me->data; 
 
	if ( sb->cntx1 && sb->cntx1shift == 0 && sb->cntx2 && sb->cntx2shift == 0 ) { 
		sister_x = sb->cntx1->band; 
		sister_y = sb->cntx2->band; 
		sister_trans = 0; 
		if ( sb->cntx1->transposed != sb->transposed ) sister_trans |= 1; 
		if ( sb->cntx2->transposed != sb->transposed ) sister_trans |= 2; 
	} else { 
		sister_x = sister_y = NULL; 
	} 
 
	len1=len2=len3=len4=0; 
	stats1 = d->stats1; 
	stats2 = d->stats2; 
	stats3 = d->stats3; 
	stats4 = d->stats4; 
 
	parent = sb->parent->band; 
	parent_step = (sb->width) / (sb->parent->width); 
	if ( parent_step == 0 ) errexit("BP_bin can't handle parent bigger than band"); 
	parent_mask = parent_step - 1; 
	parent_shift = 0; 
	for(i=parent_step;i>1;i>>=1) parent_shift++; 
} 
 
void coderBPbin_encodeSubbandBP(coder *me,subband_leaf *sb,int bitmask) 
{ 
int *band,width,height,fullw; 
int x,y,bit; 
int *dp,*pp,*dpn; 
arithInfo *ari = me->arith; 
binContext *signs = ((myInfo *)me->data)->signs; 
 
	for(x= bitmask,nextmask=0; xband; width = sb->width; height = sb->height; fullw = sb->rowpad + width; 
 
	codeBand_init(me,sb); 
 
	dp = band;	pp = parent; 
	for(y=0;y>parent_shift],x,y,width,height,fullw); 
 
			bit = (abs(dp[x])&bitmask)?1:0; 
			arithEncBit(ari,p0,pt,bit); 
 
			fixStats(bit); 
 
			if ( bit & !VD ) { 
				int context; 
				/** code the sign **/ 
				context = 0; 
				if ( x < (width-1) )	AddSignContext(context,dp[x+1],donemask); else AddSignContext(context,0,0); 
				if ( x > 0 )			AddSignContext(context,dp[x-1],nextmask); else AddSignContext(context,0,0); 
				if ( y < (height-1) )	AddSignContext(context,dp[x+fullw],donemask); else AddSignContext(context,0,0); 
				if ( y > 0 )			AddSignContext(context,dp[x-fullw],nextmask); else AddSignContext(context,0,0); 
#ifdef BIG_SIGN_CONTEXT 
				if ( y > 0 && x > 0 )	AddSignContext(context,dp[x-fullw-1],nextmask); else AddSignContext(context,0,0); 
				if ( y > 0 && x < (width-1) )	AddSignContext(context,dp[x-fullw+1],nextmask); else AddSignContext(context,0,0); 
#endif 
				bitEnc( (isneg(dp[x])?1:0) ,ari,signs[context].p0,signs[context].pt); 
			} 
			 
		} 
		if ( (y & parent_mask) == parent_mask ) pp += fullw; 
		dp += fullw; 
	} 
 
 
#ifdef LOG 
printf("nbest : 1 = %d , 2 = %d , 3 = %d , 4 = %d \n",nbest1,nbest2,nbest3,nbest4); 
#endif 
} 
 
void coderBPbin_decodeSubbandBP(coder *me,subband_leaf *sb,int bitmask) 
{ 
int *band,width,height,fullw; 
int x,y,bit; 
int *dp,*pp,*dpn; 
arithInfo *ari = me->arith; 
binContext *signs = ((myInfo *)me->data)->signs; 
 
	band = sb->band; width = sb->width; height = sb->height; fullw = sb->rowpad + width; 
 
	codeBand_init(me,sb); 
 
	for(x= bitmask,nextmask=0; x>parent_shift],x,y,width,height,fullw); 
 
			bit = arithDecBit(ari,p0,pt); 
 
			fixStats(bit); 
 
			if ( bit ) { 
				if ( isneg(dp[x]) ) dp[x] -= bitmask; 
				else dp[x] += bitmask;  
				if ( ! VD ) { 
					int context; 
					/** code the sign **/ 
					context = 0; 
					if ( x < (width-1) )	AddSignContext(context,dp[x+1],donemask); else AddSignContext(context,0,0); 
					if ( x > 0 )			AddSignContext(context,dp[x-1],nextmask); else AddSignContext(context,0,0); 
					if ( y < (height-1) )	AddSignContext(context,dp[x+fullw],donemask); else AddSignContext(context,0,0); 
					if ( y > 0 )			AddSignContext(context,dp[x-fullw],nextmask); else AddSignContext(context,0,0); 
#ifdef BIG_SIGN_CONTEXT 
					if ( y > 0 && x > 0 )	AddSignContext(context,dp[x-fullw-1],nextmask); else AddSignContext(context,0,0); 
					if ( y > 0 && x < (width-1) )	AddSignContext(context,dp[x-fullw+1],nextmask); else AddSignContext(context,0,0); 
#endif 
					bitDec(bit,ari,signs[context].p0,signs[context].pt); 
					if ( bit ) dp[x] = - dp[x]; 
				} 
			} 
		} 
		if ( (y & parent_mask) == parent_mask ) pp += fullw; 
		dp += fullw; 
	} 
}