精华内容
下载资源
问答
  • 纯C#实现的JPEG解码器核心算法,纯代码,不包含图片的展示,需要自己写窗体程序并构建Bitmap来显示图片。
  • STM32F407 JPEG解码.zip

    2019-08-15 20:13:27
    基于正点原子的STM32F407探索者开发板,直接解码JPG图片生成的数据,数据保存在内部FLASH里。
  • JPEG解码类 C++

    2015-11-29 16:21:25
    这是我自己编写的JPEG解码类,解码速度不是太快,只支持baseline类型JPEG解码,可以帮助初学者了解JPEG解码流程。本人水平有限,望批评指正,共同学习。赚积分不容易,望搬运工放过小的,在此谢过,跪谢。
  • jpeg解码过程

    2014-11-14 13:43:13
    jpeg解码过程,比较详细的介绍了图像解码的原理,有详细的代码
  • 开源的JPEG格式图片解码C语言程序库,其中包含已移植的avr,pic单片机版本以及原始的VC版本。本人亲测,移植到stm32f103单片机中,正常使用,效果非常...主流的jpeg解码程序库无法正常解码。使用该程序库后可正常解码。
  • JPEG解码

    千次阅读 2018-05-29 17:47:28
    一、JPEG编码原理1.原理框图2.各个步骤【零偏置(Level offset)】将无符号的数变为有符号的数,使得出现大数的概率减小【DCT变换】将时域上的转变为频域上的,低频的集中在左上角,高频的在右下角,这样大部分的数据...

    一、JPEG编码原理

    1.原理框图


    2.各个步骤

    【零偏置(Level offset)】

    将无符号的数变为有符号的数,使得出现大数的概率减小

    【DCT变换】

    将时域上的转变为频域上的,低频的集中在左上角,高频的在右下角,这样大部分的数据基本在左上角

    【量化】

    低频数据多且人眼敏感,细量化,高频数据少不敏感,粗量化;同理,根据人眼对亮度敏感高于色度的原理,亮度细量化,色度粗量化;

    【之字形扫描(Zig_zag scan)】:使非零的数集中在前面,后面的连0用EOB表示

    【编码】

    DC 系数编码: 由于直流系数 F(0,0)反映了该子图像中包含的直流成分,通常较大,又由 于两个相邻的子图像的直流系数通常具有较大的相关性,所以对 DC 系数采用 差值脉冲编码(DPCM),即对本像素块直流系数与前一像素块直流系数的差 值进行无损编码。

      AC 系数编码: 首先,进行游程编码(RLC),并在最后加上块结束码(EOB);然后,系 数序列分组,将非零系数和它前面的相邻的全部零系数分在一组内;每组用两 个符号表示[(Run,Size),(Amplitude)] Amplitude:表示非零系数的幅度值;Run:表示零的游程即零的个数;Size: 表示非零系数的幅度值的编码位数

    二、JPEG解码原理

    1.主要流程


    2.文件格式

    2.1

    Segment 的组织形式 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,则跳过此字节不予处理

    2.2JPEG的Segment Marker




    三、代码分析

    3.1

    主函数里面,通过benchmark_mode看是单个图像转换还是多次转换


    3.2

    tinyjpeg_parse_header解析头函数

    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))//segment marker文件开始一定是0XFF
        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);//解析JFIF
    
      return ret;
    }

    在parse_JFIF中依次解析了各个标志

    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:
            .......
    }

    3.3tinyjpeg_decode解码中

    依据每个分量的水平、垂直采样因子计算 MCU 的大小,并得到每个 MCU 中 8*8 宏块的个数 

    int tinyjpeg_decode(struct jdec_private *priv, int pixfmt)
    {
      ...
      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 TRACE
         fprintf(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 TRACE
         fprintf(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 TRACE
         fprintf(p_trace,"Use decode 2x1 sampling\n");
    	 fflush(p_trace);
    #endif
      }
    
    
    

    3.4 

    对每个 MCU 解码(依照各分量水平、垂直采样因子对 MCU 中每个分量宏块解 码) 

    .对每个宏块进行 Huffman 解码,得到 DCT 系数 

    . 对每个宏块的 DCT 系数进行 IDCT,得到 Y、Cb、Cr 

    . 遇到 Segment Marker RST 时,清空之前的 DC DCT 系数 

    static void decode_MCU_1x1_3planes(struct jdec_private *priv)
    {
      // Y
      process_Huffman_data_unit(priv, cY); 
      IDCT(&priv->component_infos[cY], priv->Y, 8);
      
      // Cb
      process_Huffman_data_unit(priv, cCb);
      IDCT(&priv->component_infos[cCb], priv->Cb, 8);
    
      // Cr
      process_Huffman_data_unit(priv, cCr);
      IDCT(&priv->component_infos[cCr], priv->Cr, 8);
    }
    
    /*
     * Decode a 1x1 directly in 1 color
     */
    static void decode_MCU_1x1_1plane(struct jdec_private *priv)
    {
      // Y
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y, 8);
      
      // Cb
      process_Huffman_data_unit(priv, cCb);
      IDCT(&priv->component_infos[cCb], priv->Cb, 8);
    
      // Cr
      process_Huffman_data_unit(priv, cCr);
      IDCT(&priv->component_infos[cCr], priv->Cr, 8);
    }
    
    
    /*
     * Decode a 2x1
     *  .-------.
     *  | 1 | 2 |
     *  `-------'
     */
    static void decode_MCU_2x1_3planes(struct jdec_private *priv)
    {
      // Y
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y, 16);
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y+8, 16);
    
      // Cb
      process_Huffman_data_unit(priv, cCb);
      IDCT(&priv->component_infos[cCb], priv->Cb, 8);
    
      // Cr
      process_Huffman_data_unit(priv, cCr);
      IDCT(&priv->component_infos[cCr], priv->Cr, 8);
    }
    
    /*
     * Decode a 2x1
     *  .-------.
     *  | 1 | 2 |
     *  `-------'
     */
    static void decode_MCU_2x1_1plane(struct jdec_private *priv)
    {
      // Y
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y, 16);
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y+8, 16);
    
      // Cb
      process_Huffman_data_unit(priv, cCb);
    
      // Cr
      process_Huffman_data_unit(priv, cCr);
    }
    
    
    /*
     * Decode a 2x2
     *  .-------.
     *  | 1 | 2 |
     *  |---+---|
     *  | 3 | 4 |
     *  `-------'
     */
    static void decode_MCU_2x2_3planes(struct jdec_private *priv)
    {
      // Y
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y, 16);
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y+8, 16);
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y+64*2, 16);
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16);
    
      // Cb
      process_Huffman_data_unit(priv, cCb);
      IDCT(&priv->component_infos[cCb], priv->Cb, 8);
    
      // Cr
      process_Huffman_data_unit(priv, cCr);
      IDCT(&priv->component_infos[cCr], priv->Cr, 8);
    }
    
    /*
     * Decode a 2x2 directly in GREY format (8bits)
     *  .-------.
     *  | 1 | 2 |
     *  |---+---|
     *  | 3 | 4 |
     *  `-------'
     */
    static void decode_MCU_2x2_1plane(struct jdec_private *priv)
    {
      // Y
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y, 16);
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y+8, 16);
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y+64*2, 16);
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16);
    
      // Cb
      process_Huffman_data_unit(priv, cCb);
    
      // Cr
      process_Huffman_data_unit(priv, cCr);
    }
    
    /*
     * Decode a 1x2 mcu
     *  .---.
     *  | 1 |
     *  |---|
     *  | 2 |
     *  `---'
     */
    static void decode_MCU_1x2_3planes(struct jdec_private *priv)
    {
      // Y
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y, 8);
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y+64, 8);
    
      // Cb
      process_Huffman_data_unit(priv, cCb);
      IDCT(&priv->component_infos[cCb], priv->Cb, 8);
    
      // Cr
      process_Huffman_data_unit(priv, cCr);
      IDCT(&priv->component_infos[cCr], priv->Cr, 8);
    }
    
    /*
     * Decode a 1x2 mcu
     *  .---.
     *  | 1 |
     *  |---|
     *  | 2 |
     *  `---'
     */
    static void decode_MCU_1x2_1plane(struct jdec_private *priv)
    {
      // Y
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y, 8);
      process_Huffman_data_unit(priv, cY);
      IDCT(&priv->component_infos[cY], priv->Y+64, 8);
    
      // Cb
      process_Huffman_data_unit(priv, cCb);
    
      // Cr
      process_Huffman_data_unit(priv, cCr);
    }

    四、实验结果

    4.1输出YUV文件



    输出三个改为输出一个


    4.2TRACE

    输出 DQT的表


    Huffman表

                       

                               

    3.输出DC图像

                  

    4.输出DCT[25]

                           

    DCTC[0]图像       

                             

    DCT系数往后基本都为0,只有前几个非0

    展开全文
  • 柔滑的JPEG解码-不再有伪像! JPEG编码会丢失信息。 但是JPEG解码通过用噪声填充丢失的信息而引入了伪像。 jpeg2png更智能,可填充丢失的信息以创建尽可能平滑的图片。 左上方:Lena图像 右上:原始的64x64细节 ...
  • jpeg_tutorial:跟我写JPEG解码器(和我一起写JPEG解码器)
  • 图片编解码技术JPEG解码GIF文件结构与解码器TjpgDec技术BMP图片文件详解文档资料: BMP图片文件详解.pdf E文JPEG编解码介绍.pdf GIF Decoder.pdf GIF图形文件格式文档.doc GIF文件格式详解.doc GIF文件结构与解码器....
  • 摘 要:实现基于多核处理器构架的JPEG解码算法;通过将JPEG算法并行化,在多个处理器核上并行处理,并针对多核处理嚣构架进行内存读取等方面的优化,可极大地提高JPEG解码算法的解码速度。实测表明,在4核集成的...
  • 基于c的小尺寸JPEG解码,程序源程序是日本的一个开源网站
  • JPEG解码原理

    千次阅读 2019-04-14 01:13:39
    问题定义:为什么要做视频图像的编解码? 我们先来看看,视频资源占用计算:4KP30视频1min,3840218033060* = 42.7GB(每帧大小24.3MB),1分钟4K的视频大概需要42.7GB存储,因此视频图像的编解码十分必要。 我们再...

    1.背景介绍

    问题定义:为什么要做视频图像的编解码?
    我们先来看看,视频资源占用计算:4KP30视频1min,3840218033060* = 42.7GB(每帧大小24.3MB),1分钟4K的视频大概需要42.7GB存储,因此视频图像的编解码十分必要。
    我们再看看图像的存储格式和常用分辨率:
    模拟信号PAL、NTSC制式已经远去,我们来看数字信号(YUV、RGB888),由于人眼对亮度信号比色度信号更敏感,因此出现了YUV(planar/semi planar)降采样格式:YUV420、YUV422、YUV444
    在这里插入图片描述
    图1 降采样格式,实心点为Y分量,空心圆圈为cb、cr分量
    在这里插入图片描述
    图2 平面格式与交错格式内存存储

    2.编解码方法

    参考经典数字图像处理教材,常见的编解码方法主要做以下三方面工作:

    • 时间/空间冗余,利用时间空间相关性消除
    • 编码冗余,通过变长编码(直方图越大的值,分配较小的比特)
    • 不相关信息,忽略人眼不敏感的信息

    如下图,这张图有大量的平坦区域(空间冗余),并且灰度集中在几个区间(编码冗余)
    在这里插入图片描述
    基本上述分析,如何来从上述三个方面来压缩图像呢?基于两个先验:
    人眼对亮度分量的敏感度高于色度分量,轻微的色度变化对视觉体验影响很小
    人眼对低频分量的敏感度高于高频分量,轻微的高频变化对视觉体验影响很小
    常见的编解码流程如下:
    在这里插入图片描述

    3.JPEG编解码

    目前有较多的图像编码标准,如jpeg、bmp、gif、png、webp、heif,我们这里先说jpeg部分,这个编解码标准诞生于20世纪90年代,JPEG标准仅仅说明定义了codec部分,也就是图片如何压缩为字节流以及重新解码为图片的过程,标准没有涉及到文件的存储格式。
    1992年颁布了JPEG File Interchange Format(JFIF),目前在互联网上用的最多的jpeg格式,接着又出现了EXIF格式,主要用于数码产品,记录了媒体的时间地点信息。
    JPEG文件由一系列字段组成,每个字段都有marker(标记),由0xff开头。
    在这里插入图片描述
    (1)SOF marker(Start of Frame),这个字段定义了文件的起始
    在这里插入图片描述
    (2)APP0(Application-specific),这个字段定义了JFIF格式
    在这里插入图片描述
    (3)APPn(Application-specific),定义了其它格式,如APP1表示exif格式
    在这里插入图片描述
    (4)DQT(Define Quantization Table(s)),定义了量化表
    在这里插入图片描述
    下面以jpeg图的二进制数据来分析,通过vim打开后(:%!xxd切换到十六进制),ffd8表示start of image,ffe0表示app0,即是JFIF格式,0043前面的ffdb表示量化表(两个ffdb分别表示亮度和色度分量的量化表),0043表示量化表65字节(64byte量化参数 + 1 byte精度及量化表ID),ffc0表示start of frame,即图像数据。
    在这里插入图片描述

    3.jpeg编解码流程

    jpeg编码流程如下:
    在这里插入图片描述
    (1)块划分
    将输入数据按8x8划分数据块,源图像如果不是8x8的整数倍,需进行补充
    在这里插入图片描述
    (2)DCT变换
    减去128再进行DCT,DCT可接受的范围是[-128,127)
    DCT变换,得到64个基底系数,(0,0)位置是直流系数,是64个源数据的均值
    DCT在复杂度和失真上是最好的trade-off
    我们暂时先只考虑水平方向上一行数据(8个像素)的情况时的DCT变换,从而来说明其物理意义。如下图所示:
    原始的图像信号(最左边的波形)经过DCT变换之后变成了8个波,其中第一个波为直流成分,其余7个为交流成分。由于大多数图像的高频分量比较小,相应的图像高频分量的DCT系数经常接近于0,再加上高频分量中只包含了图像的细微的细节变化信息,而人眼对这种高频成分的失真不太敏感,所以,可以考虑将这一些高频成分予以抛弃,从而降低需要传输的数据量。这样一来,传送DCT变换系数的所需要的编码长度要远远小于传送图像像素的编码长度。到达接收端之后通过反离散余弦变换就可以得到原来的数据,虽然这么做存在一定的失真,但人眼是可接受的,而且对这种微小的变换是不敏感的。
    在这里插入图片描述
    (3)量化
    对亮度和色度分量的DCT系数进行量化,使用如下标准量化表,该量化表是从广泛的实验中得出的。当然,也可以自定义量化表

    //标准亮度分量量化表
    static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
        16,  11,  10,  16,  24,  40,  51,  61,
        12,  12,  14,  19,  26,  58,  60,  55,
        14,  13,  16,  24,  40,  57,  69,  56,
        14,  17,  22,  29,  51,  87,  80,  62,
        18,  22,  37,  56,  68, 109, 103,  77,
        24,  35,  55,  64,  81, 104, 113,  92,
        49,  64,  78,  87, 103, 121, 120, 101,
        72,  92,  95,  98, 112, 100, 103,  99
    };
    
    //标准色度分量量化表
    static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
        17,  18,  24,  47,  99,  99,  99,  99,
        18,  21,  26,  66,  99,  99,  99,  99,
        24,  26,  56,  99,  99,  99,  99,  99,
        47,  66,  99,  99,  99,  99,  99,  99,
        99,  99,  99,  99,  99,  99,  99,  99,
        99,  99,  99,  99,  99,  99,  99,  99,
        99,  99,  99,  99,  99,  99,  99,  99,
        99,  99,  99,  99,  99,  99,  99,  99
    };
    

    量化表搞掉了很多高频量,对DCT变换进行量化后得到量化结果,会出现大量的0,使用Z形扫描,可以将大量的0连到一起,减小编码后的大小。越偏离左上方,表示频率越高,这里其实是通过量化,将图像的高频信息干掉了。
    在这里插入图片描述
    (4)DC和AC分量编码
    DC进行DPCM编码,AC进行RLC编码,这两种编码都有中间格式,进一步减小存储量,原理可自行wiki
    (5)熵编码
    在得到DC系数的中间格式和AC系数的中间格式之后,为进一步压缩图像数据,有必要对两者进行熵编码,通过对出现概率较高的字符采用较小的bit数编码达到压缩的目的。JPEG标准具体规定了两种熵编码方式:Huffman编码和算术编码。JPEG基本系统规定采用Huffman编码。
    Huffman编码:对出现概率大的字符分配字符长度较短的二进制编码,对出现概率小的字符分配字符长度较长的二进制编码,从而使得字符的平均编码长度最短。Huffman编码的原理请参考数据结构中的Huffman树或者最优二叉树。
    Huffman编码时DC系数与AC系数分别采用不同的Huffman编码表,对于亮度和色度也采用不同的Huffman编码表。因此,需要4张Huffman编码表才能完成熵编码的工作。具体的Huffman编码采用查表的方式来高效地完成。然而,在JPEG标准中没有定义缺省的Huffman表,用户可以根据实际应用自由选择,也可以使用JPEG标准推荐的Huffman表。或者预先定义一个通用的Huffman表,也可以针对一副特定的图像,在压缩编码前通过搜集其统计特征来计算Huffman表的值。

    下一篇再来讲jpeg编解码库libjpeg turbo的使用。

    5.参考

    [1] https://en.wikipedia.org/wiki/JPEG
    [2] https://blog.csdn.net/carson2005/article/details/7753499

    展开全文
  • jpeg解码器 用于解码JPEG的Rust库。 例子 Cargo.toml: [ dependencies ] jpeg-decoder = " 0.1 " main.rs: extern crate jpeg_decoder as jpeg; use std :: fs :: File; use std :: io :: BufReader; fn main ...
  • Knusperli的目标是通过将图像数据中的量化DCT系数解释为一个间隔而不是一个固定值,并从该间隔中选择一个值,以最大程度地减少块边界处的不连续性,从而减少JPEG解码图像中的块状伪影。 传统的JPEG解码器...
  • JPG软件解码 STM32,可用于stm32快速刷新图像,软件解码jpg文件,不用自己手写代码!
  • 实现基于多核处理器构架的JPEG解码算法;通过将JPEG算法并行化,在多个处理器核上并行处理,并针对多核处理嚣构架进行内存读取等方面的优化,可极大地提高JPEG解码算法的解码速度。实测表明,在4核集成的多核处理器...
  • 这款解码库的源码 比较适合学习JPEG本身和JFIF的格式。 其中带了使用的demo 和一个转BITMAP的程序。 可以方便的测试。 欢迎发现问题之后和我交流 QQ 365155289
  • JPEG解码C源代码及一些解释

    热门讨论 2010-05-31 16:55:20
    包括JPEG格式的解码标准C源代码及说明文档,希望对需要的人有帮助。
  • 掌握 JPEG解码系统的基本原理。初步掌握复杂的数据压缩算法实现,并能根据理论分析需要实现所对应数据的输出。 二、JEPEG原理: JPEG 是Joint Photographic Experts Group(联合图像专家小组)的缩写,是第一个国际...

    一、实验目的:

    掌握 JPEG 编解码系统的基本原理。初步掌握复杂的数据压缩算法实现,并能根据理论分析需要实现所对应数据的输出。

    二、JEPEG原理:

    JPEG 是Joint Photographic Experts Group(联合图像专家小组)的缩写,是第一个国际图像压缩标准。
    .jpeg/.jpg是最常用的图像文件格式,是一种有损压缩格式。JPEG编码框图如下图所示:

    在这里插入图片描述
    编码步骤为:

    (1)颜色空间转换、采样、零偏置

    由于JPEG采用的是YUV颜色空间,首先将输入图片转换为YUV颜色空间,并按一定的采样格式进行采样。然后对Y分量进行电平偏移转换,可以对Y减128操作,使Y、U、V电平取值范围都在-128~127之间。

    (2)分块

    分别对Y、U、V三个分量的数据进行88分块,编码时,按从左至右,从上至下的顺序依次读取一个88块,对其进行DCT变换、量化、编码后,再读取下一个8*8块。

    若图像宽高不是8的整数倍,还需要通过复制相邻像素值补成8的整数倍。
    

    (3)DCT变换

    JPEG中采用DCT(离散余弦变换),DCT变换具有能量守恒、能量集中和去相关的特性。这样可以将能量集中在低频区域,对低频和高频各系数采用不同的量化比特数进行单独量化,不会损伤过多的效率。

    (4)zig-zag扫描排序、量化

    对每个88块的数据进行zig-zag扫描排序,重新排序后的88数组里的系数值按低频到高频依次排列。再对每个8*8系数块进行量化,由于人眼对亮度信号比对色差信号更敏感,所以采用亮度量化表和色差量化表对其分别处理。又由于人眼对低频比对高频敏感,所以对低频系数细量化,对高频粗量化。

    zig-zag扫描: 两张量化表:

    (5)DC系数的差分脉冲调制编码

    由于8*8 的图像块经过 DCT 变换之后得到的 DC 系数有两个特点:

    (1)系数的数值比较大;

    (2)相邻的 8*8 图像块的 DC 系数值变化不大:冗余;

    所以对DC系数采用DPCM编码,即对相邻图像块之间量化DC系数的差值DIFF进行无损编码。

    (6)AC系数的游程编码

    因为DCT变换后AC系数按zig-zag排序后可以出现很多连零的机会,采用游程编码(RLC)可以进一步降低数据的传输量。

    (7)熵编码

    在得到 DC 系数的中间格式和 AC 系数的中间格式之后,为进一步压缩图象数据,有必要对两者进行熵编码。JPEG算法中通常采用Huffman编码方法。JPEG中共采用了四张Huffman码表:亮度DC、亮度AC、色度DC、色度AC。

    三、JPEG文件格式

    JPEG文件大体上可以认为是标记码和压缩数据的组合体。标记码部分提供JPEG图像的特征信息,与BMP中头文件相似,但复杂的多。JPEG的每个标记都是两个字节组成的,且前一个字节恒为0xFF.下表列出了几个比较常用的标记码:

    SOI ,Start of Image, 图像开始
    标记代码 2字节 固定值0xFFD8
    EOI, End of Image, 图像结束

    标记代码 2字节 固定值0xFFD9

    APP0 应用程序保留标记0

    (1)DQT标记段,包括一个或者多个量化表

    量化表长度。长度参数占用两个字节,他不包括前两个字节0XFF和0XDB。
    量化表数目。表数目参数占用一个字节,其中高4位为量化表的数据精确度。若高4位等于0,那么后面的量化表中的每个值占8位;若高4位等于1,那么后面的量化表中每个值占16位,低4位表示量化表的编号,为0~3.
    量化表表项。表项参数对应Z字形排列后的64个数值。
    (2)DHT标记段,包括一个或多个霍夫曼表

    霍夫曼码表的长度。占用两个字节。
    每个霍夫曼码表(霍夫曼码表一般不止一个,但是绝对不多于4个)都包含4个信息:索引、类型、位表和内容编码。索引信息表示该霍夫曼表的表号,占1个字节。高四位可以是0或1,为0时指DC所用的霍夫曼表;为1时,指AC所用的霍夫曼表。低4位表示霍夫曼表的编号,值为0或1.位表是一个长为16字节的编码,其代码代数和为接下来的编码长度。内容编码信息表示每个霍夫曼码字对应的值
    (3)压缩数据
    图像的压缩存放在若干8*8数据块组成的MCU(Minimum Data Unit,最小数据单元)。图像从上到下,从左到右划分成若干MCU,若图像的宽高不是整数倍,则对图像的底边和右边进行复制。

    四、实验代码部分

    以TXT文件输出所有的量化矩阵和所有的HUFFMAN码表

        static int parse_DQT(struct jdec_private *priv, const unsigned char *stream)
    {
        ......
          while (stream < dqt_block_end)
       {
         qi = *stream++;
        #if C_TRACE     //cdj add
             fprintf(c_trace, ">DQT marker\n");//输出进入Parse_DQT的提示符
             fprintf(c_trace, "DQT TABLE[%d]\n", qi & 0x0F);
             fflush(c_trace);
        #endif
        table = priv->Q_tables[qi];
         build_quantization_table(table, stream);
         stream += 64;
       }
        ......
    }
    
        static void build_quantization_table(float *qtable, const unsigned char *ref_table)
    {
      ......
      for (i=0; i<8; i++) {
         for (j=0; j<8; j++) {
           *qtable = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j];          
    #if C_TRACE
           fprintf(c_trace, "%2d\t", ref_table[zigzag[i*8+j]]);
       if (j == 7)
               fprintf(c_trace, "\n");
           fflush(c_trace);
    #endif
           qtable++;
         }
       }
    ......
    }
    
        static void build_huffman_table(const unsigned char *bits, const unsigned char *vals, struct huffman_table *table)
    {
            ......
        for (i=0; huffsize[i]; i++)
       {
           ......
        #if C_TRACE
         fprintf(c_trace, "val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size);
        
         fflush(c_trace);
    #endif
            ......
       }
            ......
    }
    

    输出DC图像、与AC分量

        #if C_TRACE
      char temp[1024];
      snprintf(temp, 1024, "%s_DC.yuv", output_filename);
      C_DCpicture = fopen(temp, "wb");
      if (C_DCpicture == NULL)
      {
          printf("C_DCpicture FILE OPEN ERROR");
      }
      snprintf(temp, 1024, "%s_AC.yuv", output_filename);
      C_ACpicture = fopen(temp, "wb");
      if (C_ACpicture == NULL)
      {
          printf("C_ACpicture FILE OPEN ERROR");
      }
        #endif
    
    
        static void decode_MCU_1x1_3planes(struct jdec_private *priv)
    {
      // Y
      process_Huffman_data_unit(priv, cY);
    #if C_TRACE
      unsigned char tmp_dc = (unsigned char)(&priv->component_infos[cY])->DCT[0]/8;
      unsigned char tmp_ac = (unsigned char)(&priv->component_infos[cY])->DCT[1];
      fwrite(&tmp_ac, 1, 1, C_ACpicture);
    #endif
      IDCT(&priv->component_infos[cY], priv->Y, 8);
    
      // Cb
      process_Huffman_data_unit(priv, cCb);
      IDCT(&priv->component_infos[cCb], priv->Cb, 8);
    
      // Cr
      process_Huffman_data_unit(priv, cCr);
      IDCT(&priv->component_infos[cCr], priv->Cr, 8);
    }
    
    

    五、实验结果

    在这里插入图片描述

    txt输出结果:
    在这里插入图片描述

    在这里插入图片描述
    输出AC、DC图像并经过huff_run.exe统计其概率分布:

    DC(DCT[0]):

    在这里插入图片描述
    在这里插入图片描述
    AC(DCT[4]):
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • JPEG解码的实现,包括哈夫曼编码,解码。还有JPG转BMP格式程序.
  • JPEG解码_C语言实现

    万次阅读 2017-06-01 20:34:14
    1.JPEG解码原理 JPEG(Joint Photographic Experts Group)采用有损压缩方式去除冗余的图像和彩色数据,在获得极高压缩率的同时能展现十分丰富生动的图像。 编码原理图如下: ① Level Offset(零偏置) 为了使使...

    一、实验原理

    1.JPEG编解码原理

    JPEG(Joint Photographic Experts Group)采用有损压缩方式去除冗余的图像和彩色数据,在获得极高压缩率的同时能展现十分丰富生动的图像。

    编码原理图如下:

    ① Level Offset(零偏置

    为了使使像素的绝对值出现3位10进制的概率大大减少,对于灰度级是2的n次方的像素,通过减去2的n-1次方,将无符号的整数值变成有符号数。

    ② 8✖️8 DCT变换

    变换公式如下:


    DCT变换的优点:1、能量守恒  2、能量集中  3、去相关

    经过DCT变换后,能量集中在左上角,使得左上角数值较大,右下角数值较小。


    ③Uniform scalar quantization(量化)

    因为人眼对亮度信号比对色差信号更敏感,因此使用了两种量化表:亮度量化值和色差量化值。由于人眼对低频敏感,对高频不太敏感,因此对低频分量采取较细的量化,对高频分量采取较粗的量化。


    dc quantization indices Differential coding(DC系数的差分编码

    8×8图像块经过DCT变换之后得到的DC直流系数有两个特点:系数的数值比较大; 相邻8×8图像块的DC系数值变化不大(产生冗余)。

    根据这个特点,JPEG算法使用了差分脉冲调制编码(DPCM)技术,对相邻图像块之间量化DC系数的差值DIFF进行编码:DIFFk =DCk - DCk-1。

    码表如下(此编码表并不是一成不变的,不同的文件有不同的码表。以此码表为例,DC=8,上一DC=5时,则DIFF=8-5=3,类别ID=2,类内索引=3,则码流为10011):


    ⑤Zig-zag scan(AC系数的Z字扫描

    由于量化之后右下角高频系数大部分为0,在编码是为了制造更长的0游程提高编码效率,采用之字形扫描读取法。经过之字形扫描读出后把二维系数矩阵转换为一维数据序列。在最后, 如果都是零,给出 EOB (End of Block) 即可。 
    zig-zag序



    AC系数的游程编码(Run-level coding

    编码规则:(run,level) 
    表示连续run个0,后面跟着值为level的AC系数。 

    run:最多15个,故用4位表示。

    level:类似DC系数,分为类别ID与类内索引。用4位表示类别ID。 

    (run,level的类别ID)合成1字节存在AC系数码表的权值中

    AC系数的之字形序列编码中有两个特殊符号——(0,0)和(15,0)。第一个特殊符号指的是块的结束(end-of-block,EOB),用来表明在之字形块中剩余的元素都是零。另一个特殊符号是指零游程长度(zero-run-length,ZRL),用来表明16个零游程。基线(baselinesequential)JPEG算法允许的零游程最大长度是16个。如果这里的零超过16个,那么这个游程分成几个长度为16的零游程。 
    经过RLE编码的AC系数可以映射成两个标志(RUNLENGTH,CATEGORY)和(AMPLITUDE),前者采用的是霍夫曼编码,而后者采用的是VLI编码(直接二进制编码)。同理经过DPCM编码的DC系数同样可以映射成两个标志(CATEGORY)和(AMPLITUDE),,前者采用霍夫曼编码,后者采用VLI编码。

    解码过程是编码过程的反过程


    2. JPEG文件格式

    英文缩写 英文全称 说明 标志代码
    SOI Start of Image 图像开始 0xFFD8
    APPn Application 应用程序保留标记n 0xFFEn
    DQT Define Quantization Table 定义量化表 0XFFDB
    SOF0 Start of Frame 帧图像开始 0xFFC0
    DHT Define Huffman Table 定义哈夫曼表 0xFFC4
    SOS Start of Scan 扫描开始,12字节 0xFFDA
    EOI End of Image 图像结束,2字节 0xFFD9

    JPEG文件以FFD8开头

    APPn是文件细节信息,看图片时,没有点进去就显示出来的缩略图就是存在这部分里,下图FFE0为APP0,从FFE0依次向后读:00 10表示该部分占16字节;4A 46 49 4600表示JFIF0;01 01表示版本号;00 表示X和Y方向的密度单位(0:无单位、1:1像素/英寸、2:2像素/厘米);00 01表示X方向像素密度;00 01表示Y方向像素密度;最后的00和00分别表示缩略图的X和Y方向像素数,由于该文件没有缩略图,后面就没有缩略的RGB位图的数据。

    文件中有两个FFDB,说明有两张量化表(DQT),以第一张量化表为例,从FFDB向后读:00 43表示量化表的长度为67字节;00的低四位表示第0张量化表,高四位表示8bit的量化精度(非0则16bit);最后是8*8的量化表实际数据,按之字形保存。

    FFC0代表帧图像的开始(SOF0),向后读:00 11表示该部分的长度17字节;08表示每个颜色分量每个像素占8bit;04 00 04 00表示图像的高和宽分别为1024和1024像素;03 表示有3个颜色分量(YCbCr);后面9个字节,每3个一组,分别表示Y、Cb、Cr的如下信息,1字节的颜色ID(01、02、03)、1字节的采样因子(高四位水平 1、低四位垂直 1,说明MCU为8*8)、该分量使用的量化表(00、01、01)。

    该文件有4个FFC4,表示有4张huffman码表,以第一张为例:001D表示这张表的长度为29字节;00高四位表示直流(1为交流),低四位表示第0张表;后面16字节为不同位数码字的数量,00 03 01 01……00等表示码字为1、2、3……16位的个数分别为0、3、1、1……0个,相加得到码字总数为10;最后是这10个码字对应的权重,表示解码时需要再读入的位数。

    FFDA表示扫描开始(SOS):00 0C表示这部分长度12字节;03表示颜色分量数为3; 后面6个字节。每2个一组表示一种颜色分量的ID和该分量使用的直流与交流量化表,01 00表示Y分量,交流使用第0张量化表,直流使用第0张量化表,02 11表示Cb分量,交流直流均使用第1张量化表,03 11表示Cr分量,交流直流均使用第1张量化表;后面是压缩图像数据,00是固定值,表示谱选择开始,3F是固定值,表示谱选择结束,00是固定值,表示谱选择。

    后面是图像流的组成部分,需要进行译码,直至遇到FF D9(EOI)结束。


    二、代码分析

    任务一:调试JPEG解码器程序,将输出文件保存为可供YUVViewer观看的YUV文件。

    1. 定义输入参数的枚举类型enum tinyjpeg_fmt中增加TINYJPEG_FMT_YUV一项

    enum tinyjpeg_fmt {
       TINYJPEG_FMT_GREY = 1,
       TINYJPEG_FMT_BGR24,
       TINYJPEG_FMT_RGB24,
       TINYJPEG_FMT_YUV420P,
       /*******************/
       TINYJPEG_FMT_YUV,//增加
       /*******************/
    };

    2.  convert_one_image函数的判断输出格式里增加caseTINYJPEG_FMT_YUV一项。
     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_YUV:
            write_YUV(outfilename, width, height, components);
            break;//增加
        /***************************************************************/
        case TINYJPEG_FMT_GREY:
          write_pgm(outfilename, width, height, components);
          break;
       }

    3. main函数,增加解析命令行。

    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");

    4.在 tinyjpeg_decode函数中switch里增加caseTINYJPEG_FMT_YUV项

     

    switch (pixfmt) {
            ......
            //增加start
         case TINYJPEG_FMT_YUV:
           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;
           //增加end
          ......
      }

    任务二:

    以txt文件输出所有的量化矩阵、所有的HUFFMAN码表。

    1. 定义指向txt文件的指针

    FILE *p_ytxt;
    #define YTXT 1 
    #define YTXTFILE "ld.txt" 

    2.  打开txt文件

    #if YTXT
      p_ytxt = fopen(YTXTFILE, "w");
      if (p_ytxt == NULL)
      {
          printf("trace file open error!");
      }
    #endif

    3.  输出量化矩阵

    static void build_quantization_table(float *qtable, const unsigned char *ref_table)
    {
      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++) {
        #if YTXT
                  fprintf(p_ytxt, "%d ", ref_table[*zz]);//输出以zigzag矩阵所规定的顺序的量化矩阵。原因是ref_table指针中存着的着量化表值是以z字形扫描的次序来进行存储的,因此需要利用zigzag进行正确的排序
                  fflush(p_ytxt);
        #endif
              *qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j];
              }
             #if YTXT
                  fprintf(p_ytxt, "\n");
                  fflush(p_ytxt);
             #endif
    
      }
    
    }

    4.zigzag矩阵

    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
    };

    5.  输出Huffman码表(包含长度、AC/DC信息),输出Huffman码表的码长、码字、对应的符号

    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 TRACE
      fprintf(p_trace,"> DHT marker (length=%d)\n", length);
      fflush(p_trace);
    #endif
    #if YTXT
      fprintf(p_ytxt, "> DHT marker (length=%d)\n", length);
      fflush(p_ytxt);
    #endif
      while (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_CHECK
         if (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 TRACE
         fprintf(p_trace,"Huffman table %s[%d] length=%d\n", (index&0xf0)?"AC":"DC", index&0xf, count);
         fflush(p_trace);
    #endif
    #if YTXT
         fprintf(p_ytxt, "Huffman table %s[%d] length=%d\n", (index & 0xf0) ? "AC" : "DC", index & 0xf, count);
         fflush(p_ytxt);
    #endif
    #endif
    
         if (index & 0xf0 )
           build_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]);
         else
           build_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]);
    
         length -= 1;
         length -= 16;
         length -= count;
         stream += count;
      }


    static void build_huffman_table(const unsigned char *bits, const unsigned char *vals, struct huffman_table *table)
    {
      unsigned int i, j, code, code_size, val, nbits;
      unsigned char huffsize[HUFFMAN_BITS_SIZE+1], *hz;
      unsigned int huffcode[HUFFMAN_BITS_SIZE+1], *hc;
      int next_free_entry;
    
      /*
       * Build a temp array 
       *   huffsize[X] => numbers of bits to write vals[X]
       */
      hz = huffsize;
      for (i=1; i<=16; i++)
       {
         for (j=1; j<=bits[i]; j++)
           *hz++ = i;
       }
      *hz = 0;
    
      memset(table->lookup, 0xff, sizeof(table->lookup));
      for (i=0; i<(16-HUFFMAN_HASH_NBITS); i++)
        table->slowtable[i][0] = 0;
    
      /* Build a temp array
       *   huffcode[X] => code used to write vals[X]
       */
      code = 0;
      hc = huffcode;
      hz = huffsize;
      nbits = *hz;
      while (*hz)
       {
         while (*hz == nbits)
          {
        *hc++ = code++;
        hz++;
          }
         code <<= 1;
         nbits++;
       }
    
      /*
       * Build the lookup table, and the slowtable if needed.
       */
      next_free_entry = -1;
      for (i=0; huffsize[i]; i++)
       {
         val = vals[i];
         code = huffcode[i];
         code_size = huffsize[i];
        #if TRACE
         fprintf(p_trace,"val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size);
         fflush(p_trace);
        #endif
        #if YTXT
             fprintf(p_ytxt, "val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size);
             fflush(p_ytxt);
        #endif
         table->code_size[val] = code_size;
         if (code_size <= HUFFMAN_HASH_NBITS)
          {
        /*
         * Good: val can be put in the lookup table, so fill all value of this
         * column with value val 
         */
        int repeat = 1UL<<(HUFFMAN_HASH_NBITS - code_size);
        code <<= HUFFMAN_HASH_NBITS - code_size;
        while ( repeat-- )
          table->lookup[code++] = val;
    
          }
         else
          {
        /* Perhaps sorting the array will be an optimization */
        uint16_t *slowtable = table->slowtable[code_size-HUFFMAN_HASH_NBITS-1];
        while(slowtable[0])
          slowtable+=2;
        slowtable[0] = code;
        slowtable[1] = val;
        slowtable[2] = 0;
        /* TODO: NEED TO CHECK FOR AN OVERFLOW OF THE TABLE */
          }
    
       }
    }

    任务三:输出DC图像并经过huffman统计其概率分布,并输出某一个AC值图像并统计其概率分布。

    FILE *dc_file;
    FILE *ac_file;
    

    #if DC
      dc_file = fopen(DCFILE, "wb");
      if (dc_file == NULL)
      {
          printf("trace file open error!");
      }
    #endif
     
    #if AC
      ac_file = fopen(ACFILE, "wb");
      if (ac_file == NULL)
      {
          printf("trace file open error!");
      }
    #endif
    1
    

    在JPEG结构体中定义指针,用于写入AC和DC图像

    struct jdec_private
    {
      int  *acimage,*dcimage;
    }

    priv->dcimage = (int *)malloc(sizeof(int)*priv->width * priv->height/64);
    priv->acimage = (int *)malloc(sizeof(int)*priv->width * priv->height / 64);



    static void DC_image(struct jdec_private *priv)
    {
        static int i=0;
        if ( i < (priv->height*priv->width / 64))
        {
            priv->dcimage[i] = priv->component_infos[cY].DCT[0];
        }
        i++;
    }
    static void AC_image(struct jdec_private *priv)
    {
        static int i = 0;
        if (i < (priv->height*priv->width / 64))
        {
            priv->acimage[i] = priv->component_infos[cY].DCT[1];
        }
        i++;
    }

    输出为yuv文件

     int acmax, dcmax, acmin, dcmin;
      int tmp;
      acmax = priv->acimage[0];
      acmin = priv->acimage[0];
      dcmax = priv->dcimage[0];
      dcmin = priv->dcimage[0];
      for (i = 0; i < priv->width*priv->height / 64; i++)
      {
          if (priv->acimage[i] >=acmax)
              acmax = priv->acimage[i];
          if (priv->dcimage[i] >= dcmax)
              dcmax = priv->dcimage[i];
          if (priv->acimage[i] <= acmin)
              acmin = priv->acimage[i];
          if (priv->dcimage[i] <=dcmin)
              dcmin = priv->dcimage[i];
      }
      for (i = 0; i < priv->width*priv->height / 64; i++)
      {
          tmp = priv->acimage[i] - acmin;
          acfileout[i] = (unsigned char)(255 *(priv->acimage[i]-acmin)/ (acmax - acmin));
      }
      fwrite(acfileout, 1, priv->width*priv->height / 64, ac_file);
      if (acfileout)
          free(acfileout);
      for (i = 0; i < priv->width*priv->height / 64; i++)
      {
          dcfileout[i] = (unsigned char)(255 *(priv->dcimage[i]-dcmin)/ (dcmax - dcmin));
      }
      fwrite(dcfileout, 1, priv->width*priv->height / 64, dc_file);
      if (dcfileout)
          free(dcfileout);

    三、实验结果

    输出量化表


    输出的Huffman码表:



    原始图像YUV:


    输出的DC图像及其概率分布图:

     


    输出的AC图像及其概率分布图:

     





    蚊子噪声的图像 


    压缩程度越剧烈,量化的步长越大,高频系数为零的可能性就越大,即高频截止,于是轮廓周围会出现许多蚊子似的点,即空间域出现蚊子噪声。

    展开全文
  • 图像jpeg解码文档

    2018-09-05 17:05:32
    jpeg解码总结文档,快速了解jpeg解码,对jpeg标准进行归纳
  • 在NVIDIA A100 GPU上利用硬件JPEG解码器和NVIDIA nvJPEG库 根据调查,普通人产生的1.2万亿张图像可以通过电话或数码相机捕获。这样的图像的存储,尤其是以高分辨率的原始格式,会占用大量内存。 JPEG指的是联合图像...
  • jpeg解码,将jpeg解码成bmp格式 jpeg解码,将jpeg解码成bmp格式 jpeg解码,将jpeg解码成bmp格式
  • 嵌入式开发之Opencv(二)JPEG解码加速

    千次阅读 2018-07-26 23:03:51
    参考文档 ...Speed-Up JPEG Encode/Decode Processing for OpenCV using libjpeg-turbo libjpeg-turbo性能报告与建议 libjpeg对于(I)DCT Scale的支持和快速实现 libjpeg-turbo介绍 libjpeg-tur...
  • JPEG解码详解--实例

    2021-10-20 16:42:17
    根据前面学习到的jpeg解码知识,编写jpeg解码code,此处采用实际的解码过程对jpeg进行讲解 如图1,为实际的jpg图像数据,根据JPEG格式,解析出对应的标识符与对应的数据信息。 FF D8:SOI 文件头 FF E0:APP0 ...
  • Tiny_Jpeg 微型 Jpeg 解码器 Luc Saillard GNU 公共许可证的原始代码 2007 年 6 月 9 日 tinyjpegdecoder-20070609.... 2个流行的公共Jpeg解码器小代码之一 Nano Jpeg Martin Fiedler东德 Tiny Jpeg Luc Saillard 法国
  • 介绍了基于静止图像压缩标准JPEG解码器IP核的设计与实现。设计采用适于硬件实现的IDCT算法结构,通过增加运算并行度和流水线技术相结合的方法以提高处理速度。根据Huffman码流特点,采用新的Huffman并行解码硬件实现...
  • ESP32-CAM拍照,jpeg解码

    2021-10-26 21:40:51
    ESP32-CAM拍照输出jpeg,解码为rgb565在tft屏显示 ESP32-CAM使用Arduino编译烧录,STM...jpeg解码参考:https://techclass.rohm.com.cn/knowledge/tech-info/how-tos/arduino/jpeg-decoding-on-arduino-tutorial 修改w

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 35,922
精华内容 14,368
关键字:

jpeg解码