视频之所以能动 原理其实就是咱们经常用的帧动画
将采集到的图片一帧帧组成连续播放的动画即构成视频中可视的部分
而我们需要采集的就是一张一张的 数字图像
这里又来了一个概念:数字图像
前面咱们讲过,数字音频,那同理,数字图像的概念也一样:
就是把你看到的图像用 01001010 这些计算机能看懂的二进制形式给你表达出来
一张数字图像是由一个包含若干个像素点的矩形框组成的
咱们可以随便在电脑上找一张图片(矢量图除外)
然后你把图片放大,不用无限放大,放大个几倍之后
你就可以看到图像是由很多很多个小格子组成的
而每个小格子都只有一种颜色,这是构成图像的最小单元 —— 像素(pixel)
说到 像素 就会想到 像素值,不同的像素值代表了不同的颜色
像素值的值域一般在 0 到 255 之间,也就是 256 个整数
但是!
这 256 个整数并不是代表图像中的彩色,而只是代表黑色到白色之间的灰度值
那这个彩色是由什么代表呢?
这个咱们就得说到颜色这个概念了
那大家考虑过没,为什么有颜色呢?或者我们为什么看到的这个世界是五彩斑斓的呢?
官方说法是颜色或色彩是通过眼、脑和我们的生活经验所产生的一种对光的视觉效应
简单点说,颜色就是人对光的一种感觉,由大脑产生的一种感觉
人的视网膜上布满了感光细胞,当有光线传入人眼时,这些细胞就会将刺激转化为视神经的电信号
最终在大脑得到解释,形成了我们熟悉的色彩
这些感光的细胞,学名:视锥细胞 和 视杆细胞
大都集中在视网膜的中央,每个视网膜大概有700万个左右
视锥细胞一共分三种:
S类型视锥细胞、M类型视锥细胞、L类型视锥细胞
每种视锥细胞里面分别含有对红、绿、蓝三种光线敏感的感光色素,就是说分别对红、绿、蓝三种光敏感
这三种类型有啥作用呢?
这类细胞能在较明亮的环境中提供辨别颜色和形成精细空间视觉的功能!
分散分布在视网膜上,每个视网膜大概有1亿个以上
这类细胞对光线更为敏感(敏感程度是视锥细胞的100多倍),一个光子就足以激发它的活动
视杆细胞不能感受颜色、不能分辨精细的空间
但它能在较弱的光线下可以提供对环境的分辨能力
比如夜里看到物体的黑白轮廓
那假设
当一束光线进入人眼后,视神经细胞会产生4个不同强度的信号:
三种视锥细胞的信号(S、M、L)和一个视杆细胞的信号
这其中,只有视锥细胞产生的信号能转化为颜色的感觉
三种视锥细胞 S、M、L 对波长长度不同的光线会有不同的反应
每种细胞对某一段波长的光会更加敏感
这些信号的组合就是人眼能分辨的颜色的总和,也就是你能看到的所有的颜色
三种视锥细胞对单色光谱刺激的反应如图所示:
横坐标为光的波长,纵坐标为产生信号的强度
可以看到
S类型细胞对450左右波长的光很敏感,一受刺激就产生了那么大的信号强度
M类型细胞对550左右波长的光很敏感
L类型细胞对600左右波长的光很敏感
那咱们就看一下450,550,600的光长啥样,来看下光谱图:
能够引起视锥细胞活动的光波长范围是 312.3nm 至 745.4mn
这也就是可见光的范围
但这只是可见光的波长范围,光可并不是只有这一段范围
像紫光再往左的部分叫什么光?
– 紫外线!
红光再往右的部分叫什么光?
– 红外线!
这个和上面咱们所说的声学知识其实是一样
像低于20HZ的声波 咱们叫它 次声波
像高于2WHZ的声波 咱们叫它 超声波
道理都差不多
所以,人们之所以能看到五彩斑斓的世界,就是因为
当一定波长的光线照射到视网膜时,会以一定的比例使三种视锥细胞分别产生不同程度的兴奋
这样的信息传至中枢,就产生某一种颜色的感觉
那么基于这个生理结构,人们得出来一个重要的理论:
就是可以用3种精心选择的单色光来刺激视锥细胞,模拟出人眼所能感知的几乎所有的颜色
这三种颜色就是咱们上美术课的时候讲的"三原色":红、绿、蓝
比如:
用红绿光的混合光去刺激视锥细胞,和你用单色黄光去刺激视锥细胞,它产生的视神经信号是等效的
这也就是说,红绿光的混合光就是黄色光
同理,看看下图也知道,什么和什么光 生成什么样式的光
这就是三色加法模型,就是基于你的生理因素产生的
说完了像素、像素值、也说完了像素的颜色
数字图像既然是由一个个像素组成的,那么图像的采集和存储也就是这个一个个像素的采集和存储
那么像素是怎么采集和存储的呢?
下面就说两种像素的采集存储格式:
RGB、YUV
咱们上面说到三原色
这个 RGB色彩空间 就是三原色的一种表达形式
即 用<font color=red>R(Red)</font>、<font color=green>G(Green)</font>、<font color=blue>B(Blue)</font> 这三种颜色来编码 去展示咱们想要看到的彩色像素
Android童鞋应该很熟悉哈
咱们搭建UI界面的颜色色值就是通过RGB形式展现的
它由 一个字节(8bits) 代表一个颜色,三种颜色共需要 三个字节
例如 #FF0000代表红色、#00FF00代表绿色、#0000FF代表蓝色
就是存储每个像素点的R值、G值、B值
那么大家算一下,RGB这种方式一共能存储多少种颜色呢?
公式也很简单
256 * 256 * 256 = 16,777,216 种颜色
因此也简称为 1600万色,也被称为 24位色(占用24bit)
这个颜色范围已经超过了人眼可见的全部色彩,所以又叫真彩色
再高的话,对于我们人眼来说,已经没啥意义了,你也识别不出来
RGB颜色的几何立体模型如下:(任何一个颜色在该立体模型中都能找到其对应的点)
在彩色显示器还没有发明的时候,人类已经懂得使用三原色光调配出所有颜色的光
但这并不是说三原色混合后产生了新的频率的光,而是给人眼睛的感觉是这样,这点别搞错了!
而在显示器发明之后,从黑白显示器发展到彩色显示器人们开始使用发出不同颜色的光的荧光粉、不同颜色的滤色片、不同颜色的半导体发光器件来形成色彩
但无一例外的都选择了Red、Green、Blue这3种颜色的发光体作为基本的发光单元
通过控制他们发光强度,组合出了人眼睛能够感受到的大多数的自然色彩
而到了计算机中,显示彩色图像的时候也不例外,最终在要显示的时候
控制一个个像素中Red、Green、Blue的值,来确定这一个个像素的颜色
第二种格式呢,就是YUV色彩空间
这里说一下,既然有RGB了,为啥还要再发明一个YUV去储存像素呢?
这就涉及到一个体积的问题了 咱们先算个账
大家都知道视频体积很大,一部电影一般都在两个小时左右
那咱们假设一个小时的高清视频(1920 * 1080)
如果使用RGB格式去存储,假定视频的帧率为25FPS(一秒播放25帧画面):
1h * 60 *60 * 25 * 1920 * 1080 * 3Byte = 559.9G Byte
一个小时的高清视频,占了560G,那没法往下玩了,体积也太大了
于是乎,就诞生了另一个的存储格式:YUV
人们通过实验发现,就这个人的眼睛呀,天生就对亮度敏感,而对色度不敏感
因此有一种思路就是可以将图像的亮度信息和颜色信息分离开来,
并使用不同的分辨率进行存储!
亮度不是敏感嘛!那就是用和原来一样的分辨率去存储
色度不敏感嘛!就使用低分辨率去存储,非常狠地去压缩它!
这样可以在对主观感觉影响很小的前提下,更加有效的存储图像数据,从而提高压缩效率,减少体积
那咱们就来看一下这个 YUV格式
YUV中的Y只代表亮度信息,U和V只代表色度
YUV只靠 Y数据就可展现黑白图像
在早期技术不发达的时候,照片打印和电视播放都只能实现黑白画面显示,所以Y数据就成了那时候的标准
之后才有了彩色打印和彩色电视,但是为了兼容之前的黑白数据,你总不能有了彩色的,把之前人家用的黑白设备全都不管了吧
厂商就发明了 UV 数据,把它加到 Y 的后面
这样呢,YUV加在一起就可以实现彩色,而且一套数据格式同时兼容了黑白设备和彩色设备
如果你没钱买新的,还是使用黑白电视,就单独使用Y 不用管UV即可,画面还是原来的黑白
如果你买了新的彩色电视机,那就可以读取全部数据去展示彩色画面了
可以有一张图来直接的了解一下YUV,这个YCbCr也是YUV,后面会讲到这个
可以看到这个Y图的分辨率就很高,但是这个UV图就不那么清晰了
小小的总结一下:
RGB 将一个颜色拆解为 3个纯色的亮度组合
YUV将一个颜色分解为一个亮度和2个色度的组合
对于图像显示器来说,它是通过RGB模型来显示图像的
⽽在传输时为了节省带宽 ⼜是使⽤YUV模型去传输图像数据
因此就需要在采集图像的时候需要将RGB模型转换到YUV模型,而在显示的时候再将YUV模型转换为RGB模型
不论OpenGL还是iOS,都不支持直接渲染YUV数据,底层都是转为RGB
RGB 和 YUV 的转换,它是有公式的
简单来说就是将图像像素点的R、G、B分量转换到Y、U、V分量
转换公式我这里贴一下:
Y = 0.299 * R + 0.587 * G + 0.114 * B
U = -0.147 * R - 0.289 * G + 0.436 * B
V = 0.615 * R - 0.515 * G - 0.100 * B
R = Y + 1.14 * V
G = Y - 0.39 * U - 0.58 * V
B = Y + 2.03 * U
上面的一些常数,叫做权重因数
可以看到,各个权重因数的大小是不一样的
当然,这些权重因子也不是不能改变的,在各个标准下 权重因子都不一样
后来国际无线电咨询委员会制定的一套标准
1982年CCIR制定了彩色视频数字化标准,称为CCIR 601标准,现改为ITU-R BT.601标准
该标准规定了彩色视频转换成数字图像时使用的采样频率,RGB和YCbCr两个彩色空间之间的转换关系等
便于国际间的节目交换,消除数字设备之间的制式差别,不同电视系统之间兼容,推动数字电视广播系统参数统一化、标准化!
有兴趣的可以研究一下
那 YUV 到底是怎么压缩的呢?
YUV主流的采样方式有 YUV4:2:2、YUV4:1:1、YUV4:2:0
下面用图解的方式说明一下:
YUV422:(每两个Y共用一组UV分量)
未采样前:
第一行四个像素为: [Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]
采样之后:
采样之后的像素为: [Y0 U0 ] [Y1 V1] [Y2 U2 ] [Y3 V3]
还原之后:
还原后的像素点为: [Y0 U0 V1] [Y1 U0 V1] [Y2 U2 V3] [Y3 U2 V3]
压缩率更高的 YUV411:
未采样前:
第一行四个像素为:[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]
采样之后:
第一行采样像素为:[Y0 U0 ] [Y1 ] [Y2 V2] [Y3 ]
还原之后:
还原之后的像素: [Y0 U0 V2] [Y1 U0 V2] [Y2 U0 V2] [Y3 U0 V2]
压缩率更更高的 YUV420:(每四个Y共用一组UV分量)
未采样前:
第一行四个像素为:[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]
第二行四个像素为:[Y4 U4 V4] [Y5 U5 V5] [Y6 U6 V6] [Y7 U7 V7]
它指得是对每行扫描线来说,只有一种色度分量以 2:1 的抽样率存储
相邻的扫描行存储不同的色度分量, 也就是说,如果一行是 4:2:0 的话,下一行就是4:0:2
第一行采样像素为:[Y0 U0 ] [Y1 ] [Y2 U2 ] [Y3 ]
第二行采样像素为:[Y4 V4] [Y5 ] [Y6 V6] [Y7 ]
还原之后的像素:
[Y0 U0 V4] [Y1 U0 V4] [Y2 U2 V6] [Y3 U2 V6]
[Y4 U0 V4] [Y5 U0 V4] [Y6 U2 V6] [Y7 U2 V6]
可以看到,不论哪种采样压缩,这个 Y 值是不能动的!
上文中提到过 YCbCr 最后咱们就来说一下这个:
YUV 来源于 RGB,YCbCr 来源于 YUV
其实它就是YUV经过缩放和偏移的翻版,可以理解成它的压缩版本
其中 Y 与 YUV 中的 Y 含义一致, Cb , Cr 同样都指色彩, 只是在表示方法上不同而已
不同之处在于Y’CbCr用于数字图像领域,YUV用于模拟信号领域
除此之外它俩其实没啥区别
一般人们所讲的YUV,或者在很多技术文档中的YUV 大多是指 YCbCr
可以简单了解下这个Y’=0.5时,Cb、Cr构成的颜色平面:
音频的编码咱们上面说了
这次来看看图像的编码
编码是什么?
为什么要对视频进行编码呢?
咱们还是再来举个例子:
今天的例子有点多
先来上个图,大家也很熟悉:
之所以会有视频编码,关键就在于:体积!
一个视频,如果未经编码,它的体积是非常非常非常庞大的
可能这么说你没有一个概念,咱们还是拿数据来说话,再给它算一遍:
以一个分辨率1920×1280,帧率30的视频为例:
共:1920 × 1280 = 2,073,600(Pixels 像素),每个像素点是24bit(三个字节)
也就是:每幅图片2073600 × 24 = 49766400 bit,8 bit(位) = 1 byte(字节);
所以:49766400bit = 6220800byte ≈ 6.22MB
而这可是一帧 1920×1280 图片的大小呀朋友们,再乘以帧率30
帧率30就是一秒播放30张图片(后续会讲到)
那也就是说:
每秒视频的大小是6.22 * 30 = 186.6MB,每分钟大约是11GB,一部90分钟的电影,约是1000GB。。。
这个不敢想呀
就算你现在电脑硬盘是4TB的 (实际也就3600GB),
根本放不下几部苍老师啊!
这还仅仅要存储,这还没考虑到下载(传输)呢
如果按照100M的网速(12.5MB/s),下刚才那部电影,需要22个小时。。。
你看个偶像的电影 你下载一天,这谁不崩溃。。。
正因为如此,这些追星(屌丝)工程师们就提出了,必须!必须!
必须得对视频进行编码!
所以编码就是为了压缩
要实现压缩,就要设计各种算法,将视频数据中的冗余信息去除
现在考你一下:
给你一张图片,或者给你一段视频,让你想一想,如果是你,你会如何进行压缩呢?
或者有什么思路呢?
福利时间,召唤女神:
石原姐姐!当初听到她结婚的消息心都稀碎了!
~都前尘往事了,不聊这个
你们会怎么压缩呢?
不了解你们,反正我是1bit都舍不得压缩
没思路的也别着急
咱们来看几个例子开发下思路:
来看一张图:
假如这张图是 1920 × 1080 分辨率,全是红色的,就这张图来讲
有没有必要说:我要去存储2073600个 [255, 0, 0] ?
肯定没这必要吧!
因为我只要存一次[255, 0, 0],剩下的那2073599次直接“同上”就可以了是吧
那咱们再假设说
如果一段1分钟的视频,其中有十几秒时间内画面是不动的;
或者这个视频中有80%的图像面积,整个过程都是保持不动的
那么,那你说我还用不用把一帧一帧所有的图片上面的所有像素都存下来?
你看上图中的墙面,木桶,还有这桌子等等!
它们都是保持不动的
那这块存储开销,我要是不节约掉,那不就脑残了嘛!
这上面的都是属于视频中的冗余信息
那还有其他的冗余信息吗?
有!
一般来说,视频中的冗余信息分类如下:
种类 | 内容 | 压缩方式 |
---|---|---|
空间冗余 | 像素之间的相关性 | 变换编码,预测编码 |
时间冗余 | 时间方向上的相关性 | 帧间预测,运动补偿 |
图像构造冗余 | 图像本身的构造 | 轮廓编码,区域分隔 |
知识冗余 | 收发两端对人物的共有认识 | 基于知识的编码 |
视觉冗余 | 人的视觉特性 | 非线性量化,位分配 |
其他 | 充数的 |
而视频编码的技术最看重的,也就是最最优先要消除的,就是上面的 空间冗余 和 时间冗余
那咱们就来看下这两个 空间冗余 和 时间冗余
其他的“不重要”就先略过了(其实是我不了解)
首先是 空间冗余:
它说的是像素之间的相关性,这个很好理解
就是咱们上面的那张全是红色的图片嘛!
那它是怎么处理的呢?
在一幅图像中,首先咱们先来假设图片中的画面都是有意义的,你不能说这里面的信息没意思,直接给人家无理由删了
比如一个人的照片,图像中的背景在某个局部位置有可能是非常相似的
那么这个区域的相似性就是空间冗余
而我们就可以利用某一个最具代表性的局部画面或者一个点来代替其他的画面或者点。
比如,有连续的一系列白点,那么它们的值都是255左右,我们只需要知道第一个是255,其他的都和它一样就可以了
对应的这种在一张图像中进行的编码压缩的方式,叫做帧内编码
再来是 时间冗余:
通俗地讲,也就是前后两幅图像相似性很大
视频是一帧一帧的图片构成,如果两帧或者多帧之间的画面中的内容几乎没有变化
那么你完全可以通过告知第二副图片和第一副图片的差别来表示第二副图像
这样第二副图像就不需要完整的存储了
如图所示:
这里牵扯出了一些帧概念:I帧、P帧
大家都知道视频是由不同的帧画面连续播放形成的,比如 25FPS
意思就是一秒钟连续播放25张图片,叫做 帧率
这个也就是咱们打游戏常说的 FPS
但是这25张图片并不是简单的堆叠到一块的,它们也不是把整张图片完整的都存储起来
而是分成了 I、P、B 三种类型的图片 分别是:
I帧、B帧、P帧
I帧:
是自带全部信息的独立帧,是最完整的画面(占用的空间最大)
无需参考其它图像便可独立进行解码,它自己就可以进行解码
它是关键帧,一秒钟25张图片里面,可能就只有五张关键帧(视频序列中的第一个帧,始终都是I帧)
P帧:
“帧间预测编码帧”,需要参考前面的 I帧 和 P帧 的不同部分,才能进行编码,它不能进行独立解码
P帧对前面的 P 和 I 参考帧有依赖性
但是,P帧压缩率比较高,占用的空间较小
B帧:
“双向预测编码帧”,以前帧后帧作为参考帧
不仅参考前面,还参考后面的帧,所以,它的压缩率最高,可以达到200:1
不过,因为依赖后面的帧,所以不适合实时传输(例如视频会议)
那来总结一下:
通过 I B P 三种图片格式,不仅记录了完整帧的全部信息,也记录了帧与帧之间区别,帧与帧之间的特征
然后在回放的时候,通过算法去实时的计算出来
比如:一秒钟记录了五张完整的关键帧,其他剩余的20残缺的帧通过帧与帧之间区别,帧与帧之间的特征,在回放的时候 实时的去计算出来
对应的这种在不同图像之间进行的编码压缩的方式,叫做帧间编码
我在网上找了个例子
来通过这个例子咱们来看一下:
这里有两个帧:
能看出有什么不一样吗吗?
好像是一样的
那把它俩做个GIF动图:
可以看到,人在动,背景是没有在动的
第一帧就可以做成一个I 关键帧,第二帧就可以做成P帧
两个帧之间的差值,就是如下:
也就是说,图中的部分像素,进行了移动
移动轨迹如下:
这个,就是 帧间编码 中的 运动估计和补偿
在这里总结一下 帧内编码 和 帧间编码 的优缺点:
帧间编码:
记录关键帧,回放的时候通过关键帧去生成其他的帧,这种方式有个不好的地方就是
你的算法再优秀,其他的帧信息也是根据关键帧去凭空捏造出来的
和当时拍摄的原始的图像信息还是会有一定的区别,所以在画质上也有一定程度的下降
但是这种方式压缩出来的文件,体积比较小,更加适合网络传播
像 H264、H265 这种编码方式,就采用了帧间编码 在后期回放的时候
它需要CPU大量运算,所以如果电脑配置不好的话,它就会容易卡
帧内编码:
它是记录所有帧信息,然后去压缩每一帧图像,只是在每一帧之内
去压缩本帧的图像,而跟其他帧没有任何的关联
它是近乎无损的,它是记录了每一帧图像的完整信息,它只是对每一帧的图像的本身进行压缩
这个就有点像我们电脑上的zip、rar等方式,你压完了,然后我再解压出来的东西,和原来的是一摸一样的
但是这种方式压缩出来的文件,体积比较大,画质比较好,再回放的时候会特别流畅
它不需要通过计算机的CPU、GPU去运算出来其他帧图像,它仅仅只是按照顺序,一帧一帧去播放下去就行了,对后期剪辑软件也比较友好
就像苹果的 ProRes 格式编码就是帧内压缩,全部都是帧内压缩,它的整个回放就特别流畅,但是它的文件体积就会非常大
而视频的编码,就是应用了上表中的一系列去除冗余信息的方法:
空间冗余、时间冗余、图像构造冗余、知识冗余、视觉冗余等,诞生了很多的编码格式:
常见的编码格式有:H.264、QuickTime、ProRes、MPEG系列等,其实原理都跟咱们上面讲的一样
目前最常用的两种编码:H.264 和 ProRes 编码
如果你的视频最终是上传到网络平台,或者给其他人播放,H.264是最佳的选择
如果你想创建一个比H264画质更高的存档,画质接近无压缩,但是对体积又没有严苛的要求,首选ProRes
当然,编码不仅仅是这些,还有很多
比如更先进的H.265,它的压缩率跟画质更先进,体积更小巧,但是它对播放载体的解码能力要求更高,普及率很低
这里再说一下 封装格式 吧,我感觉容易混淆
而且我这段时间去网上搜资料的时候,经常看到 封装格式 和 编码格式 傻傻分不清楚
应该也是代表了一部分人的疑惑,我在这里讲一下这个:
封装格式 只是 视频的一个外壳,你可以把它理解成一个容器,一个箱子:
箱子里面装了视频图像、音频、字幕等信息,封装格式的功能只是简单的把这些信息打包起来
像 MP4(最佳网络传输格式)、MOV(苹果开发格式)、AVI(微软开发格式)、WMV(微软开发格式)、MKV
现在最常用的就是MP4、MOV
视频文件名后面加的这些后缀,就是 视频的封装格式!
而编码格式,就是咱们现在说的这个
它负责生成通过先进的压缩算法技术 去压缩生产箱子中的 视频画面、音频信息
就是说,封装格式箱子种的视频图像、音频、字幕等信息,就是编码格式生产出来的
简单来说,就是一个是容器,一个是技术