【Codecs系列】视频编码中常用熵编码介绍

Date: 2017/10/21

Content:视频编码中常用熵编码方法介绍


1、熵编码

  编码过程中按照熵原理不丢失任何信息的编码,即编码过程中不丢失信息量,保存信息熵。

  熵编码是无损压缩的编码方法。

  常见的熵编码方法:香农编码(shannon)、哈夫曼编码(huffman)、算术编码(arithmetic coding)、哥伦布编码(Golomb Codes)、游程编码等。

2、可变长编码(Variable Length Coding,VLC)

  可变长编码通过给出现概率大的符号赋予较短的码字,改变码字长度达到压缩信息冗余的目的,编码和解码过程完全可逆,又称为统计编码和无失真的压缩编码方法。最常用的可变长编码为Huffman、哥伦布编码、游程长度编码。

3、算术编码(Arithmetic coding)

   算术编码的本质是对输入流分配一个码字,而不是为每个符号分配一个码字。算术编码对整条信息(无论多长),其输出仅仅是一个小数,而且是介于0和1之间(半开区间[0,1))的二进制小数。如果算术编码对某条信息的输出为1010001111,那么表示的是小数0.1010001111,换算成十进制即为0.64。

    3.1 编码

   算术编码不是单独对一个码字进行编码,而是对整条信息进行编码。

编码举例:

     考虑某条信息中可能出现的字符仅有a,b,c三种,我们要编码的字符串为bccb。

(1) 假设三者出现概率一

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
以下是一个简单的使用香农编码对图像进行压缩的C语言示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_SYMBOLS 256 typedef struct { unsigned char symbol; int frequency; } Symbol; typedef struct { long long low; long long high; } Range; typedef struct { Symbol symbol_list[MAX_SYMBOLS]; int symbol_count; } FrequencyTable; void init_frequency_table(FrequencyTable* table) { memset(table, 0, sizeof(FrequencyTable)); } void update_frequency_table(FrequencyTable* table, unsigned char* data, int size) { for (int i = 0; i < size; i++) { int found = 0; for (int j = 0; j < table->symbol_count; j++) { if (table->symbol_list[j].symbol == data[i]) { table->symbol_list[j].frequency++; found = 1; break; } } if (!found) { Symbol symbol = { data[i], 1 }; table->symbol_list[table->symbol_count++] = symbol; } } } void sort_frequency_table(FrequencyTable* table) { for (int i = 0; i < table->symbol_count - 1; i++) { for (int j = i + 1; j < table->symbol_count; j++) { if (table->symbol_list[i].frequency < table->symbol_list[j].frequency) { Symbol temp = table->symbol_list[i]; table->symbol_list[i] = table->symbol_list[j]; table->symbol_list[j] = temp; } } } } void build_range_table(FrequencyTable* table, Range* range_list) { long long total_frequency = 0; for (int i = 0; i < table->symbol_count; i++) { total_frequency += table->symbol_list[i].frequency; } long long low = 0; for (int i = 0; i < table->symbol_count; i++) { long long high = low + table->symbol_list[i].frequency * (1LL << 32) / total_frequency; range_list[i].low = low; range_list[i].high = high; low = high; } } void encode_data(unsigned char* data, int size, Range* range_list, FILE* output) { long long low = 0; long long high = (1LL << 32) - 1; for (int i = 0; i < size; i++) { int symbol_index = -1; for (int j = 0; j < MAX_SYMBOLS; j++) { if (range_list[j].low <= low && high < range_list[j].high) { symbol_index = j; break; } } if (symbol_index < 0) { fprintf(stderr, "Error: symbol not found in range table.\n"); exit(1); } Range range = range_list[symbol_index]; long long range_size = high - low + 1; high = low + range_size * range.high / (1LL << 32) - 1; low = low + range_size * range.low / (1LL << 32); while (1) { if ((low ^ high) < (1LL << 31)) { fputc(low >> 31, output); while (fputc(1, output), high_bits > 0) { high_bits--; } low = (low << 1) & ((1LL << 32) - 1); high = ((high << 1) | 1) & ((1LL << 32) - 1); } else if ((low >> 30) == 1 && (high >> 30) == 0) { high_bits++; low = (low << 1) & ((1LL << 32) - 1); high = ((high << 1) | 1) & ((1LL << 32) - 1); } else { break; } } } for (int i = 0; i < 8; i++) { fputc(low >> 31, output); } } void encode_image(char* input_filename, char* output_filename) { FILE* input = fopen(input_filename, "rb"); if (!input) { fprintf(stderr, "Error: failed to open input file.\n"); exit(1); } FILE* output = fopen(output_filename, "wb"); if (!output) { fprintf(stderr, "Error: failed to open output file.\n"); exit(1); } unsigned char buffer[1024]; FrequencyTable table; Range range_list[MAX_SYMBOLS]; init_frequency_table(&table); while (!feof(input)) { int size = fread(buffer, 1, sizeof(buffer), input); update_frequency_table(&table, buffer, size); } sort_frequency_table(&table); build_range_table(&table, range_list); fwrite(&table.symbol_count, sizeof(int), 1, output); for (int i = 0; i < table.symbol_count; i++) { fwrite(&table.symbol_list[i].symbol, sizeof(unsigned char), 1, output); fwrite(&table.symbol_list[i].frequency, sizeof(int), 1, output); } rewind(input); while (!feof(input)) { int size = fread(buffer, 1, sizeof(buffer), input); encode_data(buffer, size, range_list, output); } fclose(input); fclose(output); } int main(int argc, char** argv) { if (argc != 3) { fprintf(stderr, "Usage: %s input_file output_file\n", argv[0]); return 1; } encode_image(argv[1], argv[2]); return 0; } ``` 这个示例程序将输入的图像文件经过香农编码压缩后输出到指定的文件。具体来说,它先对输入数据各个符号的出现频率进行统计,并按照频率从高到低排序,然后根据符号出现频率构建出每个符号的编码范围,最后使用编码范围对输入数据进行编码,并将编码后的数据输出到文件。在解压缩时,只需要使用相同的频率表和编码范围即可还原原始数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞翔的鲲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值