数据压缩作业:JPEG原理分析及JPEG解码器的调试
JPEG 是Joint Photographic Experts Group(聯(lián)合圖像專家小組)的縮寫,是第一個國際圖像壓縮標(biāo)準(zhǔn)。JPEG圖像壓縮算法能夠在提供良好的壓縮性能的同時,具有比較好的重建質(zhì)量,被廣泛應(yīng)用于圖像、視頻處理領(lǐng)域。人們?nèi)粘E龅降?#34;.jpeg"、''.jpg"等指代的是用JPEG算法壓縮出來的靜態(tài)圖片文件在媒體上的封存形式,不能與JPEG壓縮標(biāo)準(zhǔn)混為一談。?
一、實驗內(nèi)容
1、JPEG編解碼原理
JPEG編碼的過程如上圖所示。解碼是編碼的逆過程。?
2、JPEG文件格式
JPEG 在文件中以 Segment 的形式組織,它具有以下特點:
1.均以 0xFF 開始,即表示圖像開始SOI (Start of Image)標(biāo)記,后跟 1 byte 的 Marker 和 2 byte 的 Segment length(包含表示Length 本身所占用的 2 byte,不含“0xFF” + “Marker” 所占用的 2 byte);
2.采用 Motorola 序(相對于 Intel 序),即保存時高位在前,低位在后;
3.Data 部分中,0xFF 后若為 0x00,則跳過此字節(jié)不予處理;
4.一定以0xFFD9結(jié)束,表示圖像結(jié)束EOI(End of Image)標(biāo)記
(1)APPn,數(shù)值0xFF E1~0xFFEF
*N=1~15,數(shù)值對應(yīng)0xE1~0xEF
*APPn長度(Length)
*應(yīng)用細(xì)節(jié)信息(Application specific information)
*EXIF文件格式中多寫入0xFF E1
(2)DQT標(biāo)記段,包括一個或者多個量化表
*量化表長度。長度參數(shù)占用兩個字節(jié),他不包括前兩個字節(jié)0XFF和0XDB。
*量化表數(shù)目。表數(shù)目參數(shù)占用一個字節(jié),其中高4位為量化表的數(shù)據(jù)精確度。若高4位等于0,那么后面的量化表中的每個值占8位;若高4位等于1,那么后面的量化表中每個值占16位,低4位表示量化表的編號,為0~3.
*量化表表項。表項參數(shù)對應(yīng)Z字形排列后的64個數(shù)值。
(3)DHT標(biāo)記段,包括一個或多個霍夫曼表
*霍夫曼碼表的長度。占用兩個字節(jié)。
*每個霍夫曼碼表(霍夫曼碼表一般不止一個,但是絕對不多于4個)都包含4個信息:索引、類型、位表和內(nèi)容編碼。索引信息表示該霍夫曼表的表號,占1個字節(jié)。高四位可以是0或1,為0時指DC所用的霍夫曼表;為1時,指AC所用的霍夫曼表。低4位表示霍夫曼表的編號,值為0或1.位表是一個長為16字節(jié)的編碼,其代碼代數(shù)和為接下來的編碼長度。內(nèi)容編碼信息表示每個霍夫曼碼字對應(yīng)的值
?3、JPEG 的解碼流程
?(1)零偏置(level offset)
對于灰度級是2n的像素,通過減去2n-1,將無符號的整數(shù)值變成有符號數(shù)
對于n=8,即將0~255的值域,通過減去128,轉(zhuǎn)換為值域在-128~127之間的值
目的:使像素的絕對值出現(xiàn)3位10進制的概率大大減少
(2)8*8DCT變換
對每個單獨的彩色圖像分量,把整個分量圖像分成8×8的圖像塊,若邊緣未滿8*8,則用邊緣像素進行填充(不建議用黑或白像素填充的原因是可能會破壞圖像的原有結(jié)構(gòu))。
DCT變換使用下式計算:
?圖像的低頻部分集中在每個8*8塊的左上角,高頻部分集中在右下角。
(3)量化
因為人眼對亮度信號比對色差信號更敏感,因此使用了兩種量化表:亮度量化值和色差量化值;根據(jù)人眼的視覺特性(對低頻敏感,對高頻不太敏感)對低頻分量采取較細(xì)的量化,對高頻分量采取較粗的量化。
(4)DC系數(shù)
8×8圖像塊經(jīng)過DCT變換之后得到的DC直流系數(shù)有兩個特點:系數(shù)的數(shù)值比較大 ,相鄰8×8圖像塊的DC系數(shù)值變化不大——有冗余;對此,JPEG算法使用了差分脈沖調(diào)制編碼(DPCM)技術(shù),對相鄰圖像塊之間量化DC系數(shù)的差值DIFF進行編碼。
(5)AC系數(shù)
由于經(jīng)過DCT變換后,系數(shù)大多集中在左上角,也就是低頻分量區(qū),因此采用Z字形掃描,按頻率的高低順序讀出,這樣會出現(xiàn)很多的連零,可以使用RLE游程編碼,尤其是在最后,如果都是零,直接給出EOB(End of Block)即可
在JPEG編碼中,游程編碼的形式為:(run,level)
表示連續(xù)run個0后有值為level的系數(shù)
run最多15個,用4位表示RRRR
level,類似DC,
????????分成16個類別,用4位SSSS表示類別號,
????????類內(nèi)索引
對(RRRR,SSSS)采用Huffman編碼,
對類內(nèi)索引采用定長編碼
二、實驗步驟
(1)實驗用圖:
SOI和EOI
??
(2)代碼結(jié)構(gòu)體分析
- 結(jié)構(gòu)體struct ?huffman_table——存儲Huffman碼表
- 結(jié)構(gòu)體struct ?component——存儲當(dāng)前像塊中關(guān)于解碼的信息 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_CHECKunsigned int cid; #endif };
- 結(jié)構(gòu)體struct ?jdec_private——存儲圖像寬高、碼表等信息
(3)主要代碼分析
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; #if TRACEp_trace=fopen(TRACEFILE,"w");if (p_trace==NULL){printf("trace file open error!");} #endifif (argc < 3)usage();current_argument = 1;while (1){if (strcmp(argv[current_argument], "--benchmark")==0)benchmark_mode = 1;elsebreak;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;elseexitmessage("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);elseconvert_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); #if TRACEfclose(p_trace); #endifreturn 0; }解碼?
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];/* 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(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; }?tinyjpeg_parse_header——JPEG文件頭解析
int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size) {int ret;/* Identify the file */if ((buf[0] != 0xFF) || (buf[1] != SOI)) //判斷是否是jpeg文件snprintf(error_string, sizeof(error_string),"Not a JPG file ?\n");priv->stream_begin = buf+2;priv->stream_length = size-2;priv->stream_end = priv->stream_begin + priv->stream_length;ret = parse_JFIF(priv, priv->stream_begin); return ret; }static int parse_JFIF——解析marker標(biāo)志
static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream) {int chuck_len;int marker;int sos_marker_found = 0;int dht_marker_found = 0;const unsigned char *next_chunck;/* Parse marker */while (!sos_marker_found){if (*stream++ != 0xff)goto bogus_jpeg_format;/* Skip any padding ff byte (this is normal) */while (*stream == 0xff)stream++;marker = *stream++;chuck_len = be16_to_cpu(stream);next_chunck = stream + chuck_len;switch (marker){case SOF:if (parse_SOF(priv, stream) < 0)return -1;break;case DQT:if (parse_DQT(priv, stream) < 0)return -1;break;case SOS:if (parse_SOS(priv, stream) < 0)return -1;sos_marker_found = 1;break;case DHT:if (parse_DHT(priv, stream) < 0)return -1;dht_marker_found = 1;break;case DRI:if (parse_DRI(priv, stream) < 0)return -1;break;default: #if TRACEfprintf(p_trace,"> Unknown marker %2.2x\n", marker);fflush(p_trace); #endifbreak;}stream = next_chunck;}if (!dht_marker_found) { #if TRACEfprintf(p_trace,"No Huffman table loaded, using the default one\n");fflush(p_trace); #endifbuild_default_huffman_tables(priv);}#ifdef SANITY_CHECKif ( (priv->component_infos[cY].Hfactor < priv->component_infos[cCb].Hfactor)|| (priv->component_infos[cY].Hfactor < priv->component_infos[cCr].Hfactor))snprintf(error_string, sizeof(error_string),"Horizontal sampling factor for Y should be greater than horitontal sampling factor for Cb or Cr\n");if ( (priv->component_infos[cY].Vfactor < priv->component_infos[cCb].Vfactor)|| (priv->component_infos[cY].Vfactor < priv->component_infos[cCr].Vfactor))snprintf(error_string, sizeof(error_string),"Vertical sampling factor for Y should be greater than vertical sampling factor for Cb or Cr\n");if ( (priv->component_infos[cCb].Hfactor!=1) || (priv->component_infos[cCr].Hfactor!=1)|| (priv->component_infos[cCb].Vfactor!=1)|| (priv->component_infos[cCr].Vfactor!=1))snprintf(error_string, sizeof(error_string),"Sampling other than 1x1 for Cr and Cb is not supported"); #endifreturn 0; bogus_jpeg_format: #if TRACEfprintf(p_trace,"Bogus jpeg format\n");fflush(p_trace); #endifreturn -1; }static int parse_DQT——解碼量化表
static int parse_DQT(struct jdec_private *priv, const unsigned char *stream) {int qi;float *table;const unsigned char *dqt_block_end; #if TRACEfprintf(p_trace,"> DQT marker\n");fflush(p_trace); #endifdqt_block_end = stream + be16_to_cpu(stream);stream += 2; /* Skip length */while (stream < dqt_block_end){qi = *stream++; #if SANITY_CHECKif (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); #endiftable = priv->Q_tables[qi];build_quantization_table(table, stream);stream += 64;} #if TRACEfprintf(p_trace,"< DQT marker\n");fflush(p_trace); #endifreturn 0; }static void build_quantization_table——建立量化表
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;const unsigned char *zz2 = zigzag;for (i=0; i<8; i++) {for (j=0; j<8; j++) {*qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j];}}#if TRACEfor (i=0; i<8; i++){for (j=0; j<8; j++){fprintf(p_trace,"%-6d",ref_table[*zz2++]);}fprintf(p_trace,"\n");} #endif }parse_DHT——解碼Huffman碼表,并同時將Huffman碼表寫入trace文件
static int parse_DHT(struct jdec_private *priv, const unsigned char *stream) {unsigned int count, i;unsigned char huff_bits[17];int length, index;length = be16_to_cpu(stream) - 2;stream += 2; /* Skip length */ #if TRACEfprintf(p_trace,"> DHT marker (length=%d)\n", length);fflush(p_trace); #endifwhile (length>0) {index = *stream++;/* We need to calculate the number of bytes 'vals' will takes */huff_bits[0] = 0;count = 0;for (i=1; i<17; i++) {huff_bits[i] = *stream++;count += huff_bits[i];} #if SANITY_CHECKif (count >= HUFFMAN_BITS_SIZE)snprintf(error_string, sizeof(error_string),"No more than %d bytes is allowed to describe a huffman table", HUFFMAN_BITS_SIZE);if ( (index &0xf) >= HUFFMAN_TABLES)snprintf(error_string, sizeof(error_string),"No more than %d Huffman tables is supported (got %d)\n", HUFFMAN_TABLES, index&0xf); #if TRACEfprintf(p_trace,"Huffman table %s[%d] length=%d\n", (index&0xf0)?"AC":"DC", index&0xf, count);fflush(p_trace); #endif #endifif (index & 0xf0 )build_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]);elsebuild_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]);length -= 1;length -= 16;length -= count;stream += count;} #if TRACEfprintf(p_trace,"< DHT marker\n");fflush(p_trace); #endifreturn 0; }tinyjpeg_decode——以mcu為單位進行解碼
int tinyjpeg_decode(struct jdec_private *priv, int pixfmt) {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;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 TRACEfprintf(p_trace,"Bad pixel format\n");fflush(p_trace); #endifreturn -1;}xstride_by_mcu = ystride_by_mcu = 8;if ((priv->component_infos[cY].Hfactor | priv->component_infos[cY].Vfactor) == 1) {decode_MCU = decode_mcu_table[0];convert_to_pixfmt = colorspace_array_conv[0]; #if TRACEfprintf(p_trace,"Use decode 1x1 sampling\n");fflush(p_trace); #endif} else if (priv->component_infos[cY].Hfactor == 1) {decode_MCU = decode_mcu_table[1];convert_to_pixfmt = colorspace_array_conv[1];ystride_by_mcu = 16; #if TRACEfprintf(p_trace,"Use decode 1x2 sampling (not supported)\n");fflush(p_trace); #endif} else if (priv->component_infos[cY].Vfactor == 2) {decode_MCU = decode_mcu_table[3];convert_to_pixfmt = colorspace_array_conv[3];xstride_by_mcu = 16;ystride_by_mcu = 16; #if TRACE fprintf(p_trace,"Use decode 2x2 sampling\n");fflush(p_trace); #endif} else {decode_MCU = decode_mcu_table[2];convert_to_pixfmt = colorspace_array_conv[2];xstride_by_mcu = 16; #if TRACEfprintf(p_trace,"Use decode 2x1 sampling\n");fflush(p_trace); #endif}resync(priv);/* Don't forget to that block can be either 8 or 16 lines */bytes_per_blocklines[0] *= ystride_by_mcu;bytes_per_blocklines[1] *= ystride_by_mcu;bytes_per_blocklines[2] *= ystride_by_mcu;bytes_per_mcu[0] *= xstride_by_mcu/8;bytes_per_mcu[1] *= xstride_by_mcu/8;bytes_per_mcu[2] *= xstride_by_mcu/8;/* Just the decode the image by macroblock (size is 8x8, 8x16, or 16x16) */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;}}}} #if TRACEfprintf(p_trace,"Input file size: %d\n", priv->stream_length+2);fprintf(p_trace,"Input bytes actually read: %d\n", priv->stream - priv->stream_begin + 2);fflush(p_trace); #endifreturn 0; }static void write_yuv——保存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);printf("write yuv begin!\n");//yuv都寫入一個文件snprintf(temp, 1024, "%s.yuv", filename);F = fopen(temp, "wb");fwrite(components[0], width, height, F); //寫Yfwrite(components[1], width * height / 4, 1, F);fwrite(components[2], width * height / 4, 1, F); //寫UVfclose(F); //關(guān)閉文件printf("write yuv done!\n");}三、實驗結(jié)果
打開out_yuv.yuv:
?
前后對比:?
霍夫曼碼表——直流系數(shù)DC
?霍夫曼碼表——交流系數(shù)AC
?
?
輸出DC、AC圖像并統(tǒng)計其概率分布?
更改tinyjpeg_decode:
int tinyjpeg_decode(struct jdec_private *priv, int pixfmt) {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;unsigned char* DCbuf, * ACbuf;unsigned char* uvbuf = 128;int count = 0;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 TRACEfprintf(p_trace,"Bad pixel format\n");fflush(p_trace); #endifreturn -1;}xstride_by_mcu = ystride_by_mcu = 8;if ((priv->component_infos[cY].Hfactor | priv->component_infos[cY].Vfactor) == 1) {decode_MCU = decode_mcu_table[0];convert_to_pixfmt = colorspace_array_conv[0]; #if TRACEfprintf(p_trace,"Use decode 1x1 sampling\n");fflush(p_trace); #endif} else if (priv->component_infos[cY].Hfactor == 1) {decode_MCU = decode_mcu_table[1];convert_to_pixfmt = colorspace_array_conv[1];ystride_by_mcu = 16; #if TRACEfprintf(p_trace,"Use decode 1x2 sampling (not supported)\n");fflush(p_trace); #endif} else if (priv->component_infos[cY].Vfactor == 2) {decode_MCU = decode_mcu_table[3];convert_to_pixfmt = colorspace_array_conv[3];xstride_by_mcu = 16;ystride_by_mcu = 16; #if TRACE fprintf(p_trace,"Use decode 2x2 sampling\n");fflush(p_trace); #endif} else {decode_MCU = decode_mcu_table[2];convert_to_pixfmt = colorspace_array_conv[2];xstride_by_mcu = 16; #if TRACEfprintf(p_trace,"Use decode 2x1 sampling\n");fflush(p_trace); #endif}resync(priv);/* Don't forget to that block can be either 8 or 16 lines */bytes_per_blocklines[0] *= ystride_by_mcu;bytes_per_blocklines[1] *= ystride_by_mcu;bytes_per_blocklines[2] *= ystride_by_mcu;bytes_per_mcu[0] *= xstride_by_mcu/8;bytes_per_mcu[1] *= xstride_by_mcu/8;bytes_per_mcu[2] *= xstride_by_mcu/8;/* Just the decode the image by macroblock (size is 8x8, 8x16, or 16x16) */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);DCbuf = (unsigned char)((priv->component_infos->DCT[0] + 512.0) / 4 + 0.5);ACbuf = (unsigned char)(priv->component_infos->DCT[1] + 128);fwrite(&DCbuf, 1, 1, DCfile);fwrite(&ACbuf, 1, 1, ACfile);count++;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;}}}} #if TRACEfprintf(p_trace,"Input file size: %d\n", priv->stream_length+2);fprintf(p_trace,"Input bytes actually read: %d\n", priv->stream - priv->stream_begin + 2);fflush(p_trace); #endiffor (int j = 0; j < count * 0.25 * 2; j++){fwrite(&uvbuf, sizeof(unsigned char), 1, DCfile);fwrite(&uvbuf, sizeof(unsigned char), 1, ACfile);}return 0; }(在打開YUVviewerPlus時注意:因為原圖是1024×1024,所以輸出的DC、DC圖像的大小為128×128,都是4:2:0采樣)
| 圖像 | 概率分布 |
?
四、實驗總結(jié)
理解了程序設(shè)計的整體框架,明白了JPEG編碼的過程主要是采用量化、離散余弦變換(DCT)以及熵編碼的聯(lián)合編碼方式,來去除數(shù)據(jù)本身的冗余信息和視覺冗余信息。
總結(jié)
以上是生活随笔為你收集整理的数据压缩作业:JPEG原理分析及JPEG解码器的调试的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: dokcer基础命令-详解
- 下一篇: 第十六届“振兴杯”计算机网络管理员赛项理