一、实验原理
- JPEG编码过程:
YUV图片输入,依次经过零偏置、8x8DCT变换、统一量化,然后分为DC系数和AC系数分别进行编码。DC系数进行差分编码然后进行Huffman编码,AC系数先进行zigzag扫描然后进行游程编码然后进行Huffman编码生成码流。
- JPEG解码过程:
解码Huffman数据,解码DC差值,重构量化后的系数,DCT逆变换,丢弃填充的行/列,反零偏置,对丢失的CbCr分量差值(下采样的逆过程)
JPEG 在文件中以 Segment 的形式组织,它具有以下特点:
1.均以 0xFF 开始,后跟 1 byte 的 Marker 和 2 byte 的 Segment length(包含表示 Length 本身所占用的 2 byte,不含“0xFF” + “Marker” 所占用的 2 byte);
2.采用 Motorola 序(相对于 Intel 序),即保存时高位在前,低位在后;
3. Data 部分中,0xFF 后若为 0x00,则跳过此字节不予处理;
二、实验步骤
1.读取文件
2.解析文件
SOI、APP0、DQT、SOF0、DHT、SOS
3.根据每个分量的水平和垂直采样因子计算最小编码单元的大小,并得到每个最小编码单元内8×8宏块的个数
4.对每个最小编码单元解码
5.解析到EOI结束
6.将Y、Cb、Cr转换为所需的色彩空间保存
三、主要代码
- main函数
int main(int argc, char *argv[])
{
int output_format = TINYJPEG_FMT_YUV420P;
char *output_filename, *input_filename;
clock_t start_time, finish_time;
unsigned int duration;
int current_argument;
int benchmark_mode = 0;
Q_table = fopen("Q_table.txt","w"); //量化表、DC AC表
DC_table = fopen("DC_table.yuv","w");
AC_table = fopen("AC_table.yuv","w");
#if TRACE
p_trace = fopen(TRACEFILE,"w"); //路径文件
if (p_trace == NULL)
{
printf("trace file open error!");
}
#endif
if (argc < 3)
usage();
current_argument = 1;
while (1)
{
if (strcmp(argv[current_argument], "--benchmark")==0)
benchmark_mode = 1;
else
break;
current_argument++;
}
if (argc < current_argument+2)
usage();
input_filename = argv[current_argument];
//设置变换方式
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];
start_time = clock();
if (benchmark_mode)
load_multiple_times(input_filename, output_filename, output_format);
//加载多次
else
convert_one_image(input_filename, output_filename, output_format);
//转换一个图像
finish_time = clock();
duration = finish_time - start_time;
snprintf(error_string, sizeof(error_string),"Decoding finished in %u ticks\n", duration);
fclose(Q_table); //关文件
fclose(DC_table);
fclose(AC_table);
#if TRACE
fclose(p_trace);
#endif
return 0;
}
- 输出量化表
static int parse_DQT(struct jdec_private *priv, const unsigned char *stream)
{
int i;
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);
/***************************************************/
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");
/***************************************************/
stream += 64;
}
#if TRACE
fprintf(p_trace,"< DQT marker\n");
fflush(p_trace);
#endif
return 0;
}
- 输出DC、AC系数
for (y=0; y < priv->height/ystride_by_mcu; y++)
{
//trace("Decoding row %d\n", y);
priv->plane[0] = priv->components[0] + (y * bytes_per_blocklines[0]);
priv->plane[1] = priv->components[1] + (y * bytes_per_blocklines[1]);
priv->plane[2] = priv->components[2] + (y * bytes_per_blocklines[2]);
for (x=0; x < priv->width; x+=xstride_by_mcu)
{
decode_MCU(priv);
convert_to_pixfmt(priv);
priv->plane[0] += bytes_per_mcu[0];
priv->plane[1] += bytes_per_mcu[1];
priv->plane[2] += bytes_per_mcu[2];
if (priv->restarts_to_go>0)
{
priv->restarts_to_go--;
if (priv->restarts_to_go == 0)
{
priv->stream -= (priv->nbits_in_reservoir/8);
resync(priv);
if (find_next_rst_marker(priv) < 0)
return -1;
}
}
DC[0]=(priv->component_infos->DCT[0]+512.0)/4;
DCimage[0]=(unsigned char)(DC[0]+0.5);
fwrite(DCimage,1,1,DC_table);
//按块写DC系数
ACimage[0]=(unsigned char)(priv->component_infos->DCT[1]+128);
fwrite(ACimage,1,1,AC_table);
//按块写AC系数
}
}
四、实验结果
原图:
输出的trace文件
输出的量化表
输出的DC图像
输出的AC图像
555555编程真的好难啊 为什么方向一的孩子还要受这个苦 真的好痛苦啊编程呜呜呜呜