1. 程式人生 > >JPEG影象壓縮解壓演算法——C++實現

JPEG影象壓縮解壓演算法——C++實現

/**
*	作者:戴文治
*	時間:2017年11月17日
*	描述:JPEG壓縮與解壓演算法
*	測試環境:Dev-C++ 5.9.2
*/

#include<iostream>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#define MAX 100
#define N 8 	//N為每個影象分量的矩陣大小
using namespace std; 

/*亮度量化值表*/
struct  BrightnessQuantizedValueTable{
	int Q[N][N];
	BrightnessQuantizedValueTable(){
		int x[N][N]={16,11,10,16,24,40,51,61,
					 12,12,14,19,26,58,60,55,
					 14,13,16,24,40,57,69,56,
					 14,17,22,29,51,87,80,62,
					 18,22,37,56,68,109,103,77,
					 24,35,55,64,81,104,113,92,
					 49,64,78,87,103,121,120,101,
					 72,92,95,98,112,100,103,99};
		for(int i=0;i<N;i++){
			for(int j=0;j<N;j++){
				Q[i][j] = x[i][j];
			}
		} 
	}
};
BrightnessQuantizedValueTable brightnessQuantizedValueTable;//定義一個亮度量化值表

/*亮度DC差值碼錶*/
struct BrightnessDC_DifferenceTableList{
	string brightnessDC_DifferenceTable[12];//亮度DC差值碼錶  類別(陣列下標)與碼字對映
	BrightnessDC_DifferenceTableList(){
		brightnessDC_DifferenceTable[0]="00";
		brightnessDC_DifferenceTable[1]="010";
		brightnessDC_DifferenceTable[2]="011";
		brightnessDC_DifferenceTable[3]="100";
		brightnessDC_DifferenceTable[4]="101";
		brightnessDC_DifferenceTable[5]="110";
		brightnessDC_DifferenceTable[6]="1110";
		brightnessDC_DifferenceTable[7]="11110";
		brightnessDC_DifferenceTable[8]="111110";
		brightnessDC_DifferenceTable[9]="1111110";
		brightnessDC_DifferenceTable[10]="11111110";
		brightnessDC_DifferenceTable[11]="111111110";
	}
};
BrightnessDC_DifferenceTableList brightnessDC_DifferenceTableList;//定義一個亮度DC差值碼錶


/*AC係數熵編碼時的中間符號*/
struct AC_EntropyCoding_MiddleSymbol{
	string R_S;
	int temp; 
};
AC_EntropyCoding_MiddleSymbol ac_EntropyCoding_MiddleSymbol[N*N];//由於用函式返回結構體陣列,裡面的字串會出現一些無法處理的亂碼,故定義為全域性變數 

/*熵編碼時的編碼輸出*/
struct EntropyCoding{
	string strTemp1;
	string strTemp;
};
EntropyCoding ac_EntropyCodingStr[N*N];//由於用函式返回結構體陣列,裡面的字串會出現一些無法處理的亂碼,故定義為全域性變數 


/* R/S與碼字對映結點*/
struct StringMap{
	string key;
	string value;
}; 

/*亮度AC碼錶  R/S與碼字對映表*/
/**特別注意,以下的亮度AC碼錶只適用於給出的測試資料,如要其它的測試資料,則必須補全亮度AC碼錶**/
//網上找到一個fantasy 的部落格http://menmory.blog.163.com/blog/static/12690012620114535032530/ 這裡面有比較詳細的亮度AC碼錶等 
struct StringMapList{
	StringMap stringMap[N*N];
	int partNum;	//該亮度AC碼錶中的條數 
	
