Apply data compression to image compression - baidut/co-codec GitHub Wiki

注:如有疑问可以到对应的issue中添加评论。

将数据压缩技术应用到图像压缩中,在图像压缩最后一级加入数据压缩,从而去除数据的统计冗余。

  • 直接在原工程上改,适合少许修改,如参数调整,逻辑调整
  • 继承原来的扫描类,重写接口实现,适合对原有方法进行改进的情形
  • 添加新的扫描类定义,工作量大,但有助于理解结构且不破坏原工程,适合添加新的方法的情形

这里为了提取图像压缩技术衔接数据压缩的接口,采用第三种方式。

定义新的marker

issue:添加新的帧类型标记

注:这里的X应该是十六进制的含义(HEX) 见标准文档P36/186 Table B.1 – Marker code assignments

X’FF02’ through X’FFBF’ RES ReservedFF02到FFBF都是保留marker,可以从这里选,为了匹配扫描类型,这里选择了

#define JPGCODE_SOF_ANS_SEQ         0xFF09
#define JPGCODE_SOF_ANS_DIF_SEQ     0xFF0D

jpeg-ls's main process flow analysis

main
  ├─ Encode (ppm──>jpg)
  │  ├─ jpeg->ProvideImage(tags) 
  │  │  └─ JPEG::InternalProvideImage(tags)
  │  │     └─ m_pEncoder->CreateImage(tags)   ──> write FrameType
  │  │ 
  │  └─ jpeg->Write(iotags)
  │     └─ JPEG::WriteInternal(tags)
  │        ├─ m_pImage->StartMeasureFrame()
  │        ├─ frame->StartMeasureScan()
  │        ├─ m_pImage->StartWriteFrame(m_pIOStream)
  │        ├─ m_pFrame->StartWriteScan(m_pIOStream)
  │        ├─ m_pScan->StartMCURow()
  │        ├─ m_pScan->Flush()
  │        └─ m_pScan->WriteMCU()
  │ 
  └─ Reconstruct (jpg──>ppm)
     ├─ jpeg->Read(tags)
     │  └─ JPEG::ReadInternal(tags)
     │     ├─ m_pDecoder->ParseHeader(m_pIOStream)
     │     ├─ m_pImage->StartParseFrame(m_pIOStream)
     │     ├─ m_pFrame->StartParseScan(m_pIOStream)
     │     ├─ m_pScan->StartMCURow()
     │     └─ m_pScan->ParseMCU()
     │  
     ├─ jpeg->GetInformation(itags)
     └─ jpeg->DisplayRectangle(tags)
        └─ JPEG::InternalDisplayRectangle(tags)
           └─ m_pImage->ReconstructRegion(&bmh,&rr)
              └─ m_pImage->ReconstructRegion(bmh,rr)   ──> ReconstructRegion interface

基本步骤

  1. 定位熵编码相关的类
  2. 分析熵编码模块的调用关系
  3. 封装框架

调用的方法有:

  • m_pScan->StartMCURow() return m_pParser->StartMCURow();
  • m_pScan->ParseMCU() return m_pParser->ParseMCU();
  • scan->WriteMCU() return m_pParser->WriteMCU();
  • m_pScan->Flush() m_pParser->Flush(true);

看scan被谁调用了 // 需要实现方法 scan的那些方法被调用了

成员的相关方法需要实现 class EntropyParser *m_pParser; 通过看一个最简单的parser的实现了解如何对ANS进行封装

分析scan中调用了m_pParser->WriteFrameType(io);的情况

定位熵编码相关的类,分析其关系 熵编码解析器为基类,提供接口 各类扫描熵编码器提供熵编码的实现,被Scan调用,需要实现方法,

NOTES

注意为了防止在编码段中出现JPEG标记,需要对FF开头的比特进行转码。因此调用了数据压缩程序得到的熵编码段还需要进行处理才能放入图像压缩程序中。处理工作可以在从熵编码缓存区输出到文件时进行。

In order to ensure that a marker does not occur within an entropy-coded segment, any X’FF’ byte generated by either a Huffman or arithmetic encoder, or an X’FF’ byte that was generated by the padding of 1-bits described in NOTE 1 above, is followed by a “stuffed” zero byte (see D.1.6 and F.1.2.3).

F.1.2.3 Byte stuffing In order to provide code space for marker codes which can be located in the compressed image data without decoding, byte stuffing is used. Whenever, in the course of normal encoding, the byte value X’FF’ is created in the code string, a X’00’ byte is stuffed into the code string. If a X’00’ byte is detected after a X’FF’ byte, the decoder must discard it. If the byte is not zero, a marker has been detected, and shall be interpreted to the extent needed to complete the decoding of the scan. Byte alignment of markers is achieved by padding incomplete bytes with 1-bits. If padding with 1-bits creates a X’FF’ value, a zero byte is stuffed before adding the marker.

⚠️ **GitHub.com Fallback** ⚠️