做淘宝客如何建自己的网站,国外市场网站推广公司,wordpress打赏工具,怎么在云服务器上搭建网站说到视频#xff0c;我们首先想到的可能就是占内存。我们知道一个视频是由一连串图像序列组成的#xff0c;视频中图像一般是 YUV 格式。假设有一个电影视频#xff0c;分辨率是 1080P#xff0c;帧率是 25fps#xff0c;并且时长是 2 小时#xff0c;如果不做视频压缩的…说到视频我们首先想到的可能就是占内存。我们知道一个视频是由一连串图像序列组成的视频中图像一般是 YUV 格式。假设有一个电影视频分辨率是 1080P帧率是 25fps并且时长是 2 小时如果不做视频压缩的话YUV 420格式它的大小是 1920 x 1080 x 1.5 x 25 x 2 x 3600 521.4G如果是在视频通话场景下的话按照这个大小去传输视频数据对流量和带宽资源的消耗也是非常大的并且如此大的数据发送对网络要求也非常高很显然我们是接受不了的。因此做视频编码压缩就非常有必要。 什么是编码 编码就是按指定的方法将信息从一种形式格式转换成另一种形式格式。视频编码就是将一种视频格式转换成另一种视频格式。编码的目的通常是为了减少文件大小。
视频编码原理
频编码是对一帧帧图像来进行的。一般我们所熟知的彩色图像的格式是 RGB 的即用红绿蓝三个分量的组合来表示所有颜色。但是RGB 三个颜色是有相关性的为了去掉这个相关性减少需要编码的信息量我们通常会把 RGB 转换成 YUV也就是 1 个亮度分量和 2 个色度分量。另外人眼对于亮度信息更加敏感而对于色度信息稍弱所以视频编码是将 Y 分量和 UV 分量分开来编码的。另外人眼对于亮度信息更加敏感而对于色度信息稍弱所以视频编码是将 Y 分量和 UV 分量分开来编码的。 图像一般都是有数据冗余的主要包括以下 4 种 空间冗余。一帧图片的内容往往存在大量相似的内容。如果将一帧图像划分成一个个 16x16 的块之后相邻的块很多时候都有比较明显的相似性这种就叫空间冗余。 如上面这张图片天空是蓝色的一大片若果把它划分成一个一个的小块区域那么相邻的区块之间的差别是比较小的特别是天空部分。 时间冗余。一个帧率为 30fps 的视频中前后两帧图像相差只有 33ms两张图像的变化是比较小的相似性很高这种叫做时间冗余。 如上图假设是视频流中的两帧图片图片的背景都一样只是小车在移动。那么这两帧图片大部分内容都是相同只是小车的位置不一样这个就是时间冗余。 视觉冗余。我们的眼睛是有视觉灵敏度这个东西的。人的眼睛对于图像中高频信息的敏感度是小于低频信息的。有的时候去除图像中的一些高频信息人眼看起来跟不去除高频信息差别不大这种叫做视觉冗余。 信息熵冗余。我们一般会使用 Zip 等压缩工具去压缩文件将文件大小减小这个对于图像来说也是可以做的这种冗余叫做信息熵冗余。
对于一个 YUV 图像H264把它划分成一个个 16x16 的宏块Y、U、V 分量的大小分别是 16x16、8x8、8x8。这里我们只对 Y 分量进行分析U、V 分量同理。假设 Y 分量这 16x16 个像素就是一个个数字我们从左上角开始之字形扫描每一个像素值则可以得到一个“像素串”。如下图所示
我们来看一个LeetCode编程题 字符串压缩 字符串压缩。利用字符重复出现的次数编写一种方法实现基本的字符串压缩功能。比如字符串aabcccccaaa会变为a2b1c5a3。 将 “aabcccccaaa” 压缩成 “a2b1c5a3”字符串由 11个字节压缩到 78个字节这个叫做行程编码。如果我们对图像宏块扫描出来的这个“像素串”做同样的行程编码操作是不是也有可能减小图像块呢 在对“像素串”行程编码之前我们先回过头来看看另一个行程编码的例子。如果刚才编程题的字符串是 “abcdabcdabcd” 的话那么编码之后就会是 “1a1b1c1d1a1b1c1d1a1b1c1d”。字符串的大小从 13 字节变成了 25 字节还变大了。
我们发现如果想要达到压缩的目的我们必须要使得编码前的字符串中出现比较多连续相同的字符。这对于图像块也是一样的。我们需要使得扫描出来的“像素串”也尽量出现连续相同的像素值最好是一连串数字很小比如 0的“像素串”因为 0 在二进制中只占 1 个位就可以了。这个地方你可能会有疑惑0 也是至少要一个字节存储需要 8 个位怎么会是 1 个位呢这个有的编码算法是可以做到的比如指数哥伦布编码它就可以做到 0 只占用一个位。事实上算术编码可以做到一个符号只占用 0 点几个位连一个位都不用这里不详细展开
那我们如何做到将这串像素值变成有很多 0 的“像素串”呢首先第一步我们通过减少图像块的空间冗余和时间冗余来接近这个目标。刚才我们也说到图像内部相邻宏块之间有很多相似性并且两张图像之间也有很多相似性。因此根据图像的这个特点我们可以在编码的时候进行帧内预测和帧间预测。
帧内预测就是在当前编码图像内部已经编码完成的块中找到与将要编码的块相邻的块。一般就是即将编码块的左边块、上边块、左上角块和右上角块通过将这些块与编码块相邻的像素经过多种不同的算法得到多个不同的预测块。 然后我们再用编码块减去每一个预测块得到一个个残差块。最后我们取这些算法得到的残差块中像素的绝对值加起来最小的块为预测块。而得到这个预测块的算法为帧内预测模式。 由于这个残差块中像素的绝对值之和最小这个残差块的像素值经过扫描之后的“像素串”是不是就比直接扫描编码块的“像素串”中的像素值更接近 0 了 同理帧间预测也是一样的。我们在前面已经编码完成的图像中循环遍历每一个块将它作为预测块用当前的编码块与这个块做差值得到残差块取残差块中像素值的绝对值加起来最小的块为预测块预测块所在的已经编码的图像称为参考帧。
预测块在参考帧中的坐标值 (x0, y0) 与编码块在编码帧中的坐标值 (x1, y1) 的差值 (x0 - x1, y0 - y1) 称之为运动矢量。
而在参考帧中去寻找预测块的过程称之为运动搜索。事实上编码过程中真正的运动搜索不是一个个块去遍历寻找的而是有快速的运动搜索算法的。之后我们在帧间预测的课中会详细介绍。总之通过预测得到的残差块的像素值相比编码块的像素值去除了大部分空间冗余信息和时间冗余信息这样得到的像素值更小。如果把这个残差块做扫描得到的像素串送去做行程编码是不是相比直接拿编码块的像素串去做编码更有可能得到更大的压缩率
但是我们的目标不只是将像素值变小而是希望能出现连续的 0 像素那怎么办呢这就需要利用我们人眼的视觉敏感性的特点了。我们刚才说了人眼对高频信息不太敏感。因为人眼看到的效果可能差别不大所以我们可以去除一些高频信息。这个就是接下来我们要讨论的 DCT 变换和量化。
为了分离图像块的高频和低频信息我们需要将图像块变换到频域。常用的变换是 DCT 变换。DCT 变换又叫离散余弦变换。在 H264 里面如果一个块大小是 16x16 的我们一般会划分成 16 个 4x4 的块当然也有划分成 8x8 做变换的我们这里以 4x4 为例。然后对每个 4x4 的块做 DCT 变换得到相应的 4x4 的变换块。变换块的每一个“像素值”我们称为系数。变换块左上角的系数值就是图像的低频信息其余的就是图像的高频信息并且高频信息占大部分。低频信息表示的是一张图的总体样貌。一般低频系数的值也比较大。而高频信息主要表示的是图像中人物或物体的轮廓边缘等变化剧烈的地方。高频系数的数量多但高频系数的值一般比较小注意不是所有的高频系数都一定小于低频只是大多数高频系数比较小。如下图所示黄色为低频绿色为高频 这样做完了 DCT 变换之后低频和高频信息就分离开来了。由于低频信息在左上角其余的都是高频信息。那么如果我们对变换块的像素值进行“之字形”扫描这样得到的像素串前面的就是数值比较大的低频系数后面就是数值比较小的高频部分。由于人眼对高频信息不太敏感如果我们通过一种手段去除掉大部分高频信息也就是将大部分高频信息置为 0但又不太影响人的观感是不是就可以达到我们最初的目标即可以得到有一连串 0 的像素串这就涉及到量化操作了。我们让变换块的系数都同时除以一个值这个值我们称之为量化步长也就是 QStepQStep 是编码器内部的概念用户一般使用量化参数 QP 这个值QP 和 QStep 一一对应你可以自行去网上查询一下转换表得到的结果就是量化后的系数。QStep 越大得到量化后的系数就会越小。同时相同的 QStep 值高频系数值相比低频系数值更小量化后就更容易变成 0。这样一来我们就可以将大部分高频系数变成 0。如下图所示 解码的时候我们会将 QStep 乘以量化后的系数得到变换系数很明显这个变换系数和原始没有量化的变换系数是不一样的这个就是我们常说的有损编码。而到底损失多少呢这由 QStep 来控制QStep 越大损失就越大。QStep 跟 QP 一一对应也就是说确定了一个 QP 值就确定了一个 QStep。所以从编码器应用角度来看QP 值越大损失就越大从而画面的清晰度就会越低。同时QP 值越大系数被量化成 0 的概率就越大这样编码之后码流大小就会越小压缩就会越高。以上就是视频编码的推理过程。总结一下就是为了能够在最后熵编码的时候压缩率更高我们希望送到熵编码以行程编码为例的“像素串”是一串含有很多 0并且最好连续为 0 的“像素串”。为了达到这个目标我们先通过帧内预测或者帧间预测去除空间冗余和时间冗余从而得到一个像素值相比编码块小很多的残差块。之后我们再通过 DCT 变换将低频和高频信息分离开来得到变换块然后再对变换块的系数做量化。由于高频系数通常比较小很容易量化为 0同时人眼对高频信息不太敏感这样我们就得到了一串含有很多个 0大多数情况下是一串含有连续 0 的“像素串”并且人的观感还不会太明显。这样最后熵编码就能把图像压缩成比较小的数据以此达到视频压缩的目的。这就是视频编码的原理。
总结
本文主要讲了视频编码的必要性以及视频编码的原理。视频编码主要分为熵编码、预测、DCT 变换和量化这几个步骤。
熵编码以行程编码为例视频编码中真正实现“压缩”的步骤主要去除信息熵冗余。在出现连续多个 0 像素的时候压缩率会更高。帧内预测为了提高熵编码的压缩率先将当前编码块的相邻块像素经过帧内预测算法得到帧内预测块再用当前编码块减去帧内预测块得到残差块从而去掉空间冗余。帧间预测类似于帧内预测在已经编码完成的帧中先通过运动搜索得到帧间预测块再与编码块相减得到残差块从而去除时间冗余。DCT 变换和量化将残差块变换到频域分离高频和低频信息。由于高频信息数量多但大小相对较小又人眼对高频信息相对不敏感我们利用这个特点使用 QStep 对 DCT 系数进行量化将大部分高频信息量化为 0达到去除视觉冗余的目的。
参考编码原理