JPEG概述
JPEG( Joint Photographic Experts Group)即联合图像专家组,是用于连续色调静态图像压缩的一种标准,文件后缀名为.jpg或.jpeg,是最常用的图像文件格式。其主要是采用预测编码(DPCM),离散余弦变换(DCT)以及熵编码的联合编码方式,以去除冗余的图像和彩色数据,属于有损压缩格式,它能够将图像压缩在很小的储存空间,一定程度上会造成图像数据的损伤。
JPEG编码原理
JPEG编码的主要步骤为:零电平偏置,DCT变换,量化;对于DC系数来说,进行DPCM+Huffman编码;对于AC系数来说,进行之字形扫描+游程编码+Huffman编码。
实验步骤 :
将输出保存为YUV文件
static void write_yuv(const char *filename, int width, int height, unsigned char **components)
{
FILE *F;
char temp[1024];
snprintf_s(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码表
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];
};
struct component:储存当前8×8像块中有关解码的信息
struct component
{
unsigned int Hfactor; // 水平采样因子
unsigned int Vfactor; // 垂直采样因子
float* Q_table; // 指向该8×8块使用的量化表
struct huffman_table *AC_table; // 指向该块使用的AC Huffman表
struct huffman_table *DC_table; // 指向该块使用的DC Huffman表
short int previous_DC; // 前一个块的直流DCT系数
short int DCT[64]; // DCT系数数组
#if SANITY_CHECK
unsigned int cid;
#endif
};
struct jdec_private:JPEG数据流结构体,用于存储JPEG图像宽高、数据流指针、Huffman码表等内容,并包含struct huffman_table和struct component
struct jdec_private
{
/* Public variables */
uint8_t *components[COMPONENTS]; /* 分别指向YUV三个分量的三个指针 */
unsigned int width, height; /* 图像宽高 */
unsigned int flags;
/* Private variables */
const unsigned char *stream_begin, *stream_end;
unsigned int stream_length;
const unsigned char *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];
};
解码流程
int convert_one_image(const char *infilename, const char *outfilename, int output_format)
{
FILE *fp;
unsigned int length_of_file; // 文件大小
unsigned int width, height; // 图像宽、高
unsigned char *buf; // 缓冲区
struct jdec_private *jdec;
unsigned char *components[3];
/* 将JPEG读入缓冲区 */
fp = fopen(infilename, "rb");
if (fp == NULL)
exitmessage("Cannot open filename\n");
length_of_file = filesize(fp);
buf = (unsigned char *)malloc(length_of_file + 4);
if (buf == NULL)
exitmessage("Not enough memory for loading file\n");
fread(buf, length_of_file, 1, fp);
fclose(fp);
/* Decompress it */
jdec = tinyjpeg_init(); // 初始化
if (jdec == NULL)
exitmessage("Not enough memory to alloc the structure need for decompressing\n");
/* 解析JPEG文件头 */
if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0)
exitmessage(tinyjpeg_get_errorstring(jdec));
/* 计算图像宽高 */
tinyjpeg_get_size(jdec, &width, &height);
snprintf(error_string, sizeof(error_string),"Decoding JPEG image...\n");
if (tinyjpeg_decode(jdec, output_format) < 0) // 解码实际数据
exitmessage(tinyjpeg_get_errorstring(jdec));
/*
* Get address for each plane (not only max 3 planes is supported), and
* depending of the output mode, only some components will be filled
* RGB: 1 plane, YUV420P: 3 planes, GREY: 1 plane
*/
tinyjpeg_get_components(jdec, components);
/* 按照指定的输出格式保存输出文件 */
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;
}
/* Only called this if the buffers were allocated by tinyjpeg_decode() */
tinyjpeg_free(jdec);
/* else called just free(jdec); */
free(buf);
return 0;
}