	StringMapList(){
		//部分常用亮度AC碼錶
		stringMap[0].key = "0/0(EOB)";
		stringMap[0].value = "1010";
		stringMap[1].key = "0/1";
		stringMap[1].value = "00"; 
		stringMap[2].key = "1/1";
		stringMap[2].value = "1100";
		stringMap[3].key = "1/2";
		stringMap[3].value = "11011";
		stringMap[4].key = "2/1";
		stringMap[4].value = "11100";
		stringMap[5].key = "3/2";
		stringMap[5].value = "111110111";
		stringMap[6].key = "F/0(ZRL)";
		stringMap[6].value = "11111111001";
		stringMap[7].key = "F/F";
		stringMap[7].value = "1111111111111110";
		partNum = 8;
	}
};
StringMapList stringMapList;//定義一個 部分常用亮度AC碼錶


/*DC差值範圍表,本人通過對錶找規律發現如下規律 */
int DC_Difference(int temp){
	int temp1;
	if(temp == 0){
		 temp1 = 0;
	}else{
		for(int i=1;i<=11;i++){
			if(abs(temp)<pow(2,i)){
				temp1 = i;
				break;
			}
		}
	}
	return temp1;
}


/*AC係數範圍表,本人通過對錶找規律發現如下規律*/
int AC_Difference(int temp){
	int temp1;
	if(temp == 0){
		 temp1 = 0;
	}else{
		for(int i=1;i<=10;i++){
			if(abs(temp)<pow(2,i)){
				temp1 = i;
				break;
			}
		}
	}
	return temp1;
}


/*將正整數十進位制轉換成二進位制*/ 
string TenToTwo(int temp){
	string strTemp="";
	//舊方法 
//	for(int k=abs(temp);k>0;k=k/2){
//		strTemp = strTemp + (k%2==1?'1':'0');
//	}
//	//倒置 
//	int len = strTemp.length();
//	for(int k=0;k<len/2;k++){
//		char t = strTemp[k];
//		strTemp[k] = strTemp[len-1-k];
//		strTemp[len-1-k] = t;
//	}
	//新方法 
	char str[N*N];
	itoa(temp,str,2);
	strTemp = str; 
	return strTemp; 
}


/*將正整數二進位制轉換成十進位制*/ 
int TwoToTen(string strTemp){
	int temp=0;
	for(int i=0;i<strTemp.length();i++){
		temp = temp*2+strTemp[i]-'0';
	}
	return temp;
} 

/*將一個負數的二進位制串逐位取反*/ 
string ConvertToComplement(string strTemp){
	string str = "";
	for(int i=0;i<strTemp.length();i++){
		str = str + (strTemp[i]=='1'?'0':'1');
	}
	return str;
} 


/*DC係數編碼*/
EntropyCoding DC_EntropyCoding(int &temp,int &temp1){
	//對DC係數生成中間符號(中間符號(temp1,temp))
	
	//查DC差值表
	temp1 = DC_Difference(temp);
	
	/*測試*/
//	cout<<temp1<<endl;
	
	//對中間符號通過查表進行符號編碼 
	//對 temp1通過查亮度DC差值碼錶進行熵編碼
	EntropyCoding dc_EntropyCodingStr; 
	dc_EntropyCodingStr.strTemp1 = brightnessDC_DifferenceTableList.brightnessDC_DifferenceTable[temp1];

	//對 temp進行轉換成補碼 
	//先將 temp轉換成二進位制串
	dc_EntropyCodingStr.strTemp = TenToTwo(abs(temp));
	//轉換成補碼
	if(temp<0){
		dc_EntropyCodingStr.strTemp = ConvertToComplement(dc_EntropyCodingStr.strTemp);	
	}
	
	/*測試*/
//	cout<<dc_EntropyCodingStr.strTemp1<<"\t"<<dc_EntropyCodingStr.strTemp<<endl;
	
	return dc_EntropyCodingStr;
}


/*AC係數編碼*/
bool AC_EntropyCoding(int F_[N][N],int &index){
	//對AC係數生成中間符號中/後的部分 
	int SSSS[N][N];
	
	//查AC係數範圍表,本人通過對錶找規律發現如下規律 
	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){
			SSSS[i][j] = AC_Difference(F_[i][j]);
		}
	}
	
	/*測試*/
