图片平台上承接了巨量的图片每天需要针对几十亿的图像进行处理,由于JPEG格式是存储系统中存储最多图像格式,而JPEG格式编解码以及处理中都是大量的数据计算,GPU较于CPU具有更强大的数据并行计算的能力。于是研究利用GPU来加速处理图像编解码以及图像处理, 为此很有必要先了解JPEG的的编解码过程。
文章参考了大量外部资料,引用了相关的图片以及数据,所涉及到的内容或者原理都有相应的链接跳转以供查询。
JPEG采用YCrCb的颜色模式,通常叫着YUV,其中Y代表亮度,Cr,cb代表色度和饱和度。而我们通常熟悉的计算机系统采用RGB颜色模式。从RGB颜色模式向YUV模式转换采用以下公式:
Y = 0.299R' + 0.587G' + 0.114B'
U = -0.147R' - 0.289G' + 0.436B'
V = 0.615R' - 0.515G' - 0.100B'
为何JPEG采用YUV格式编码呢?是因为亮度变换的敏感度要比对色彩变换的敏感度高出很多。因此采用YUV颜色模式能够将图像不太重要的信息进行抽离出来。采用不同的采样比例来达到减少存储数据的目的。
经过上述颜色空间转换后,我们就能得到Y、U、V三个分量上的三张表。
4:1:1采样为例,若在一个2x2的图像中。4:1:1采样即为:
Y: SHY=2 SVY=2
U: SHU=1 SVU=1
V: SHV=1 SVV=1
若2x2的rgb转换为YUV后图像编码表示为:
[Y0 U0 V0] [Y1 U1 V1]
[Y2 U2 V2] [Y3 U3 V3]
那么经过4:1:1采样后
[Y0 U0 V2] [Y1 U0 V2]
[Y2 U0 V2] [Y3 U0 V2]
数据存放为:
Y0 U0 Y1 Y2 V2 Y3
那么原图共占用12个字节,经过采样后仅需要6个字节。这里通过采样初步减少了图像大小。
数据采样完成后就需要进行下一步操作,进行空间域向频率域转换DCT变换。在空间域里处理图像有困难,就转到频率域来进行处理。为了进行DCT变换需要对图像码流进行分块。从码流中分别提取Y、U、V三个分量构成三张表。
JPEG 进行DCT变换时需要8x8的block为单元。而最小编码单元MCU是水平方向和垂直方向上采样最大值与8x8的乘积。那么4:1:1采样的mcu大小为16x16。
图像边缘在不满8x8时需要进行补齐,采用不同的补齐方式将会产生不同的影响。如采用全黑色进行补齐将产生振铃效应,在边缘较为锐利的文字型图像中较为容易发现。通常采用重复边缘上的数据来进行填充。 其次是图像在进行DCT变换时高频分量的丢失或者精度损失也造成振铃效应。
振铃效应图像对比:
振铃效应影响的图片 | IM处理的图像 |
---|---|
这里有两张傅里叶变换的经典图像:
鉴于图像在8x8的范围内相对的连续性,DCT变换能够将能量集中于低频部分,而高频部分信息肉眼不敏感,这样就使得后续对DCT变换后的矩阵进行量化减少高频信息成为可能。
DCT变换的强大威力示例:
经过DCT变换后得到的8x8矩阵,其中(0,0)位置称为直流分量,其他63个元素称为交流分量。
数据量化是针对DCT变换后得到的系数矩阵进行精度处理,使用DCT系数矩阵中的每一项分别于对应的量化矩阵位置处的值相除所得到的新矩阵为量化后的结果。JPEG分别针对Y亮度、UV色度和饱和度提供两张不同的量化表。因为人眼对亮度相对于色度更加敏感,所以亮度量化表精度较色度量化表更加精细。
亮度量化表 | 色度量化表 |
---|---|
而通常我们在进行JPEG质量调整时就是在量化表乘一个系数得到新的量化表。量化过程对于原图来说是一个有损的过程。这也就是JPEG实际图像质量无法超越原始图像的原因。
经过量化后的数据进一步缩小了数值范围,在右下角高频部分由于量化表系数较大很多图像在此部分形成了较多的0。而左上角低频部分保留了较多的肉眼敏感的数据。
一个8x8DCT变化后数据量化的示例:
针对量化后的数据需要从二维矩阵降维到一维的数组,方便进行数据编码。而由于矩阵呈现右下角数据更小更集中的趋势,在降维时采用了zigzag扫描算法。这样右下角的数据在一维空间中连续存放,有利于产生更多的0。对减少编码后图像大小提高压缩率有很好的帮助。
zigzag扫描过程:
上面数据经过zigzag扫描后行程这样的序列
经过zigzag扫描后的数据进行横向排布后得到这样的序列:
-26,-3,0,-3,-2,-6,2,-4,1,-3,1,0,5,1,2,-1,1,-1,2,0,0,0,0,0,-1,-1,0,0,0...,0
数据分为两部分,第一个数值为DC直流分量,对直流分量采用DPCM编码,因为该值通常较大,而相邻的8x8图像数据之间的差值变化不大。
针对AC系数序列进行RLE游程编码。是因为经过zigzag扫描后产生许多连续的0,RLE编码能够大幅减少0数据的空间占位。
再使用标准的huffman表对DC和AC编码后的数据进行huffman编码得到二进制序列。而使用huffman表编码时,针对DC直流分量和AC交流分量分别采用不同的huffman表。对YUV各个通道的编码也将采用不同的编码表。
欲了解上述数据如何进行RLE编码,再进行huffman编码可参考这篇文章JPEG算法解密(四),该文章详细的描述了游程编码过程以及从游程编码的结果进行huffman编码得到相应的存储二进制数据流。
数据编码完成后把用到的DHT表,huffman表以及其他一些数据信息,按规定格式写入到数据的头部。和编码后的数据合并起来就产生了一个JPEG文件。jpeg头部写入的huffman表。写入的是码字数量和编码内容,在解码时需要根据各个长度的码字数量结合编码内容来建立huffman树对数据进行解码。
上述过程中DCT变换过程,数据量化过程以及后续的huffman数据编码过程都是以MCU为单位,这些过程应该都能够进行并行化处理。来获取一定的处理加速。
后续将分析图像缩放以及解码过程,考虑通过并行化以获取加速的可能。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。