数据压缩实验五
来源:互联网 发布:软件删除system32 编辑:程序博客网 时间:2024/05/21 14:09
实验原理
jpeg编解码原理
jpeg文件格式
8*8块编码
零偏置
对于灰度级是2^n的像素,通过减去2^n-1,将无符号的整数值变成有符号数,对于n=8,即将0~255的值域,通过减去128,转换为值域在-128~127之间的值。
目的:使像素的绝对值出现3位10进制的概率大大减少。
DCT变换量化
中平型均匀量化,量化步距是按照系数所在的位置颜色分量来确定
因为人眼对亮度信号比对色差信号更敏感,因此使用了两种量化表:亮度量化值和色差量化值。根据人眼的视觉特性(对低频敏感,对高频不太敏感)对低频分量采取较细的量化,对高频分量采取较粗的量化。如果原始图象中细节丰富,则去掉的数据较多,量化后的系数与量化前差别。反之,细节少的原始图象在压缩时去掉的数据少些。
ac游程编码
在JPEG和MPEG编码中规定为:(run, level)表示连续run个0,后面跟值为level的系数如:0,2,0,0,3,0,-4,0,0,0,-6,0,0,5,7 表示为(1, 2), (2, 3) ,...
编码:
Run: 最多15个,用4位表示RRRR
Level:类似DC分成16个类别,用4位表示SSSS表示类别号,类内索引
对(RRRR, SSSS)联合用Huffman编码 对类内索引用定长码编码
ac系数的之字形扫描
DC差分编码
8×8图像块经过DCT变换之后得到的DC直流系数有两个特点:系数的数值比较大、相邻8×8图像块的DC系数值变化不大:冗余
根据这个特点,JPEG算法使用了差分脉冲调制编码(DPCM)技术,对相邻图像块之间量化DC系数的差值 DIFF进行编码:
DIFF=DCk- DCk-1
解码重构
与编码相反::
解码Huffman数据、解码DC差值、重构量化后的系数、DCT逆变换、丢弃填充的行/列、反0偏置、对丢失的CbCr分量差值(下采样的逆过程) YCbCr -》 RGB
实验步骤1.逐步调试JPEG解码器程序。将输入的JPG文件进行解码,将输出文件保存为可供YUVViewer观看的YUV文件。
2. 程序调试过程中,应做到:
理解程序设计的整体框架
理解三个结构体的设计目的
struct huffman_table
struct component
struct jdec_private
理解在视音频编解码调试中TRACE的目的和含义
会打开和关闭TRACE
会根据自己的要求修改TRACE
3.以txt文件输出所有的量化矩阵和所有的HUFFMAN码表。
4. 输出DC图像并经过huffman统计其概率分布(使用第三个实验中的Huffman编码器)。
5. 输出某一个AC值图像并统计其概率分布(使用第三个实验中的Huffman编码器)
实验代码及分析
1、输出一个yuv文件
yuv输出的时候定义部分和yuv420,即分别输出y、u、v、文件的过程基本相同,照此进行修改
//LOADJPEG.C//将三个yuv文件在一个文件中输出static void write_yuv2(const char *filename, int width, int height, unsigned char **components){FILE *F;char temp[1024];snprintf(temp, 1024, "%s.YUV", filename);F = fopen(temp, "wb");fwrite(components[0], width, height, F);fwrite(components[1], width*height / 4, 1, F);fwrite(components[2], width*height / 4, 1, F);fclose(F);}
/* Save it */ switch (output_format) { case TINYJPEG_FMT_RGB24: case TINYJPEG_FMT_BGR24: write_tga(outfilename, output_format, width, height, components); break; case TINYJPEG_FMT_YUV420P: write_yuv(outfilename, width, height, components); break; case TINYJPEG_FMT_GREY: write_pgm(outfilename, width, height, components); break;case TINYJPEG_FMT_YUV:write_yuv2(outfilename, width, height, components);break; }
static void usage(void){ fprintf(stderr, "Usage: loadjpeg [options] <input_filename.jpeg> <format> <output_filename>\n"); fprintf(stderr, "options:\n"); fprintf(stderr, " --benchmark - Convert 1000 times the same image\n"); fprintf(stderr, "format:\n"); fprintf(stderr, " yuv420p - output 3 files .Y,.U,.V\n"); fprintf(stderr, " rgb24 - output a .tga image\n"); fprintf(stderr, " bgr24 - output a .tga image\n"); fprintf(stderr, " gray - output a .pgm image\n");fprintf(stderr, " yuv - output a .yuv image\n"); exit(1);}主函数中
if (strcmp(argv[current_argument+1],"yuv420p")==0) output_format = TINYJPEG_FMT_YUV420P; else if (strcmp(argv[current_argument+1],"rgb24")==0) output_format = TINYJPEG_FMT_RGB24; else if (strcmp(argv[current_argument+1],"bgr24")==0) output_format = TINYJPEG_FMT_BGR24; else if (strcmp(argv[current_argument+1],"grey")==0) output_format = TINYJPEG_FMT_GREY; else if (strcmp(argv[current_argument + 1], "yuv") == 0) output_format = TINYJPEG_FMT_YUV; else exitmessage("Bad format: need to be one of yuv420p, rgb24, bgr24, grey\n"); output_filename = argv[current_argument+2];
//TINYJPEG.Henum tinyjpeg_fmt { TINYJPEG_FMT_GREY = 1, TINYJPEG_FMT_BGR24, TINYJPEG_FMT_RGB24, TINYJPEG_FMT_YUV420P, TINYJPEG_FMT_YUV,};
函数中的内容和YUV420中的相同//TINYJPEG.C case TINYJPEG_FMT_YUV: colorspace_array_conv = convert_colorspace_yuv420p; if (priv->components[0] == NULL) priv->components[0] = (uint8_t *)malloc(priv->width * priv->height); if (priv->components[1] == NULL) priv->components[1] = (uint8_t *)malloc(priv->width * priv->height / 4); if (priv->components[2] == NULL) priv->components[2] = (uint8_t *)malloc(priv->width * priv->height / 4); bytes_per_blocklines[0] = priv->width; bytes_per_blocklines[1] = priv->width / 4; bytes_per_blocklines[2] = priv->width / 4; bytes_per_mcu[0] = 8; bytes_per_mcu[1] = 4; bytes_per_mcu[2] = 4; break;2、结构体分析
component:存放MCU用来作为最小的数据块访问数据,其中Hfactor表示水平取样,Vfactor表示垂直
struct component { unsigned int Hfactor; unsigned int Vfactor; float *Q_table;/* Pointer to the quantisation table to use */ struct huffman_table *AC_table; struct huffman_table *DC_table; short int previous_DC;/* Previous DC coefficient */ short int DCT[64];/* DCT coef */#if SANITY_CHECK unsigned int cid;#endif};
jade_private表示是控制整个文件的变量,在另两个结构体的上层
struct jdec_private{ /* Public variables */ uint8_t *components[COMPONENTS]; unsigned int width, height;/* Size of the image */ unsigned int flags; /* Private variables */ const unsigned char *stream_begin, *stream_end; unsigned int stream_length; const unsigned char *stream;/* Pointer to the current stream */ unsigned int reservoir, nbits_in_reservoir; struct component component_infos[COMPONENTS]; float Q_tables[COMPONENTS][64];/* quantization tables */ struct huffman_table HTDC[HUFFMAN_TABLES];/* DC huffman tables */ struct huffman_table HTAC[HUFFMAN_TABLES];/* AC huffman tables */ int default_huffman_table_initialized; int restart_interval; int restarts_to_go;/* MCUs left in this restart interval */ int last_rst_marker_seen;/* Rst marker is incremented each time */ /* Temp space used after the IDCT to store each components */ uint8_t Y[64*4], Cr[64], Cb[64]; jmp_buf jump_state; /* Internal Pointer use for colorspace conversion, do not modify it !!! */ uint8_t *plane[COMPONENTS];};
huffman_table:用来输出ac和dc系数的huffman表
struct huffman_table{ /* Fast look up table, using HUFFMAN_HASH_NBITS bits we can have directly the symbol, * if the symbol is <0, then we need to look into the tree table */ short int lookup[HUFFMAN_HASH_SIZE]; /* code size: give the number of bits of a symbol is encoded */ unsigned char code_size[HUFFMAN_HASH_SIZE]; /* some place to store value that is not encoded in the lookup table * FIXME: Calculate if 256 value is enough to store all values */ uint16_t slowtable[16-HUFFMAN_HASH_NBITS][256];};
3、trace
trace是用来输出文件中间信息的,想要关闭trace只需要在定义trace的时候也就是在tinyjpeg.h文件中另#define TRACE 0
static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream)
{
int chuck_len;
int marker;
int sos_marker_found = 0;
int dht_marker_found = 0;
const unsigned char *next_chunck;
/* Parse marker */
while (!sos_marker_found)
{
if (*stream++ != 0xff)
goto bogus_jpeg_format;
/* Skip any padding ff byte (this is normal) */
while (*stream == 0xff)
stream++;
marker = *stream++;
chuck_len = be16_to_cpu(stream);
next_chunck = stream + chuck_len;
switch (marker)
{
case SOF:
if (parse_SOF(priv, stream) < 0)
return -1;
break;
case DQT:
if (parse_DQT(priv, stream) < 0)
return -1;
break;
case SOS:
if (parse_SOS(priv, stream) < 0)
return -1;
sos_marker_found = 1;
break;
case DHT:
if (parse_DHT(priv, stream) < 0)
return -1;
dht_marker_found = 1;
break;
case DRI:
if (parse_DRI(priv, stream) < 0)
return -1;
break;
default:
#if TRACE
fprintf(p_trace,"> Unknown marker %2.2x\n", marker);
fflush(p_trace);
#endif
break;
}
stream = next_chunck;
}
if (!dht_marker_found) {
#if TRACE
fprintf(p_trace,"No Huffman table loaded, using the default one\n");
fflush(p_trace);
#endif
build_default_huffman_tables(priv);
}
#ifdef SANITY_CHECK
if ( (priv->component_infos[cY].Hfactor < priv->component_infos[cCb].Hfactor)
|| (priv->component_infos[cY].Hfactor < priv->component_infos[cCr].Hfactor))
snprintf(error_string, sizeof(error_string),"Horizontal sampling factor for Y should be greater than horitontal sampling factor for Cb or Cr\n");
if ( (priv->component_infos[cY].Vfactor < priv->component_infos[cCb].Vfactor)
|| (priv->component_infos[cY].Vfactor < priv->component_infos[cCr].Vfactor))
snprintf(error_string, sizeof(error_string),"Vertical sampling factor for Y should be greater than vertical sampling factor for Cb or Cr\n");
if ( (priv->component_infos[cCb].Hfactor!=1)
|| (priv->component_infos[cCr].Hfactor!=1)
|| (priv->component_infos[cCb].Vfactor!=1)
|| (priv->component_infos[cCr].Vfactor!=1))
snprintf(error_string, sizeof(error_string),"Sampling other than 1x1 for Cr and Cb is not supported");
#endif
return 0;
bogus_jpeg_format:
#if TRACE
fprintf(p_trace,"Bogus jpeg format\n");
fflush(p_trace);
#endif
return -1;
}
首先在tinyjpeg.h文件中定义一个控制huffman码表的变量:tables
#define TABLES 1
函数dht下,输出acdc类别
if (index & 0xf0 ) {#if TABLES fprintf(AC_TABLE, "Huffman table AC[%d] length=%d\n", index & 0xf, count); fflush(AC_TABLE); #endifaqi=0;//控制输出的是ac还是dc build_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]); } else {#if TABLES fprintf(DC_TABLE, "Huffman table DC[%d] length=%d\n", index & 0xf, count); fflush(DC_TABLE); #endif aqi=1; build_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]); }
输出量化表
for(i=0;i<64;i++){ if((!(i%8))) { fprintf(Q_table,"\n%f",table[i]); } else { fprintf(Q_table," %f",table[i]); }} fprintf(Q_table,"\n");
输出码表
fprintf(AC_TABLE,"val=%2.2x code=%8.8x codesize=%2.2d\n",val,code,code_size);#if TABLESif(aqi==0){fflush(AC_TABLE);}else{
#endiffprintf(DC_TABLE,"val=%2.2x code=%8.8x codesize=%2.2d\n",val,code,code_size);fflush(AC_TABLE);}
4、输出ac、dc图像
在tinyjpeg.h文件中添加FILE *AC_table和*DC_table的定义在主函数中开辟空间
char temp[1024];snprintf(temp, 1024, "%sDC.Y", output_filename);
DC_FILE = fopen(temp, "wb");
snprintf(temp, 1024, "%sAC.Y", output_filename);
AC_FILE = fopen(temp, "wb");
//tinyjpeg.c文件 dc分量需要被压缩,写文件的时候是8*8的块所以输出文件大小变为128*128,ac的值比较小,所以加128之后再输出DC[0]=(priv->component_infos->DCT[0]+512.0)/4;DCimage[0]=(unsigned char)(DC[0]+0.5);
fwrite(DCimage,1,1,DC_FILE);ACimage[0]=(unsigned char)(priv->component_infos->DCT[1]+128);fwrite(ACimage,1,1,AC_FILE);
实验结果
- 数据压缩实验五
- 数据压缩实验五:JPEG解码
- 数据压缩实验五:JPEG解码
- 数据压缩实验五:JPEG文件解码实验分析
- 《数据压缩》实验报告五·JPEG编解码
- 数据压缩实验五 JPEG原理分析JPEG解码器的调试
- 数据压缩 实验五 JPEG原理分析 JPEG解码器的调试
- 数据压缩 实验五 JPEG原理分析JPEG解码器的调试
- 数据压缩实验1
- 数据压缩 实验报告一
- 【数据压缩】BMP2YUV实验报告
- 【数据压缩】实验二 BMP2YUV
- 数据压缩实验二:bmp2yuv
- 数据压缩实验2
- 【数据压缩】实验四 DPCM
- 数据压缩实验三
- 数据压缩实验四
- 数据压缩实验六
- eclips添加testNG框架
- 从url中提取域名的几种方法
- 翻转后的棋盘
- Android P2P 连接对话框按键
- JS 图片压缩上传并在iOS中矫正方向
- 数据压缩实验五
- ORACLE RMAN恢复测试脚本
- 【技巧】LESS CSS 框架简介
- 线性代数Eigen库安装使用教程
- 我新开的博客,提醒我现在也是一个做技术的人了。
- Java 线程安全
- leetcode题解-84. Largest Rectangle in Histogram
- Key 与 Value 并发的Cache 设计
- 消息中间件理解总结