JPEG原理分析及JPEG解码器的调试

一、实验原理

JPEG编码框架
在这里插入图片描述
上图为编码过程,解码是编码的逆过程
1.零偏置Level offset
将灰度级为2n的像素,减去2n-1,此时将无符号数值变为有符号数,对于本实验,n=8,即每个像素的灰度减128
2.88DCT变换
首先将图像分为8
8的若干块,以方便进行DCT变换;
DCT变换的作用为能量集中和去相关。DCT变换后多数低频信息集中在左上角,且数值较大
3.量化
由于人眼对低频更加敏感,故只需要对左上角的低频部分进行细量化,高频部分进行粗量化
人眼对亮度信号更加敏感,对色度信号不敏感,所以亮度与色度分量分别采取不同的量化表,以在保证图像质量的前提下,提高压缩比;
4.编码
DC系数:差分编码
由于直流系数 F(0,0)反映了该子图像中包含的直流成分,通常较大,又由于两个相邻的子图像的直流系数通常具有较大的相关性,所以对 DC 系数采用差值脉冲编码(DPCM),即对本像素块直流系数与前一像素块直流系数的差值进行无损编码。
编码方法:
码字由两部分组成:类别ID+类内索引
将每一个DIFF经查下表,判断出在哪一个范围内,记下类别ID,作为码字的第一部分,DIFF的真值作为码字的第二部分。
在这里插入图片描述
AC系数:游程编码
首先,进行游程编码(RLC),并在最后加上块结束码(EOB);然后,系数序列分组,将非零系数和它前面的相邻的全部零系数分在一组内;每组用两个符号表示[(Run,Size),(Amplitude)]
Amplitude:表示非零系数的幅度值;Run:表示零的游程即零的个数;Size:表示非零系数的幅度值的编码位数;

JPEG文件格式
SOI,Start of Image,图像开始
APP0,Application,应用程序保留标记0
DQT,Define Quantization Table,定义量化表
SOF0,Start of Frame,帧图像开始
DHT,Define Huffman Table,定义哈夫曼表
SOS,Start of Scan,扫描开始 12字节
EOI,End of Image,图像结束 2字节

Segment 的组织形式
JPEG 在文件中以 Segment 的形式组织,它具有以下特点:
均以 0xFF 开始,后跟 1 byte 的 Marker 和 2 byte 的 Segment length(包含表示Length 本身所占用的 2 byte,不含“0xFF” + “Marker” 所占用的 2 byte);
采用 Motorola 序(相对于 Intel 序),即保存时高位在前,低位在后;
Data 部分中,0xFF 后若为 0x00,则跳过此字节不予处理;

JPEG 的 Segment Marker
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

JPEG解码流程
1 读取文件
2 解析 Segment Marker
    2.1 解析 SOI
    2.2 解析 APP0
        检查标识“JFIF”及版本
        得到一些参数
    2.3 解析 DQT
         得到量化表长度(可能包含多张量化表)
         得到量化表的精度
         得到及检查量化表的序号(只能是 0 —— 3)
         得到量化表内容(64 个数据)
    2.4 解析 SOF0
         得到每个 sample 的比特数、长宽、颜色分量数
         得到每个颜色分量的 ID、水平采样因子、垂直采样因子、使用的量化表序号(与 DQT 中序号对应)
    2.5 解析 DHT
          得到 Huffman 表的类型(AC、DC)、序号
          依据数据重建 Huffman 表
    2.6 解析 SOS
          得到解析每个颜色分量的 DC、AC 值所使用的 Huffman 表序号(与 DHT中序号对应)
3 依据每个分量的水平、垂直采样因子计算 MCU 的大小,并得到每个 MCU 中 8*8宏块的个数
4 对每个 MCU 解码(依照各分量水平、垂直采样因子对 MCU 中每个分量宏块解码)
    4.1 对每个宏块进行 Huffman 解码,得到 DCT 系数
    4.2 对每个宏块的 DCT 系数进行 IDCT,得到 Y、Cb、Cr
    4.3 遇到 Segment Marker RST 时,清空之前的 DC DCT 系数
5 解析到 EOI,解码结束
6 将 Y、Cb、Cr 转化为需要的色彩空间并保存。

二、实验代码

任务一:yuv文件输出

static void write_yuv(const char *filename, int width, int height, unsigned char **components)
{
   
  FILE *F;
  char temp[1024];

  snprintf(temp, 1024, "%s.Y", filename);
  F = fopen(temp, "wb");
  fwrite(components[0], width, height, F);
  fclose(F);
  snprintf(temp, 1024, "%s.U", filename);
  F = fopen(temp, "wb");
  fwrite(components[1], width*height/4, 1, F);
  fclose(F);
  snprintf(temp, 1024, "%s.V", filename);
  F = fopen(temp, "wb");
  fwrite(components[2], width*height/4, 1, F);
  fclose(F);
  //写入yuv输出文件
  snprintf(temp, 1024, "%s.yuv", filename);
  fopen_s(&F, 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);
}

任务二:理解代码

struct huffman_table :用来存放huffman解码后的DC、AC系数
struct component :用来存放IDCT反变化后的颜色分量
struct jdec_private :用来统筹整个解码过程,包括huffman_table,component

TRACE的目的主要是输出中间过程中的某些变量,或者错误信息。
TRACE随着文件的解析,输出中间信息,输出到txt文件。

在main中,以下代码用来打开trace文件:

#if TRACE
  p_trace=fopen(TRACEFILE,"w");//p_trace是追踪文件
  if (p_trace==NULL)
  {
   
	  printf("trace file open error!");
  }
#endif

关闭trace

#if TABLES 
  fclose(hufftable);
#endif

任务三:以txt文件输出所有的量化矩阵和所有的HUFFMAN码表
量化表:
修改parce_DQT

static int parse_DQT(struct jdec_private *priv, const unsigned char *stream)
{
   
  int qi;
  float *table;
  const unsigned char *dqt_block_end;
#if TRACE
  fprintf(p_trace,"> DQT marker\n");
  fflush(p_trace);
#endif
  dqt_block_end = stream + be16_to_cpu(stream);
  //得到量化表长度(可能包含多张量化表)
  stream += 2;	/* Skip length */

  while (stream < dqt_block_end)//检查是否还有表
   {
   
     qi = *stream++;
#if SANITY_CHECK
     if (qi>>4)
		 //得到量化表的精度(高四位)
       snprintf(error_string, sizeof(error_string),"16 bits quantization table is not supported\n");
     if (qi>4)
		 //得到量化表序号(低四位)
       snprintf(error_string, sizeof(error_string),"No more 4 quantization table is supported (got %d)\n", qi);
#endif
     table = priv->Q_tables[qi];
	 //得到量化表内容
     build_quantization_table(table, stream);
	 //输出量化表
	 FILE *quanty = fopen("quantification.txt", "a");
	 if (quanty == NULL)
	 {
   
		 printf("Fail to open quantification.txt\n");
		 return 0;
	 }
	 fprintf(quanty,"\n量化表\n")
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值