//	for(int i=0;i<N;i++){
//		for(int j=0;j<N;j++){
//			cout<<SSSS[i][j]<<" ";
//		}
//		cout<<endl;
//	}
	
	//Z字形編碼
	int count = 0;//計算0的個數
	int i,j,t; 
	for(i=0,j=1,t=1;t<=N-2;t++){//以下語句設為一個週期,大概要執行N-2個週期(這裡N=8,通過觀察發現每一下一上為一週期,則有6個週期+半段) 
		//向左下方向 
		for(;i<N&&j>=0;i++,j--){
			if(F_[i][j]==0){
				count++;
			}else{
				char countString[N*N];
				itoa(count,countString,10);//將整數count轉換為字串並儲存在countString(以10進位制方式,也可指定2、8、10、16等進位制實現進位制轉換,進位制轉換新玩法) 
				string strTemp = "/";
				strTemp = countString + strTemp;
				//cout<<"--"<<strTemp<<"--"<<endl;
				char SSSS_String[N*N];
				itoa(SSSS[i][j],SSSS_String,10);
				strTemp = strTemp + SSSS_String;
				//cout<<"**"<<strTemp<<"**"<<endl;
				
				//中間符號 
				ac_EntropyCoding_MiddleSymbol[index].R_S = strTemp;
				ac_EntropyCoding_MiddleSymbol[index].temp = F_[i][j];
				index++;
				count = 0;//置為0 ,計算下個不為0的數前面0的個數 
			}
		}
		if(i>=N&&j<0){//當出現正中間往下時,挪回正規 
			i--;
			j = j+2;
		}else if(i>=N){//當出現往下突出時,挪回正規 
			i--;
			j = j+2;
		}else if(j<0){//當出現往左突出時,挪回正規
			j++; 
		}
		
		//向右上方向 
		for(;i>=0&&j<N;i--,j++){
			if(F_[i][j]==0){
				count++;
			}else{
				char countString[N*N];
				itoa(count,countString,10);
				string strTemp = "/";
				strTemp = countString + strTemp;
				//cout<<"--"<<strTemp<<"--"<<endl;
				char SSSS_String[N*N];
				itoa(SSSS[i][j],SSSS_String,10);
				strTemp = strTemp + SSSS_String;
				//cout<<"**"<<strTemp<<"**"<<endl;
				
				//中間符號 
				ac_EntropyCoding_MiddleSymbol[index].R_S = strTemp;
				ac_EntropyCoding_MiddleSymbol[index].temp = F_[i][j];
				index++;
				count = 0;//置為0 ,計算下個不為0的數前面0的個數
			}
		}
		if(i<0&&j>=N){//當出現正中間往上時,挪回正規 
			j--;
			i = i+2;	
		}else if(i<0){//當出現往上突出時,挪回正規 
			i++;
		}else if(j>=N){//當出現往右突出時,挪回正規 
			j--;
			i = i+2;
		}
	}
	
	//剩下半個週期的編碼 
	//向左下方向 
	for(;i<N&&j>=0;i++,j--){
		if(F_[i][j]==0){
			count++;
		}else{
			char countString[N*N];
			itoa(count,countString,10);
			string strTemp = "/";
			strTemp = countString + strTemp;
			//cout<<"--"<<strTemp<<"--"<<endl;
			char SSSS_String[N*N];
			itoa(SSSS[i][j],SSSS_String,10);
			strTemp = strTemp + SSSS_String;
			//cout<<"**"<<strTemp<<"**"<<endl;
			
			//中間符號 
			ac_EntropyCoding_MiddleSymbol[index].R_S = strTemp;
			ac_EntropyCoding_MiddleSymbol[index].temp = F_[i][j];
			index++;
			count = 0;//置為0 ,計算下個不為0的數前面0的個數
		}
	}
	if(i>=N){//當出現往下突出時,挪回正規
		i--;
		j = j+2;
	}
	if(F_[i][j]==0){//最後一個點
		count++;
		ac_EntropyCoding_MiddleSymbol[index].R_S = "0/0(EOB)";
		ac_EntropyCoding_MiddleSymbol[index].temp = INT_MAX;
		index++; 
	}else{
		char countString[N*N];
		itoa(count,countString,10);
		string strTemp = "/";
		strTemp = countString + strTemp;
		//cout<<"--"<<strTemp<<"--"<<endl;
		char SSSS_String[N*N];
		itoa(SSSS[i][j],SSSS_String,10);
		strTemp = strTemp + SSSS_String;
		//cout<<"**"<<strTemp<<"**"<<endl;
		
		//中間符號 
		ac_EntropyCoding_MiddleSymbol[index].R_S = strTemp+"(EOB)";
		ac_EntropyCoding_MiddleSymbol[index].temp = F_[i][j];
		index++;
	}
	
	/*測試*/
