算术编码、RLE编码(行程长度编码)和词典编码。
有损压缩是指使用压缩后的数据进
行重构,重构后的数据与原来的数据有所不同,但不影响人对原始资料表达的信息造成误解。有损压缩适用于重构信号不一定非要和原始信号完全相同的场合。例
如,图像和声音的压缩就可以采用有损压缩,因为其中包含的数据往往多于我们的视觉系统和听觉系统所能接收的信息,丢掉一些数据而不至于对声音或者图像所表
达的意思产生误解,但可大大提高压缩比。
1. 数据冗余
2. 统计编码——给已知统计信息的符号分配代码的数据无损压缩方法
编码方法: 香农-范诺编码; 霍夫曼编码; 算术编码
2.1也就是编码Si所需要的位数。例如,一幅用256级灰度表示的图像,如果每一个象素点灰度的概率均为Pi=1/256,编码每一个象素点就需要8位。
(3).编码流程
Shannon-Fano的树是根据旨在定义一个有效的代码表的规范而建立的。实际的算法很简单:
- 对于一个给定的符号列表,制定了概率相应的列表或频率计数,使每个符号的相对发生频率是已知。
- 排序根据频率的符号列表,最常出现的符号在左边,最少出现的符号在右边。
- 清单分为两部分,使左边部分的总频率和尽可能接近右边部分的总频率和。
- 该列表的左半边分配二进制数字0,右半边是分配的数字1。这意味着,在第一半符号代都是将所有从0开始,第二半的代码都从1开始。
- 对左、右半部分递归应用步骤3和4,细分群体,并添加位的代码,直到每个符号已成为一个相应的代码树的叶。
示例
这个例子展示了一组字母的香浓编码结构(如图a所示)这五个可被编码的字母有如下出现次数:
-
Symbol A B C D E Count 15 7 6 6 5 Probabilities 0.38461538 0.17948718 0.15384615 0.15384615 0.12820513
从左到右,所有的符号以它们出现的次数划分。在字母B与C之间划定分割线,得到了左右两组,总次数分别为22,17。 这样就把两组的差别降到最小。通过这样的分割, A与B同时拥有了一个以0为开头的码字, C,D,E的码子则为1,如图b所示。 随后, 在树的左半边,于A,B间建立新的分割线,这样A就成为了码字为00的叶子节点,B的码子01。经过四次分割, 得到了一个树形编码。 如下表所示,在最终得到的树中, 拥有最大频率的符号被两位编码, 其他两个频率较低的符号被三位编码。
-
符号 A B C D E 编码 00 01 10 110 111
Entropy(熵,平均码字长度):
1 #include"iostream" 2 #include "queue" 3 #include "map" 4 #include "string" 5 #include "iterator" 6 #include "vector" 7 #include "algorithm" 8 #include "math.h" 9 using namespace std; 10 11 #define NChar 8 //suppose use 8 bits to describe all symbols 12 #define Nsymbols 1<<NChar //can describe 256 symbols totally (include a-z, A-Z) 13 #define INF 1<<31-1 14 15 typedef vector<bool> SF_Code;//8 bit code of one char 16 map<char,SF_Code> SF_Dic; //huffman coding dictionary 17 int Sumvec[Nsymbols]; //record the sum of symbol count after sorting 18 19 class HTree 20 { 21 public : 22 HTree* left; 23 HTree* right; 24 char ch; 25 int weight; 26 27 HTree(){left = right = NULL; weight=0;ch ='\0';} 28 HTree(HTree* l,HTree* r,int w,char c){left = l; right = r; weight=w; ch=c;} 29 ~HTree(){delete left; delete right;} 30 bool Isleaf(){return !left && !right; } 31 }; 32 33 bool comp(const HTree* t1, const HTree* t2)//function for sorting 34 { return (*t1).weight>(*t2).weight; } 35 36 typedef vector<HTree*> TreeVector; 37 TreeVector TreeArr;//record the symbol count array after sorting 38 39 void Optimize_Tree(int a,int b,HTree& root)//find optimal separate point and optimize tree recursively 40 { 41 if(a==b)//build one leaf node 42 { 43 root = *TreeArr[a-1]; 44 return; 45 } 46 else if(b-a==1)//build 2 leaf node 47 { 48 root.left = TreeArr[a-1]; 49 root.right=TreeArr[b-1]; 50 return; 51 } 52 //find optimizing point x 53 int x,minn=INF,curdiff; 54 for(int i=a;i<b;i++)//find the point that minimize the difference between left and right; this can also be implemented by dichotomy 55 { 56 curdiff = Sumvec[i]*2-Sumvec[a-1]-Sumvec[b]; 57 if(abs(curdiff)<minn){ 58 x=i; 59 minn = abs(curdiff); 60 } 61 else break;//because this algorithm has monotonicity 62 } 63 HTree*lc = new HTree; HTree *rc = new HTree; 64 root.left = lc; root.right = rc; 65 Optimize_Tree(a,x,*lc); 66 Optimize_Tree(x+1,b,*rc); 67 } 68 69 HTree* BuildTree(int* freqency)//create the tree use Optimize_Tree 70 { 71 int i; 72 for(i=0;i<Nsymbols;i++)//statistic 73 { 74 if(freqency[i]) 75 TreeArr.push_back(new HTree (NULL,NULL,freqency[i], (char)i)); 76 } 77 sort(TreeArr.begin(), TreeArr.end(), comp); 78 memset(Sumvec,0,sizeof(Sumvec)); 79 for(i=1;i<=TreeArr.size();i++) 80 Sumvec[i] = Sumvec[i-1]+TreeArr[i-1]->weight; 81 HTree* root = new HTree; 82 Optimize_Tree(1,TreeArr.size(),*root); 83 return root; 84 } 85 86 /************************************************************************/ 87 /* Give Shanno Coding to the Shanno Tree 88 /*PS: actually, this generative process is same as Huffman coding 89 /************************************************************************/ 90 void Generate_Coding(HTree* root, SF_Code& curcode) 91 { 92 if(root->Isleaf()) 93 { 94 SF_Dic[root->ch] = curcode; 95 return; 96 } 97 SF_Code lcode = curcode; 98 SF_Code rcode = curcode; 99 lcode.push_back(false); 100 rcode.push_back(true); 101 Generate_Coding(root->left,lcode); 102 Generate_Coding(root->right,rcode); 103 } 104 105 int main() 106 { 107 int freq[Nsymbols] = {0}; 108 char *str = "bbbbbbbccccccaaaaaaaaaaaaaaaeeeeedddddd";//15a,7b,6c,6d,5e 109 110 //statistic character frequency 111 while (*str!='\0') freq[*str++]++; 112 113 //build tree 114 HTree* r = BuildTree(freq); 115 SF_Code nullcode; 116 Generate_Coding(r,nullcode); 117 118 for(map<char,SF_Code>::iterator it = SF_Dic.begin(); it != SF_Dic.end(); it++) { 119 cout<<(*it).first<<'\t'; 120 std::copy(it->second.begin(),it->second.end(),std::ostream_iterator<bool>(cout)); 121 cout<<endl; 122 } 123 }