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

📄 doublecode.cpp

📁 改进的JPEG-LS算法
💻 CPP
字号:
#include "stdafx.h"
#include <math.h>
#include "DoubleCode.h"
/*
				关于行尾大误差数的编码规则


  概率模型: <1>各象素相互独立,<2>每象素是大误差的概率为 p

  模型估计: 主要是估计 p 值,定初值为 1/8,每行编码结束时累计象素数(PixN)与大误差数(ErrN),p=ErrN/PixN
			实际使用值为 DoubleN=(PixN*16)/ErrN 意义是每(DoubleN/16)象素中含有一个大误差,
			*16 目的是提高精度

  二项分布的半概率点确定:
			设某行尾累积待检大误差的象素数为 N, 已检出大误差数为 en, 半概率点位置在 K
			K=(N*16+[DoubleN/4])/DoubleN 

  半概率点所在区宽度确定:
			此宽度由半概率点 K 决定, 由于函数关系不好列出, 采用查表方法, 建立对应表.

  编码过程: <1> 由象素数 N 和概率倒数值 DoubleN, 求 K 值.
			<2> 由 K 值求 Huffman编码的宽度表.
			<3> 检测待编码的大误差象素数所处的区间, 并编出首码(0...01)0的个数是区间号.以1比特表示上下区.
			<4> 根据区间的位置与宽度, 编码大误差数在区间的精确位置, 采用Huffman编码, 这是尾码部分.
			<5> 更新PixN、ErrN值.

  补充: 构造不同项数的 Huffman 码表, 概率是按大到小排队的, 但相差并不大, 这个表在几何分布的编码中也可用.
		HuffcodingBit[6][7]存放码表, HuffcodingL[6][7]存放码长, 大于等于8时用自然二进 

*/
CDoubleErrorNumberFastCoding::CDoubleErrorNumberFastCoding()
{
		Init();
		Reset();
}
void CDoubleErrorNumberFastCoding::Reset()
{
		PixN=8;
		ErrN=1;//初始概率1/8
		BitNumber=0;
}
void CDoubleErrorNumberFastCoding::Init()
{
		int i;

		UsingBinaryCode=FALSE;

		for(i=0;i<PART_WIDTH1_HALF_PROBABILITY_FAST_SEAT;i++){PartW[i]=1;PartBit[i]=0;}
		for(;i<PART_WIDTH2_HALF_PROBABILITY_FAST_SEAT;i++){PartW[i]=2;PartBit[i]=1;}
		for(;i<PART_WIDTH4_HALF_PROBABILITY_FAST_SEAT;i++){PartW[i]=4;PartBit[i]=2;}
		for(;i<PART_WIDTH8_HALF_PROBABILITY_FAST_SEAT;i++){PartW[i]=8;PartBit[i]=3;}

}
int/*返回编码比持数*/ CDoubleErrorNumberFastCoding::OneEncodePass(int Number/*总象素数*/,int ErrorN/*待编码的大误差数*/,LPBYTE lpCodeBit,int Bitcp)
{
/*  编码过程: <1> 由象素数 N 和概率倒数值 DoubleN, 求 K 值.
			  <2> 由 K 值求区间宽度和区间内编码比特数.
			  <3> 检测待编码的大误差象素数所处的区间, 并编出首码(0...01)0的个数是区间号.以1比特表示上下区.
			  <4> 根据区间的位置与宽度, 编码大误差数在区间的精确位置, 这是尾码部分.
			  <5> 更新PixN、ErrN值.
*/
		int DoubleN=(PixN<<4)/ErrN;
		int W,Code,D,d,n,CodeL,N,K,bitn;
		N=Number;
// <1> 由象素数 N 和概率倒数值 DoubleN, 求 K 值.
		if(UsingBinaryCode==FALSE)K=((N<<4)+(DoubleN>>2))/DoubleN;
		else K=MAX_HALF_PROBABILITY_FAST_SEAT+1;
		if(K<=MAX_HALF_PROBABILITY_FAST_SEAT)
		{//采用二项分布快速编码
 //<2> 由 K 值求区间宽度和区间内编码比特数.
			W=PartW[K];
			bitn=PartBit[K];
			if(K<1)
			{
				if(ErrorN<MAX_0_NUMBER){Code=1<<ErrorN;CodeL=ErrorN+1;}
				else
				{//采用自然二进制编码
					for(n=0;n<14&&(1<<n)<Number;n++);
					Code=(1<<MAX_0_NUMBER)|(ErrorN<<(MAX_0_NUMBER+1));
					CodeL=MAX_0_NUMBER+1+n;
				}
			}
			else
			{
				if(ErrorN>=K)
				{
					D=ErrorN-K;
//<3> 检测待编码的大误差象素数所处的区间, 并编出首码(0...01)0的个数是区间号.以1比特表示上下区.
					n=D/W;
					d=D%W;
					if(n<MAX_0_NUMBER)
					{
						Code=(3<<n);CodeL=n+2;//包含上下位区间的指示比特1
						Code|=d<<CodeL;
						CodeL+=bitn;
					}
					else
					{//采用自然二进制编码
						for(n=0;n<14&&(1<<n)<Number;n++);
						Code=(1<<MAX_0_NUMBER)|(ErrorN<<(MAX_0_NUMBER+1));
						CodeL=MAX_0_NUMBER+1+n;
					}
				}
				else
				{
					D=K-1-ErrorN;//K值本身是在下区间编码的,上区间将不含它
//<3> 检测待编码的大误差象素数所处的区间, 并编出首码(0...01)0的个数是区间号.以1比特表示上下区.
					n=D/W;
					d=D%W;
					if(n<MAX_0_NUMBER)
					{
						Code=(1<<n);CodeL=n+2;//包含上下位区间的指示比特1
						Code|=d<<CodeL;
						CodeL+=bitn;
					}
					else
					{//采用自然二进制编码
							for(n=0;n<14&&(1<<n)<Number;n++);
							Code=(1<<MAX_0_NUMBER)|(ErrorN<<(MAX_0_NUMBER+1));
							CodeL=MAX_0_NUMBER+1+n;
					}
				}
			}
		}
		else
		{//采用自然二进制编码
			for(n=0;n<14&&(1<<n)<Number;n++);Code=ErrorN;CodeL=n;
		}
 //<5> 更新PixN、ErrN值.
		PixN+=N;
		ErrN+=ErrorN;
		if(PixN>0x1000000)
		{
			PixN>>=1;
			ErrN>>=1;
		}
		if((Bitcp&7)+CodeL<32)(*((int *)(lpCodeBit+(Bitcp>>3))))|=(Code<<(Bitcp&7));
		else 
		{
			(*((int *)(lpCodeBit+(Bitcp>>3))))|=((Code&0xff)<<(Bitcp&7));
			(*((int *)(lpCodeBit+(Bitcp>>3)+1)))|=((Code>>8)<<(Bitcp&7));
		}
		BitNumber+=CodeL;
		return CodeL;
}
int/*返回大误差数*/ CDoubleErrorNumberFastCoding::OneDecodePass(int Number/*总象素数*/,LPBYTE lpCodeBit/*码流指针*/,int Bitcp/*码流比特位*/,int &CodeL)
{
		int DoubleN;
		int W,n,ErrorN,ZeroN;//初始区间宽度
		int N,K,bitn;
		N=Number;
		int UpDown;
		if(ErrN>0)DoubleN=(PixN<<4)/ErrN;//<<4是统一乘以16,提高精度,最后再统一除以16。
		else DoubleN=(PixN<<4);
// <1> 由象素数 N 和概率倒数值 DoubleN, 求 K 值.
		if(UsingBinaryCode==FALSE)K=((N<<4)+(DoubleN>>2))/DoubleN;
		else K=MAX_HALF_PROBABILITY_FAST_SEAT+1;
		if(K<=MAX_HALF_PROBABILITY_FAST_SEAT)
		{//采用二项分布译码
 //<2> 由 K 值求 Huffman编码的宽度表.
			W=PartW[K];
			bitn=PartBit[K];
			ZeroN=ReturnZeroBitNumber(lpCodeBit,Bitcp);
			if(K<1)
			{
				if(ZeroN<MAX_0_NUMBER){ErrorN=ZeroN;CodeL=ErrorN+1;}
				else
				{//采用自然二进制译码
					for(n=0;n<14&&(1<<n)<Number;n++);
					ErrorN=GetFromBitStream(lpCodeBit,Bitcp+MAX_0_NUMBER+1,n);
					CodeL=MAX_0_NUMBER+1+n;
				}
			}
			else
			{
				UpDown=GetFromBitStream(lpCodeBit,Bitcp+ZeroN+1,1);
				CodeL=ZeroN+2;
				if(UpDown)
				{
//<3> 检测待编码的大误差象素数所处的区间, 并编出首码(0...01)0的个数是区间号.以1比特表示上下区.
					if(ZeroN<MAX_0_NUMBER)
					{//在编码允许范围内,0 的个数就是跳过的区间数
						ErrorN=K+ZeroN*W+GetFromBitStream(lpCodeBit,Bitcp+CodeL,bitn);
						CodeL+=bitn;
					}
					else
					{//采用自然二进制译码
						for(n=0;n<14&&(1<<n)<Number;n++);
						ErrorN=GetFromBitStream(lpCodeBit,Bitcp+MAX_0_NUMBER+1,n);
						CodeL=MAX_0_NUMBER+1+n;
					}
				}
				else
				{
//<3> 检测待编码的大误差象素数所处的区间, 并编出首码(0...01)0的个数是区间号.以1比特表示上下区.
					if(ZeroN<MAX_0_NUMBER)
					{//在编码允许范围内,0 的个数就是跳过的区间数
						ErrorN=K-1-ZeroN*W-GetFromBitStream(lpCodeBit,Bitcp+CodeL,bitn);
						CodeL+=bitn;
					}
					else
					{//采用自然二进制译码
							for(n=0;n<14&&(1<<n)<Number;n++);
							ErrorN=GetFromBitStream(lpCodeBit,Bitcp+MAX_0_NUMBER+1,n);
							CodeL=MAX_0_NUMBER+1+n;
					}
				}
			}
		}
		else
		{
			for(n=0;n<14&&(1<<n)<Number;n++);
			ErrorN=GetFromBitStream(lpCodeBit,Bitcp,n);
			CodeL=n;
		}
 //<5> 更新PixN、ErrN值.
		PixN+=N;
		ErrN+=ErrorN;
		if(PixN>0x1000000)
		{
			PixN>>=1;
			ErrN>>=1;
		}
		return ErrorN;
}
int CDoubleErrorNumberFastCoding::ReturnZeroBitNumber(LPBYTE lpCodeStream,int CodeBitcp)
{//在当前的码流位置上,检查连续'0'的个数。
		int a,i,j;
		a=(*((int *)(lpCodeStream+(CodeBitcp>>3)))>>(CodeBitcp&7))&0xffffff;
		if(a==0)
		{
			i=24;
			a=(*((int *)(lpCodeStream+(CodeBitcp>>3)+3))>>(CodeBitcp&7))&0xffffff;
			if(a==0)
			{
				i+=24;
				a=(*((int *)(lpCodeStream+(CodeBitcp>>3)+6))>>(CodeBitcp&7))&0xffffff;
				for(j=1;(a&j)==0&&j<0x1000000;j<<=1,i++);
			}
			else for(j=1;(a&j)==0&&j<0x1000000;j<<=1,i++);
		}
		else for(j=1,i=0;(a&j)==0&&j<0x1000000;j<<=1,i++);
		return i;
}
int CDoubleErrorNumberFastCoding::GetFromBitStream(LPBYTE lpCodeStream,int CodeBitcp,int b)
{//在当前的码流位置上取出 b  比特,比特放入低位作为返回值。一般不能大24比特。
		return (*((int *)(lpCodeStream+(CodeBitcp>>3)))>>(CodeBitcp&7))&~((-1)<<b);
}
/*
				关于行尾大误差游程的编码规则


  概率模型: <1>各象素相互独立,<2>每象素是大误差的概率为 p,<3> 0 游程长为l时的概率为p*(1-p)^l

  模型估计: 主要是估计 p 值, 设象素数为 N, 大误差数为 en, p=en/N, 每编码一个大误差en与N各减1,

  几何分布的半概率点确定:
			编码区间宽度的估算 K=(N*log2)/en, (log2可以转化为两个整数的比值),
			当 K>8 时, K 取最小的大于K的2幂

  编码过程: <1> 由象素数 N 和大误差数 en, 求 K 值.
			<2> 检测待编码的大误差游程所处的区间, 并编出首码(0...01)0的个数是区间号.以1比特表示大误差的符号.
			<3> 根据区间的宽度, 编码大误差数在区间的精确位置, 采用Huffman编码, 这是尾码部分.
			<4> 更新N、en值.

  补充: 构造不同项数的 Huffman 码表, 概率是按大到小排队的, 但相差并不大, 这个表在几何分布的编码中也可用.
		HuffcodingBit[8][8]存放码表, HuffcodingL[8][8]存放码长, 大于等于8时用自然二进 
*/
CDoubleErrorRunFastCoding::CDoubleErrorRunFastCoding()
{
		Init();
		Reset();
}
void CDoubleErrorRunFastCoding::Reset()
{
		BitNumber=0;
}
void CDoubleErrorRunFastCoding::Init()
{
		UsingBinaryCode=FALSE;
}
int CDoubleErrorRunFastCoding::GetHalfProbabilityWidth(int Number,int ErrorN,int &Bitn)
{
//		int W=(int)((Number*log(2))/ErrorN);
//		int W=(Number*69314)/ErrorN/100000;
		int W=(Number*709)/ErrorN/1024;
		for(Bitn=0;(1<<Bitn)<W;Bitn++);
		if(W<(1<<Bitn)&&Bitn>1)Bitn--;
		W=(1<<Bitn);
		return W;
}
int/*返回编码比持数*/ CDoubleErrorRunFastCoding::OneEncodePass(int Number/*总象素数*/,
															int ErrorN/*待编码的大误差数*/,
															int RunL,
															LPBYTE lpCodeBit,int Bitcp)
{
/*  编码过程: <1> 由象素数 N 和大误差数 en, 求 K 值.
			  <2> 检测待编码的大误差游程所处的区间, 并编出首码(0...01)0的个数是区间号.以1比特表示大误差的符号.
			  <3> 根据区间的宽度, 编码大误差数在区间的精确位置, 采用Huffman编码, 这是尾码部分.
			  <4> 更新N、en值.
*/
		if(ErrorN<=0||Number<ErrorN)return 0;
		int W,Code,n,CodeL,Bitn,ZeroN,Seat;//初始区间宽度
// <1> 由象素数 N 和大误差数 en, 求 W 值.
		if(UsingBinaryCode==FALSE)W=GetHalfProbabilityWidth(Number,ErrorN,Bitn);
		else W=MAX_HALF_PROBABILITY_FAST_WIDTH+1;
		if(W<1)W=1;
		if(W<=MAX_HALF_PROBABILITY_FAST_WIDTH)
		{//采用几何分布编码
			ZeroN=RunL/W;
			Seat=RunL%W;
//			for(ZeroN=0,Seat=RunL;Seat>=W;ZeroN++)
//			{
//				Seat-=W;
//				if(ZeroN>8)
//				{
//					W<<=1;
//					Bitn++;
//				}
//			}
			if(ZeroN<MAX_0_NUMBER)
			{
				Code=1<<ZeroN;
				CodeL=ZeroN+1;
				Code|=(Seat<<CodeL);
				CodeL+=Bitn;
			}
			else
			{//采用自然二进制编码
				for(n=0;n<14&&(1<<n)<Number;n++);
				Code=(1<<MAX_0_NUMBER)|(RunL<<(MAX_0_NUMBER+1));
				CodeL=MAX_0_NUMBER+1+n;
			}
		}
		else
		{//采用自然二进制编码
			for(n=0;n<14&&(1<<n)<Number;n++);Code=RunL;CodeL=n;
		}
 		if((Bitcp&7)+CodeL<32)(*((int *)(lpCodeBit+(Bitcp>>3))))|=(Code<<(Bitcp&7));
		else 
		{
			(*((int *)(lpCodeBit+(Bitcp>>3))))|=((Code&0xff)<<(Bitcp&7));
			(*((int *)(lpCodeBit+(Bitcp>>3)+1)))|=((Code>>8)<<(Bitcp&7));
		}
		BitNumber+=CodeL;
		return CodeL;
}
int/*返回大误游程*/ CDoubleErrorRunFastCoding::OneDecodePass(int Number/*总象素数*/,
													   int ErrorN/*待编码的大误差数*/,
													   LPBYTE lpCodeBit/*码流指针*/,int Bitcp/*码流比特位*/,
													   int &CodeL)
{
		if(ErrorN<=0||Number<ErrorN)return 0;
		int W,n,ZeroN,Seat,RunL,Bitn;//初始区间宽度
		if(UsingBinaryCode==FALSE)W=GetHalfProbabilityWidth(Number,ErrorN,Bitn);
		else W=MAX_HALF_PROBABILITY_FAST_WIDTH+1;
		if(W<1)W=1;
		if(W<=MAX_HALF_PROBABILITY_FAST_WIDTH)
		{//采用几何分布译码
 //<2> 由 K 值求 Huffman编码的宽度表.
			ZeroN=ReturnZeroBitNumber(lpCodeBit,Bitcp);
			if(ZeroN<MAX_0_NUMBER)
			{
				CodeL=ZeroN+1;
				RunL=ZeroN*W;
//				RunL=0;
//				if(ZeroN>0)for(n=0;n<ZeroN;n++)
//				{
//					RunL+=W;
//					if(n>8)
//					{
//						W<<=1;
//						Bitn++;
//					}
//				}
				Seat=GetFromBitStream(lpCodeBit,Bitcp+ZeroN+1,Bitn);
				RunL+=Seat;
				CodeL+=Bitn;
			}
			else
			{//采用自然二进制译码
				for(n=0;n<14&&(1<<n)<Number;n++);
				RunL=GetFromBitStream(lpCodeBit,Bitcp+MAX_0_NUMBER+1,n);
				CodeL=MAX_0_NUMBER+1+n;
			}
		}
		else
		{
			for(n=0;n<14&&(1<<n)<Number;n++);
			RunL=GetFromBitStream(lpCodeBit,Bitcp,n);
			CodeL=n;
		}
		return RunL;
}
int CDoubleErrorRunFastCoding::ReturnZeroBitNumber(LPBYTE lpCodeStream,int CodeBitcp)
{//在当前的码流位置上,检查连续'0'的个数。
		int a,i,j;
		a=(*((int *)(lpCodeStream+(CodeBitcp>>3)))>>(CodeBitcp&7))&0xffffff;
		if(a==0)
		{
			i=24;
			a=(*((int *)(lpCodeStream+(CodeBitcp>>3)+3))>>(CodeBitcp&7))&0xffffff;
			if(a==0)
			{
				i+=24;
				a=(*((int *)(lpCodeStream+(CodeBitcp>>3)+6))>>(CodeBitcp&7))&0xffffff;
				for(j=1;(a&j)==0&&j<0x1000000;j<<=1,i++);
			}
			else for(j=1;(a&j)==0&&j<0x1000000;j<<=1,i++);
		}
		else for(j=1,i=0;(a&j)==0&&j<0x1000000;j<<=1,i++);
		return i;
}
int CDoubleErrorRunFastCoding::GetFromBitStream(LPBYTE lpCodeStream,int CodeBitcp,int b)
{//在当前的码流位置上取出 b  比特,比特放入低位作为返回值。一般不能大24比特。
		return (*((int *)(lpCodeStream+(CodeBitcp>>3)))>>(CodeBitcp&7))&~((-1)<<b);
}

⌨️ 快捷键说明

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