//	for(int k=0;k<index;k++){
//		cout<<ac_EntropyCoding_MiddleSymbol[k].R_S<<"\t"<<ac_EntropyCoding_MiddleSymbol[k].temp<<endl;
//	}
	
	
	//對中間符號進行符號編碼 
	//對R/S通過查亮度AC碼錶進行熵編碼
	for(int u=0;u<index;u++){
		for(int v=0;v<stringMapList.partNum;v++){
			if(ac_EntropyCoding_MiddleSymbol[u].R_S == stringMapList.stringMap[v].key){
				ac_EntropyCodingStr[u].strTemp1 = stringMapList.stringMap[v].value;
			}
		}
		//對 temp進行轉換成補碼 
		//先將 temp轉換成二進位制串
		if(ac_EntropyCoding_MiddleSymbol[u].R_S!="0/0(EOB)"){
			ac_EntropyCodingStr[u].strTemp = TenToTwo(abs(ac_EntropyCoding_MiddleSymbol[u].temp));
			//轉換成補碼
			if(ac_EntropyCoding_MiddleSymbol[u].temp<0){
				ac_EntropyCodingStr[u].strTemp = ConvertToComplement(ac_EntropyCodingStr[u].strTemp);	
			}
			
			/*測試*/
//			cout<<"**********"<<ac_EntropyCodingStr[u].strTemp<<endl;
		}else{
			ac_EntropyCodingStr[u].strTemp = ""+'\0';
			
			/*測試*/
//			cout<<"**********+"<<ac_EntropyCodingStr[u].strTemp<<endl;
		}
	}
	
	/*測試*/
//	for(int k=0;k<index;k++){
//		cout<<ac_EntropyCodingStr[k].strTemp1<<" "<<ac_EntropyCodingStr[k].strTemp<<endl;
//	}
	return true;
}

