《数据压缩》实验报告五·JPEG编解码
一.JPEG编解码实验原理
JPEG是第一个国际图像压缩标准,用于连续色调静态图像(即包括灰度图像和彩色图像)。JPEG是联合图像专家组(Joint Photographic Experts Group)的缩写,这个图像压缩标准是国际电信联盟(International Telecommunication Union,ITU)、国际标准化组织(International Organization for Standardization,ISO)和国际电工委员会(International Electrotechnical Commission,IEC)合作努力的成果。JPEG标准正式地称为ISO/IEC IS(国际标准)10918-1:连续色调静态图像数字压缩和编码(Digital Compression and Coding of Continuous-tone Still Images)和ITU-T建议T.81。这个标准目的在于支持用于大多数连续色调静态图像压缩的各种各样的应用,这些图像可以是任何一个色彩空间,用户可以调整压缩比,并能达到或者接近技术领域中领先的压缩性能,且具有良好的重建质量。这个标准的另一个目标是对普遍实际的应用提供易处理的计算复杂度。
JPEG编码算法主要有以下一个重要步骤:
(1)对DCT去除图像数据的空间冗余;
(2)用人眼视觉最佳效果的量化表来量化DCT系数F(u,v),去除视觉冗余;
(3)对量化后的DCT系数F(u,v)数据进行熵编码,去除熵冗余。
二.实验步骤
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编码器)。
三.实验代码
①输出YUV文件
只要把原代码改成以下代码,即可实现输出yuv文件
snprintf(temp, 1024, "%s.yuv", filename);
F = fopen(temp, "ab");
fwrite(components[0], width, height, F);
fclose(F);
snprintf(temp, 1024, "%s.yuv", filename);
F = fopen(temp, "ab");
fwrite(components[1], width*height/4, 1, F);
fclose(F);
snprintf(temp, 1024, "%s.yuv", filename);
F = fopen(temp, "ab");
fwrite(components[2], width*height/4, 1, F);
fclose(F);
②输出量化表
tinyjpeg.c中
extern FILE* lhbfp;
static void build_quantization_table(float *qtable, const unsigned char *ref_table)
{
int i, j;
static const double aanscalefactor[8] = {
1.0, 1.387039845, 1.306562965, 1.175875602,
1.0, 0.785694958, 0.541196100, 0.275899379
};
const unsigned char *zz = zigzag;
for (i=0; i<8; i++) {
for (j=0; j<8; j++) {
//add by ininw
fprintf(lhbfp,"%d",ref_table[zigzag[i*8+j]]); fprintf(lhbfp, "\t\n");
if (j == 7)//一行显示8个值
fprintf(lhbfp, "\r\n");
*qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j];
}
}
fprintf(lhbfp, "\r\n");
fprintf(lhbfp, "\r\n");
fprintf(lhbfp, "\r\n");
}
在loadjpeg.c中添加
FILE* lhbfp=NULL;
int main(int argc, char *argv[])
{
……
char* LHBFileName = NULL;
LHBFileName = argv[4];
lhbfp = fopen(LHBFileName, "wb");
……
fclose(lhbfp);
}
③在loadjpeg.c中做以下更改
外部定义变量
FILE *DC_table;
FILE *AC_table;
float *DC=NULL;
unsigned char *DCimage=NULL;
unsigned char *ACimage=NULL;
在main函数中添加
DCFileName = argv[5];
DC_table=fopen(DCFileName,"wb");
ACFileName = argv[6];
AC_table=fopen(ACFileName,"wb");
DC = (float*)malloc(1024 * 1024);
DCimage=(unsigned char *)malloc(1024 * 1024);
ACimage=(unsigned char*)malloc(1024 * 1024);
……
fclose(DC_table);
fclose(AC_table);
free(DC);
free(DCimage);
free(ACimage);
在tinyjpeg.c中
引用外部变量
extern FILE *DC_table;
extern FILE *AC_table;
extern float *DC;
extern unsigned char *DCimage;
extern unsigned char *ACimage;
并且在下面的函数中添加代码
int tinyjpeg_decode(struct jdec_private *priv, int pixfmt)
{
for (y=0; y < priv->height/ystride_by_mcu; y++)
{
......
for (x=0; x < priv->width; x+=xstride_by_mcu)
{
......
DC[0]=(priv->component_infos->DCT[0]+512.0)/4;//直流系数在-512~512之间,因此先抬高512再除以4变到0~255范围,以便显示
DCimage[0]=(unsigned char)(DC[0]+0.5);//四舍五入,数组DCimage[]为unsigned char型
fwrite(DCimage,1,1,DC_table);//每循环一个块写入一个数
ACimage[0]=(unsigned char)(priv->component_infos->DCT[3]+128);//任一交流系数DCT[i],i取1~63,交流系数都集中在0左右,有正有负,所以将电平抬高128,显示输出
fwrite(ACimage,1,1,AC_table);//每循环一个块写入一个数
}
}
}
四.实验结果
①输出YUV文件
②输出量化表
对照文件数据中的量化表(之字形扫描)
输出的Huffman表(省略一部分没有截图)
③输出的DC,AC图像
DC | ||
AC1 | ||
AC2 |
上一篇: structured streaming 入门级初使用(一)
下一篇: 阿里云ossutil