实验五-jpg解码
来源:互联网 发布:锋利的jquery源码 编辑:程序博客网 时间:2024/05/17 22:53
一、实验原理
1.jpg编码
JPEG(Joint Photographic Experts Group),文件后缀名为.jpg,.jpeg,是一种常用的图像文件格式。采用有损压缩方式去除冗余的图像和彩色数据,在获得极高压缩率的同时能展现十分丰富生动的图像。
编码过程如图示:
解码为编码的逆过程。
2.jpg文件格式
jpeg文件以Segment的形式组织,均以0xFF开始,后面跟1字节的Marker和2字节的Segment Length(包含Length本身长度,不包括Marker和0xFF)。
常用的Marker有:
1)SOI(start of image)0xFFDB
所有的jpeg文件必须以SOI开始。
2)APPn(reserved for application use)0xFFE0-0xFFEF
eg:FFE0 运用程序保留标记0
FF E0 00 10 4A 46 49 46 00 01 01 01 00 48 00 48 00 00
length 2byte:0X0010=16
标识符:4A 46 49 46 00 –JFIF
Version 2byte:0101
Units 1byte:01 –X,Y are dots per inch
Xdensity 2byte:0x0048 –水平方向点密度
Ydensity 2byte:0x0048 –垂直方向点密度
缩略图水平像素数目 1byte :0x00
缩略图垂直像素数目 1byte :0x00
缩略图24bitRGB 数据:没有缩略图
3)DQT(Define Quantization Table) 0xFFDB
length 2byte:0x 00 43
QT信息 1byte 0-3位:QT号(0-3,可能有4张量化表,亮度,色度,可能会有rgb各一张量化表) 4-7位:QT精度(0:8bit,1:16bit)
QT实际数据:nbyte n=64*QT精度的字节数。(对于8*8的宏块来说,共有8*8=64个量化系数)
需要注意的是,jpeg文件中的量化表是按之字形扫描的格式存的,要得到真正的量化表还需要反之字形扫描;
static const unsigned char zigzag[64] = { 0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63};static void build_quantization_table(float *qtable, const unsigned char *ref_table){ /* Taken from libjpeg. Copyright Independent JPEG Group's LLM idct. * For float AA&N IDCT method, divisors are equal to quantization * coefficients scaled by scalefactor[row]*scalefactor[col], where * scalefactor[0] = 1 * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 * We apply a further scale factor of 8. * What's actually stored is 1/divisor so that the inner loop can * use a multiplication rather than a division. */ 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++) { *qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j]; } }}
解析到的量化表为
4)SOF(start of Frame)0xFFC0
eg:FF C0 00 11 08 0F C0 0B D0 03 01 22 00 02 11 01 03 11 01
length 2byte :0x11—17byte
图像精度(每个数据样本的位数)1byte:0x08
图像高度 2byte:0x0FC0=4032
图像宽度 2byte : 0X0BD0=3024
颜色分量数 1byte:03(ycrcb)
颜色分量id 1byte:01—-y
采样率 1byte :4-7位水平采样率:2 0-3位垂直采样率:2
量化表号 1byte:00
颜色分量id 1byte:02—-U
采样率 1byte :位水平采样率:1 垂直采样率:1
量化表号 1byte:01
颜色分量id 1byte:03—–V
采样率 1byte :水平采样率:1 垂直采样率:1
量化表号 1byte:01
5)DHT,define Huffman Table 0xFFC4
length 2byte:0x001f—31byte
huffman表信息 1byte:4-7位huffman表类型(0:Dc,1:Ac):0
0-3位huffman表id:0
huffmanTableIndex:16byte 1-16位码长的码字各有多少个
huffman权值信息:nbyte(n为huffmanTableIndex的和,表示每个码字的权值)
6)SOS(start of Scan)0xFFDA
eg:FF DA 00 0C 03 01 00 02 11 03 11 03 3F 00
length 2byte:0x000c—12
颜色分量数 1byte:0x03 –和SOF中的颜色分量数相同
颜色分量信息 6byte:每个颜色分量占2byte
颜色分量id 1byte:0x01
颜色分量使用的huffman编号:0-3位直流分量使用的表号;4-7位交流分量使用的表号
y: 01 dc–0 ac–0
cb:02 dc–1 ac–1
cr: 03 dc–1 ac–1
压缩图像数据 3byte:
谱选择开始 1byte 固定值0x00
谱选择结束 1byte 固定值0x3f
谱选择 1byte 在基本jpeg中总为00
7)EOI end of image 0xFFD9
结束符,jpeg文件中固定为EOI。
3.解码数据结构
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};
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]; //add by zhn int tempY[4]; int tempU,tempV; //end add};
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];};
4.typedef指向函数的用法
typedef void (*decode_MCU_fct) (struct jdec_private *priv);
decode_MCU_fct decode_MCU;
decode_MCU=decode_MCU_2x2_1plane;
decode_MCU(priv);
decode_MCU_fct是一个函数指针,用它来声明的decode_MCU也是一个函数指针,并用它指向decode_MCU_2x2_1plane函数,传入参数即可调用。
二、实验步骤
1)读取文件;
2)解析Segment Marker;
3)根据每个分量的水平和垂直采样因子计算MCU的大小,得到每个MCU中宏块的个数;
4)对每个MCU解码,知道解析到EOI,解码结束;
5)将y,cb,cr转化为需要的彩色空间并保存。
三、关键代码分析
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]; //add by zhn unsigned char *yBuffer; unsigned char *uBuffer; unsigned char *vBuffer; //end add /* Load the Jpeg into memory */ 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"); if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0) exitmessage(tinyjpeg_get_errorstring(jdec)); /* Get the size of the image */ 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); /* 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_onefile(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;}
int tinyjpeg_decode(struct jdec_private *priv, int pixfmt)//add by zhn outdctY{ unsigned int x, y, xstride_by_mcu, ystride_by_mcu; unsigned int bytes_per_blocklines[3], bytes_per_mcu[3]; decode_MCU_fct decode_MCU; const decode_MCU_fct *decode_mcu_table; const convert_colorspace_fct *colorspace_array_conv; convert_colorspace_fct convert_to_pixfmt; //add by zhn unsigned char *yBuffer; unsigned char *uBuffer; unsigned char *vBuffer; int *yB,*uB,*vB; int *ytemp,*utemp,*vtemp; int dcSize,i,j; FILE *O,*D; int debug=1; int count[256],countBefore[256]; int Q_table[3][64]; int MaxY,MaxU,MaxV; memset(count,0,256*sizeof(int)); memset(countBefore,0,256*sizeof(int)); //end add if (setjmp(priv->jump_state)) return -1; /* To keep gcc happy initialize some array */ bytes_per_mcu[1] = 0; bytes_per_mcu[2] = 0; bytes_per_blocklines[1] = 0; bytes_per_blocklines[2] = 0; decode_mcu_table = decode_mcu_3comp_table; switch (pixfmt) { case TINYJPEG_FMT_YUV420P: 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; case TINYJPEG_FMT_RGB24: colorspace_array_conv = convert_colorspace_rgb24; if (priv->components[0] == NULL) priv->components[0] = (uint8_t *)malloc(priv->width * priv->height * 3); bytes_per_blocklines[0] = priv->width * 3; bytes_per_mcu[0] = 3*8; break; case TINYJPEG_FMT_BGR24: colorspace_array_conv = convert_colorspace_bgr24; if (priv->components[0] == NULL) priv->components[0] = (uint8_t *)malloc(priv->width * priv->height * 3); bytes_per_blocklines[0] = priv->width * 3; bytes_per_mcu[0] = 3*8; break; case TINYJPEG_FMT_GREY: decode_mcu_table = decode_mcu_1comp_table; colorspace_array_conv = convert_colorspace_grey; if (priv->components[0] == NULL) priv->components[0] = (uint8_t *)malloc(priv->width * priv->height); bytes_per_blocklines[0] = priv->width; bytes_per_mcu[0] = 8; break; default:#if TRACE fprintf(p_trace,"Bad pixel format\n"); fflush(p_trace);#endif return -1; }
四、实验结果分析
static void write_yuv_onefile(const char *filename, int width, int height, unsigned char **components){ FILE *F; F = fopen(filename, "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);}
/* * Decode a 2x2 * .-------. * | 1 | 2 | * |---+---| * | 3 | 4 | * `-------' */static void decode_MCU_2x2_3planes(struct jdec_private *priv){ int i; // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 16); //add by zhn priv->tempY[0]=priv->component_infos[cY].DCT[4]; //end add process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+8, 16); //add by zhn priv->tempY[1]=priv->component_infos[cY].DCT[4];#if debug_dct for(i=0;i<64;i++) { if(priv->component_infos[cY].DCT[i]>=255) printf("%4d",priv->component_infos[cY].DCT[i]); }#endif //end add process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+64*2, 16); //add by zhn priv->tempY[2]=priv->component_infos[cY].DCT[4]; //end add process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16); //add by zhn priv->tempY[3]=priv->component_infos[cY].DCT[4]; //end add // Cb process_Huffman_data_unit(priv, cCb); IDCT(&priv->component_infos[cCb], priv->Cb, 8); //add by zhn#if debug_dct for(i=0;i<64;i++) { if(priv->component_infos[cCb].DCT[i]>=255) printf("%4d",priv->component_infos[cCb].DCT[i]); }#endif priv->tempU=priv->component_infos[cCb].DCT[4]; //end add // Cr process_Huffman_data_unit(priv, cCr); IDCT(&priv->component_infos[cCr], priv->Cr, 8); //add by zhn#if debug_dct for(i=0;i<64;i++) { if(priv->component_infos[cCr].DCT[i]>=255) printf("%4d",priv->component_infos[cCr].DCT[i]); }#endif priv->tempV=priv->component_infos[cCr].DCT[4]; //end add}
原始图像
dc系数图像
dc概率分布
ac系数1的概率分布
ac系数3的概率分布
五、实验结论分析
dct的物理意义是将用各频率分量的组合来表示原图像,它的各个系数就表示该频率分量的大小。一张图片的dc系数与原图像的概率分布近似,而ac系数则服从拉普拉斯分布,且频率越高,分布越集中。
附录代码链接
http://download.csdn.net/detail/qq_35473884/9857990
- 实验五-jpg解码
- 【实验五】JPEG解码
- 实验五:JPEG解码
- 实验五 JPEG解码
- 数据压缩实验五:JPEG解码
- 数据压缩实验五:JPEG解码
- 实验五——JPEG编解码
- 数据压缩实验五:JPEG文件解码实验分析
- jpg图片解码
- 《数据压缩》实验报告五·JPEG编解码
- JPG解码库的应用
- JPG文件编解码详解
- jpg图像的编解码
- Android jpg图像解码崩溃
- ffmpeg解码JPG和PNG等图片
- ffmpeg解码jpg并编码成h264
- ffmpeg解码JPG和PNG等图片
- ffmpeg解码jpg并编码成h264
- visualVM远程监控tomcat
- hive1.2.1安装
- 运算符涉及到的数据类型转换问题
- 【OpenCV】SURF算法之视频图像实时特征点匹配
- ios单元测试&UI测试
- 实验五-jpg解码
- ListView的item展开后完整显示
- Java多线程(四)- 协调同步线程
- LedHAL实例架构分析(Led字符型驱动)
- Python中批量改名
- DevExpress学习系列(控件篇):GridControl的基本应用
- 机房重构--视图的应用
- [usaco]Friday the Thirteenth题解
- 《荒野求生》告诉我们的