int main(){
	cout<<"壓縮編碼過程:"<<endl; 
	/*壓縮編碼*/
	const double PI = acos(-1);
//	double f[N][N]={139,144,149,153,155,155,155,155,
//					144,151,153,156,159,156,156,156,
//					150,155,160,163,158,156,156,156,
//					159,161,162,160,160,159,159,159,
//					159,160,161,162,162,155,155,155,
//					161,161,161,161,160,157,157,157,
//					162,162,161,163,162,157,157,157,
//					162,162,161,161,163,158,158,158};
	double f[N][N];
	double ff[N][N],F[N][N];
	
	/*輸入影象的一個分量樣本*/
	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){
			cin>>f[i][j];
		}
	}
	
	cout<<"源影象的一個分量樣本:"<<endl; 
	/*輸出—源影象的一個分量樣本*/
	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){
			cout<<f[i][j]<<"\t";
		}
		cout<<endl;
	}
	
	//影象的一個分量樣本-128後 
	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){
			ff[i][j] = f[i][j]-128;
		}
	}
	
	cout<<"源影象的一個分量樣本-128後:"<<endl; 
	/*輸出—影象的一個分量樣本-128後*/
	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){
			cout<<ff[i][j]<<"\t";
		}
		cout<<endl;
	}
	
	//由公式計算DCT變化後的係數矩陣
	for(int u=0;u<N;u++){
		for(int v=0;v<N;v++){
			double temp = 0.0;
			for(int i=0;i<N;i++){
				for(int j=0;j<N;j++){
					temp = temp + ff[i][j]*cos((2*i+1)*u*PI*1.0/16)*cos((2*j+1)*v*PI*1.0/16);
				}
			}
			F[u][v] = 1.0/4*(u==0?1.0/sqrt(2):1)*(v==0?1.0/sqrt(2):1)*temp;
		}
	}
	
	/*輸出—DCT變化後的係數矩陣*/
	//DCT變化後的係數矩陣
	cout<<"DCT變化後的係數矩陣:"<<endl;
	for(int u=0;u<N;u++){
		for(int v=0;v<N;v++){
			printf("%.1f\t",F[u][v]);
			//cout<<F[u][v]<<" ";
		}
		cout<<endl;
	}
	
	//利用公式將DCT變化後的係數矩陣轉換為規格化量化係數矩陣 
	int F_[N][N];//規格化量化係數矩陣 
	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){//二維陣列Q 為亮度量化值表 
			F_[i][j] = (int)((F[i][j]/brightnessQuantizedValueTable.Q[i][j])>0.0)?floor((F[i][j]/brightnessQuantizedValueTable.Q[i][j]) + 0.5) : ceil((F[i][j]/brightnessQuantizedValueTable.Q[i][j]) - 0.5);//進行量化,然後進行四捨五入 
		}
	}
	
	/*輸出—規格化量化係數矩陣*/
	//規格化量化係數矩陣 
	cout<<"規格化量化係數:"<<endl;
	for(int u=0;u<N;u++){
		for(int v=0;v<N;v++){
			cout<<F_[u][v]<<"\t";
		}
		cout<<endl;
	}
	 
	//對DC係數生成中間符號(temp1,temp)
	int temp = F_[0][0];
	int temp1;
	EntropyCoding dc_EntropyCodingStr = DC_EntropyCoding(temp,temp1);
	
	cout<<"中間符號:"<<endl; 
	/*輸出—DC係數中間符號*/
	cout<<temp1<<"\t"<<temp<<endl; 
	
	
	int index=0; //AC係數生成中間符號的個數 
	//對AC係數生成中間符號
	AC_EntropyCoding(F_,index);
	
	/*輸出—AC係數中間符號*/
	for(int k=0;k<index;k++){
		cout<<ac_EntropyCoding_MiddleSymbol[k].R_S<<"\t";
		if(ac_EntropyCoding_MiddleSymbol[k].R_S!="0/0(EOB)"){
			cout<<ac_EntropyCoding_MiddleSymbol[k].temp;
		}
		cout<<endl;
	}
	
	cout<<"熵編碼輸出:"<<endl; 
	/*輸出—DC係數熵編碼輸出*/
	cout<<dc_EntropyCodingStr.strTemp1<<"\t"<<dc_EntropyCodingStr.strTemp<<endl;
	
	/*輸出—AC係數熵編碼輸出*/
	for(int k=0;k<index;k++){
		cout<<ac_EntropyCodingStr[k].strTemp1<<"\t"<<ac_EntropyCodingStr[k].strTemp<<endl;
	}
	
	
	cout<<"----------------------------------------------------------------------"<<endl<<endl;
	cout<<"解碼過程:"<<endl; 
	//下面的解碼過程只用到了壓縮過程傳輸過來的熵編碼和熵編碼中AC係數的個數index(也可以通過一個迴圈來計算出這個index) 
	
	cout<<"待解碼的熵編碼:"<<endl;
	/*輸出—DC係數熵編碼輸出*/
	cout<<dc_EntropyCodingStr.strTemp1<<"\t"<<dc_EntropyCodingStr.strTemp<<endl;
	
	/*輸出—AC係數熵編碼輸出*/
	for(int k=0;k<index;k++){
		cout<<ac_EntropyCodingStr[k].strTemp1<<"\t"<<ac_EntropyCodingStr[k].strTemp<<endl;
	}
	
	/*解碼*/
	//將DC係數熵編碼的編碼轉換為中間符號
	//對strTemp1進行反向查詢亮度DC差值碼錶得到temp1
	int Itemp1;
	for(int i=0;i<11;i++){
		if( dc_EntropyCodingStr.strTemp1 == brightnessDC_DifferenceTableList.brightnessDC_DifferenceTable[i]){
			Itemp1 = i;
		}
	}
	//對strTemp進行反向補碼得到temp,可通過查詢規律發現若是負數轉換為補碼後首個數字必為0,正數必不為0 
	int Itemp;
	if(dc_EntropyCodingStr.strTemp[0]=='0'){//為負數,先取反 
		string tempStr = ConvertToComplement(dc_EntropyCodingStr.strTemp);
		//轉換為10進位制
		Itemp = TwoToTen(tempStr);
		//加負號
		Itemp = -Itemp;
	} else{//為正數,直接轉換為10進位制即可 
		Itemp = TwoToTen(dc_EntropyCodingStr.strTemp);
	}
	
	cout<<"中間符號:"<<endl; 
	/*輸出—DC中間符號*/
	cout<<Itemp1<<"\t"<<Itemp<<endl;
	
	
	//將AC係數熵編碼的編碼轉換為中間符號
	AC_EntropyCoding_MiddleSymbol Iac_EntropyCoding_MiddleSymbol[N*N];
	//遍歷所有的AC係數熵編碼的編碼對strTemp1進行反向查詢亮度AC碼錶得到R_S
	for(int i=0;i<index;i++){
		for(int u=0;u<stringMapList.partNum;u++){
			if(ac_EntropyCodingStr[i].strTemp1==stringMapList.stringMap[u].value){
				Iac_EntropyCoding_MiddleSymbol[i].R_S = stringMapList.stringMap[u].key;
			}
		}
		//對strTemp進行反向補碼得到temp,可通過查詢規律發現若是負數轉換為補碼後首個數字必為0,正數必不為0
		if(ac_EntropyCodingStr[i].strTemp[0]=='0'){//為負數,先取反 
			string tempStr = ConvertToComplement(ac_EntropyCodingStr[i].strTemp);
			//轉換為10進位制
			Iac_EntropyCoding_MiddleSymbol[i].temp = TwoToTen(tempStr);
			//加負號
			Iac_EntropyCoding_MiddleSymbol[i].temp = -Iac_EntropyCoding_MiddleSymbol[i].temp;
		} else{//為正數,直接轉換為10進位制即可 
			Iac_EntropyCoding_MiddleSymbol[i].temp = TwoToTen(ac_EntropyCodingStr[i].strTemp);
		}
	}
	
	/*輸出—AC中間符號*/
	for(int i=0;i<index;i++){
		cout<<Iac_EntropyCoding_MiddleSymbol[i].R_S<<"\t";
		if(Iac_EntropyCoding_MiddleSymbol[i].R_S!="0/0(EOB)"){
			cout<<Iac_EntropyCoding_MiddleSymbol[i].temp;
		}
		cout<<endl;
	} 
	
	//規格化量化係數 
	int IF_[N][N];
	
	//初始化矩陣 
	for(int u=0;u<N;u++){
		for(int v=0;v<N;v++){
			IF_[u][v]=0; 
		}
	}
	
	//DC係數
	//還原編碼 
	IF_[0][0] = Itemp;
	//AC係數
	//Z字形還原編碼
	int count;//計算0的個數
	int a=0,b=1; //初始位置
	for(int h=0;h<index;h++){
		//將/前的字串轉換為整數
		count = 0;
		for(int w=0;Iac_EntropyCoding_MiddleSymbol[h].R_S[w]!='/';w++){
			count = count*10 + Iac_EntropyCoding_MiddleSymbol[h].R_S[w]-'0';
		} 
		/*測試*/
//		cout<<"count:"<<count<<endl; 
		
		while(Iac_EntropyCoding_MiddleSymbol[h].R_S!="0/0(EOB)"){
			//根據查詢規律發現,當行+列為奇數時向左下方向,當行+列為偶數時為右上方向 
			if((a+b)%2==0){//偶數,向右上方向 
				for(;count>=0&&a>=0&&b<N;a--,b++){
					if(count==0){//此時放temp 
						IF_[a][b] = Iac_EntropyCoding_MiddleSymbol[h].temp;
						count--;
						break; 
					}else{//此時放0 
						IF_[a][b] = 0;
						count--;
					}
				}
				if(count<0){//向右上移動 
					a--;
					b++;
				}
				if(a<0&&b>=N){//當出現正中間往上時,挪回正規  
					b--;
					a = a+2;
				}else if(a<0){//當出現往上突出時,挪回正規
					a++; 
				}else if(b>=N){//當出現往右突出時,挪回正規 
					b--;
					a = a+2;
				}
				if(count<0){//跳出到第一層迴圈 
					break; 
				}
			} else{//奇數,向左下方向 
				for(;count>=0&&a<N&&b>=0;a++,b--){
					if(count==0){//此時放temp 
						IF_[a][b] = Iac_EntropyCoding_MiddleSymbol[h].temp;
						count--;
						break; 
					}else{//此時放0 
						IF_[a][b] = 0;
						count--;
					}
				}
				if(count<0){//向左下移動 
					a++;
					b--;
				}
				if(a>=N&&b<0){//當出現正中間往下時,挪回正規 
					a--;
					b = b+2;
				}else if(a>=N){//當出現往下突出時,挪回正規 
					a--;
					b = b+2;
				}else if(b<0){//當出現往左突出時,挪回正規
					b++;
				}
				if(count<0){//跳出到第一層迴圈 
					break; 
				}
			}
		}
	}
	
	/*輸出—規格化量化係數矩陣*/
	//規格化量化係數矩陣 
	cout<<"規格化量化係數:"<<endl;
	for(int u=0;u<N;u++){
		for(int v=0;v<N;v++){
			cout<<IF_[u][v]<<"\t";
		}
		cout<<endl;
	}
	
	
	//利用公式將規格化量化係數矩陣轉換為逆量化後的係數矩陣  
	double IF[N][N];//逆量化後的係數矩陣
	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){//二維陣列Q 為亮度量化值表
			IF[i][j] = 1.0*IF_[i][j]*brightnessQuantizedValueTable.Q[i][j];
		}
	}
	
	/*輸出—逆量化後的係數矩陣*/
	cout<<"逆量化後的係數矩陣:"<<endl;
	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){
			cout<<IF[i][j]<<"\t";
		}
		cout<<endl;
	}
	
	//由公式計算IDCT變化後的係數矩陣
	double Iff[N][N];
	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){
			double sum = 0.0;
			for(int u=0;u<N;u++){
				for(int v=0;v<N;v++){
					sum = sum + (u==0?1.0/sqrt(2.0):1.0)*(v==0?1.0/sqrt(2.0):1.0)*IF[u][v]*cos((2*i+1)*u*PI*1.0/16)*cos((2*j+1)*v*PI*1.0/16);	
				}
			}
			Iff[i][j] = 1.0/4*sum;
		}
	}
	
	/*輸出—IDCT變化後的係數矩陣*/
	cout<<"IDCT變化後的係數矩陣:"<<endl;
	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){
			//cout<<Iff[i][j]<<"\t";
			printf("%.0f\t",Iff[i][j]);
		}
		cout<<endl;
	}

	
	cout<<"源影象的一個分量樣本的重構影象:"<<endl; 
	/*IDCT變化後的係數矩陣+128後變成源影象的一個分量樣本的重構影象*/
	double If[N][N]; 
	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){
			If[i][j] = Iff[i][j]+128;
		}
	}
	
	/*輸出—源影象的一個分量樣本的重構影象*/
	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){
			//cout<<If[i][j]<<"\t";
			printf("%.0f\t",If[i][j]);
		}
		cout<<endl;
	}
	return 0;
} 

測試用例(書本P83):