JPEG 编码过程:为 GPU 处理开路

图片平台上承接了巨量的图片每天需要针对几十亿的图像进行处理,由于JPEG格式是存储系统中存储最多图像格式,而JPEG格式编解码以及处理中都是大量的数据计算,GPU较于CPU具有更强大的数据并行计算的能力。于是研究利用GPU来加速处理图像编解码以及图像处理, 为此很有必要先了解JPEG的的编解码过程。

文章参考了大量外部资料,引用了相关的图片以及数据,所涉及到的内容或者原理都有相应的链接跳转以供查询。

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处理的图像

DCT变换

这里有两张傅里叶变换的经典图像:

鉴于图像在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树对数据进行解码。

GPU并行性考量

上述过程中DCT变换过程,数据量化过程以及后续的huffman数据编码过程都是以MCU为单位,这些过程应该都能够进行并行化处理。来获取一定的处理加速。

后续将分析图像缩放以及解码过程,考虑通过并行化以获取加速的可能。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据派THU

机器学习和深度学习视频资料精选(附学习资料)

来源:大数据挖掘DT数据分析 本文长度为633字,建议阅读3分钟。 本文为你介绍机器学习和深度学习的视频资料。 第一部分 基础语言 pandax视频教程链接: ...

5988
来自专栏机器人网

深度学习三要素:数据、模型、计算

数据来源:主要通过对初始数据图片进行人工标注和机器标注。数据样本非常的重要,好的样本等于成功了一半。

732
来自专栏Python小屋

Python使用扩展库numpy计算矩阵加权平均值

本文介绍Python扩展库numpy的函数average()的用法。 >>> import numpy as np # 创建二维矩阵 >>> x = np.ma...

2775
来自专栏CreateAMind

运动信息向量的神经网络学习 code、ppt、视频

官方代码还未开放, http://visualdynamics.csail.mit.edu/

1013
来自专栏mathor

“达观杯”文本智能处理挑战赛

 由于提供的数据集较大,一般运行时间再10到15分钟之间,基础电脑配置在4核8G的样子(越消耗内存在6.2G),因此,一般可能会遇到内存溢出的错误

1212
来自专栏AI派

如何使用sklearn进行在线实时预测(构建真实世界中可用的模型)

Python 作为当前机器学习中使用最多的一门编程语言,有很多对应的机器学习库,最常用的莫过于 scikit-learn 了。我们介绍下如何使用sklearn进...

1033
来自专栏AI科技大本营的专栏

重磅消息 | 深度学习框架竞争激烈 TensorFlow也支持动态计算图

今晨 Google 官方发布消息,称 TensorFlow 支持动态计算图。 原文如下: 在大部分的机器学习中,用来训练和分析的数据需要经过一个预处理过程,输入...

2625
来自专栏AI研习社

Github 推荐项目 | GloVe 的快速实现 —— Mittens

该软件包包含 GloVe 和 Mittens 的快速 TensorFlow 和 NumPy 实现。

1313
来自专栏AI研习社

Github 项目推荐 | 用 TensorFlow 实现的模型集合

该库包含了大量用 TensorFlow 实现的不同模型。 官方模型(official models) 文件里是使用 TensorFlow 高级 API 的示例模...

3206
来自专栏华章科技

机器学习和深度学习视频资料精选(附学习资料)

pandax视频教程 链接: https://pan.baidu.com/s/1pLqavVX 密码: fath python入门到精通 链接: http...

1233

扫码关注云+社区