JPEG编码中的采样过程其实就是一个图像数据转换成若干个8*8数据块的过程,如下图将原始图像分成8*8个小块(block),每个block中有64个像素:

ImageSharp源码详解之JPEG编码原理(2)采样

 

ImageSharp源码中关于采样有有两种选择,一种叫JpegSubsample.Ratio444,一种叫JpegSubsample.Ratio420。这两种选择就是对于JPEG图像的两种采样方法,就是我们常说的YUV采样。

与我们熟知的RGB类似,YUV也是一种颜色编码方法,主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样可以显示完整的图像,只不过是黑白的,下图就是我用ImageSharp源码做的实验,只保留Y通道,UV通道设成0:

ImageSharp源码详解之JPEG编码原理(2)采样  ImageSharp源码详解之JPEG编码原理(2)采样             

          原图                       Ratio420只留Y通道,159KB      

ImageSharp源码详解之JPEG编码原理(2)采样

      Ratio444只留Y通道,181KB                                    

YUV不像RGB那样要求三个独立的视频信号同时传输,所以用YUV方式传送占用极少的频宽。YUV码流的存储格式其实与其采样的方式密切相关,主流的采样方式有三种,YUV4:4:4,YUV4:2:2,YUV4:2:0。现在的YUV是通常用于计算机领域用来表示使用YCbCr编码的文件。可以粗浅地视YUV为YCbCr,我们后面也换成这种叫法。

一般看到这里,会出现一个概念,叫做MCU。不是单片机更不是漫威,它中文意思是最小的编码单元(Minimum Coded Unit),它是图像中一个正方矩阵像素的数据,对于不同的采样,MCU的像素也不一样:

1.YCbCr 4:4:4(其他资料可能叫1:1:1)

这种是最简单的采样方式,这种方式里面,数据流存放数据顺序就是YCbCr ,每个MCU代表着8*8个像素块。

2.YCbCr 4:2:2

 ImageSharp源码详解之JPEG编码原理(2)采样

这种方式下数据流存放顺序如图所示,每个MCU代表着16x8个像素,Y0和Y1分别指向两个8*8像素块,这两个像素块共用一个Cb和Cr通道。

3.YCbCr 4:2:0(其他资料可能叫4:1:1)

ImageSharp源码详解之JPEG编码原理(2)采样

这种方式下每个MCU代表着16x16个像素,Y0和Y1分别指向4个8*8像素块,这4个像素块共用一个Cb和Cr通道。

2. YUV采样源码分析

回到ImageSharp源码中,我们可以看到两种采样方法,分别是4:4:4和4:2:0,我们看一下他们的方法,先是4:4:4。

 1         /// <summary>
 2         /// Encodes the image with no subsampling.
 3         /// </summary>
 4         /// <typeparam name="TPixel">The pixel format.</typeparam>
 5         /// <param name="pixels">The pixel accessor providing access to the image pixels.</param>
 6         private void Encode444<TPixel>(Image<TPixel> pixels)
 7             where TPixel : struct, IPixel<TPixel>
 8         {
 9             // TODO: Need a JpegScanEncoder<TPixel> class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.)
10             // (Partially done with YCbCrForwardConverter<TPixel>)
11             Block8x8F temp1 = default;
12             Block8x8F temp2 = default;
13 
14             Block8x8F onStackLuminanceQuantTable = this.luminanceQuantTable;
15             Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable;
16 
17             var unzig = ZigZag.CreateUnzigTable();
18 
19             // ReSharper disable once InconsistentNaming
20             int prevDCY = 0, prevDCCb = 0, prevDCCr = 0;
21 
22             var pixelConverter = YCbCrForwardConverter<TPixel>.Create();
23 
24             for (int y = 0; y < pixels.Height; y += 8)
25             {
26                 for (int x = 0; x < pixels.Width; x += 8)
27                 {
28                     pixelConverter.Convert(pixels.Frames.RootFrame, x, y);
29 
30                     prevDCY = this.WriteBlock(
31                         QuantIndex.Luminance,
32                         prevDCY,
33                         &pixelConverter.Y,
34                         &temp1,
35                         &temp2,
36                         &onStackLuminanceQuantTable,
37                         unzig.Data);
38                     prevDCCb = this.WriteBlock(
39                         QuantIndex.Chrominance,
40                         prevDCCb,
41                         &pixelConverter.Cb,
42                         &temp1,
43                         &temp2,
44                         &onStackChrominanceQuantTable,
45                         unzig.Data);
46                     prevDCCr = this.WriteBlock(
47                         QuantIndex.Chrominance,
48                         prevDCCr,
49                         &pixelConverter.Cr,
50                         &temp1,
51                         &temp2,
52                         &onStackChrominanceQuantTable,
53                         unzig.Data);
54                 }
55             }
56         }    
View Code

相关文章:

  • 2021-07-13
  • 2021-05-26
  • 2021-12-24
  • 2021-06-01
  • 2021-08-28
  • 2022-01-15
  • 2022-01-01
  • 2021-06-12
猜你喜欢
  • 2022-12-23
  • 2021-11-27
  • 2021-11-27
  • 2021-12-22
  • 2021-08-21
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案