一、引言
笔者本人对音视频编码处理的基本概念基本上可以说是个白痴,在通过moviepy进行音视频处理时,发现帧数据就是一个大的numpy数组,很好奇这个数组的内容是什么,因此就到处找各种资料了解一些帧相关的基本概念,在这中间会发现“YUV”是个绕不过去的坎,但看了好多文章才理解这些相关概念的含义,在此写出来供各位与本人差不多的缺乏音视频基础知识的人士扫盲使用。
二、数字视频像素YUV编码格式
我们知道不同权重的R、G、B可以组成不同的颜色(又称为色调(hue)或色相,用于区别颜色的名称或种类,通常说的颜色七色即是指色调),但电视或视频的像素颜色表示不是使用的RGB来表示,而是使用的一种叫Y、U、V的维度来表示。
- Y表示亮度(Luminance或Luma),也称为灰阶值,是不同权重的R、G、B的组合值。实际上亮度是对颜色的明度(brightness)的一种度量,明度是指视觉系统对可见物体辐射或发光多少的感知属性,明度的一个极端是黑色没有光,另一个极端是白色,二者之间是灰色。明度很难度量,因此使用亮度(luminance)来度量,亮度(luminance)即辐射的能量。不同颜色的像素有不同的Y值,亮度信号可用来传送黑白图像,黑白视频只有Y(Luminance)视频,也就是灰阶值。
- UV色差信息:色彩信息可以表示为色差(Chrominance或Chroma),每一个色差表示了对应像素RGB值与Y的差,红色差=R-Y,蓝色差=B-Y。通过Y信息和色差信息就可以还原出RGB色彩信息。而UV信号(称为色度信号)是通过压缩红色差和蓝色差数值信号对视频频带高频端的色副载波进行调制而成的信号,经压缩后的蓝色差和红色差信号就称为U、V。UV信号告诉了显示器要偏移某象素的的颜色,而不改变其亮度。或者UV信号告诉了显示器使得某个颜色亮度依某个基准偏移。UV的值越高,代表该像素会有更饱和的颜色。
为什么色差信号能压缩呢?这是因为人类的视觉系统(HVS)对色度的敏感程度低于亮度,人眼对彩色细节的分辨能力远比对亮度细节的分辨能力低,这样就可以把几个相邻像素不同的彩色值当作相同的彩色值来处理,从而减少所需的存储容量和传输量。例如可以将相邻N个像素各自的Y值保留成N个不同的Y值,但它们可以共用一个相同的UV值,这种N+1的模式压缩了存储空间但还原RGB色彩后不影响人的感知。
不同的压缩方式对应不同的YUV编码格式,YUV细分的话有Y’UV,YUV,YCbCr,YPbPr等类型,这些YUV模型的区别主要在于UV数据的采样方式和存储方式。上述YUV编码类型中YCbCr主要用于数字信号,其中Y与YUV 中的Y含义一致, Cb , Cr 同样都指色彩, Cr反映了RGB输入信号红色部分与RGB信号亮度值之间的差异,而Cb反映的是RGB输入信号蓝色部分与RGB信号亮度值之间的差异,此即所谓的色差信号。一般所讲的YUV大多是指YCbCr。因此在数字图像处理中通常YUV指代YCbCr,JPEG、MPEG,H264均采用此格式。
YCbCr与RGB之间的换算公式如下:
Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
Cr = V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
Cb = U = -( 0.148 * R) - (0.291 * G) + (0.439 * B) + 128
与颜色相关的其他名词:
- 饱和度(saturation):指颜色的纯洁性,用来区别颜色的明暗程度,完全饱和的颜色是指没有渗入白光所呈现的颜色
- 光亮度(lightness):是人的视觉系统对亮度(luminance)的感知响应值,而明度仅限于发光体,用于描述反射或透射表面。
- 颜色空间:颜色空间是表示颜色的一种数学方法,人们用它来指定和产生颜色,使颜色形象化。颜色空间中的颜色通常使用代表三个参数的三维坐标来指定,这些参数描述的是颜色在颜色空间中的位置,但并没有告诉我们是什么颜色,其颜色要取决于使用的坐标。从技术上角度区分,颜色空间可分成如下三类:
- RGB型颜色空间/计算机图形颜色空间:这类模型主要用于电视机和计算机的颜色显示系统
- XYZ型颜色空间/CIE颜色空间:这类颜色空间是由国际照明委员会定义的颜色空间,通常作为国际性的颜色空间标准,用作颜色的基本度量方法
- YUV型颜色空间/电视系统颜色空间:由广播电视需求的推动而开发的颜色空间,主要目的是通过压缩色度信息以有效地播送彩色电视图像。关于YUV更多的介绍请参考《YUV格式初探》。
三、视频帧
我们知道数字视频播放是将一幅幅连续的静态图像按一定的频率快速切换所形成的图像流(可以称为视频流),这个播放频率即为fps(每秒播放的帧数),每个图像就称为视频的一个帧,在固定fps(帧率)播放速率情况下,在视频流中每个帧的位置可以通过时间作为位置来获取。
视频流存在两种形式,一种是没有基于流进行压缩的视频流,这种视频流是由YUV格式的图像组成,虽然YUV本身对应的帧有压缩但整个流没有压缩,这种流称为“原始流”或“YUV流”;另一种是基于流进行了压缩的视频流,称为“编码流”,又因为目前压缩/编码算法以H264为主,因此也常常称为“H264码流”。编码/压缩在流媒体领域是一项非常重要的技术:从“H264码流”到“YUV流”的过程称为解码,反之称为编码。对于视频编码/压缩而言,它的核心是采用尽量小的空间存储一组时间上连续的帧数据;而对于视频解码而言,就是把被编码/压缩后的一组帧数据尽量恢复成原来的样子,能够被100%恢复的编码/压缩算法称为无损压缩,反之称为有损压缩。
视频和帧相关的名词:
- 帧率(FPS)
FPS,全称Frames Per Second,指每秒传输的帧数,或者每秒显示的帧数,一般来说,FPS影响画面流畅度,且成正比:帧率越大,画面越流畅;帧率越小,画面越有跳动感。一个较权威的说法:当视频帧率不低于24fps时,人眼才会觉得视频时连贯的,称为“视觉暂留”现象。因此,才有说法:尽管『帧率』越高越流畅,但在很多实际应用场景中24fps就可以了。 - 分辨率(Resolution)
分辨率也常被俗称为“图像的尺寸”或者"图像的大小"。指一帧图像包含的像素的多少,常见有1280x720(720P),1920X1080(1080P)等规格。『分辨率』影响图像大小,且与之成正比:分辨率越高,图像越大;反之,图像越小。 - 码率(BPS)
码率BPS,全称Bits Per Second,指每秒传送的数据位数,常见单位KBPS(千位每秒)和MBPS(兆位每秒)。帧率、分辨率和压缩率都会影响码率。高帧率高分辨率就意味着高码率,也意味着需要高带宽和强大的硬件能力进行编解码和图像处理。高分辨率意味着图片可以包括更多的细节,低压缩率意味着图片压缩损失越少,即失真越少,越清晰。 - I帧,英文全写Intra Picture,又称帧内编码帧,俗称关键帧。一般来说I帧不需要依赖前后帧信息,可独立进行解码
- P帧,英文全写predictive-frame,又称前向预测编码帧,也有帧间预测编码帧。顾名思义,P帧需要依赖前面的I帧或者P帧才能进行编解码,因为一般来说,P帧存储的是当前帧画面与前一帧(前一帧可能是I帧也可能是P帧)的差别,较专业的说法是压缩了时间冗余信息,或者说提取了运动特性。P帧的压缩率约在20左右,几乎所有的H264编码流都带有大量的P帧
- B帧,英文全写bi-directional interpolatedprediction frame,又称 双向预测内插编码帧,简称双向预测编码帧。B帧非常特殊,它存储的是本帧与前后帧的差别,因此带有B帧的视频在解码时的逻辑会更复杂些,CPU开销会更大。因此,不是所有的视频都带有B帧,B帧的压缩率能够达到50甚至更高
- IDR帧,英文全写Instantaneous Decoding Refresh,翻译过来是即时解码刷新。IDR帧是一种特殊的I帧,它是为了服务于编解码而提出的概念,IDR帧的作用是立刻刷新,使错误不致传播,从IDR帧开始,重新算一个新的序列开始编码
- GOP,英文全称Group Of Pictures,一般来说,指的就是两个I帧之间的间隔,严格来说,是两个IDR帧之间的间隔。GOP在一定程度上会影响视频画面质量 - 在码率相同的情况下,GOP越大,意味着PB帧越多,也就更容易获取较好的图像质量”这个说法存疑。
- DTS,英文全称Decoding Time Stamp,即解码时间戳,这个时间戳的意义在于告诉解码器该在什么时候解码这一帧的数据。
- PTS,英文全称Presentation Time Stamp,即显示时间戳,这个时间戳用来告诉播放器该在什么时候显示这一帧的数据。DTS和PTS在做视音频同步的时候特别重要,尤其是PTS,目前常见的视音频同步的三种策略“同步到音频的PTS”、“同步到视频的PTS”和“同步到系统/外部时钟”,都是基于PTS完成的。
- 视频格式是视频播放软件为了能够播放视频文件而赋予视频文件的一种识别符号,视频格式规定了和播放器的通信协议。
关于视频和帧的更多内容请参考《视频和视频帧:视频和帧基础知识整理》。
关于moviepy的介绍请参考《PyQt+moviepy音视频剪辑实战文章目录》或《moviepy音视频开发专栏》。
关于收费专栏
老猿的付费专栏《使用PyQt开发图形界面Python应用》专门介绍基于Python的PyQt图形界面开发基础教程,付费专栏《moviepy音视频开发专栏》详细介绍moviepy音视频剪辑合成处理的类相关方法及使用相关方法进行相关剪辑合成场景的处理,两个专栏加起来只需要19.9元,都适合有一定Python基础但无相关专利知识的小白读者学习。这2个收费专栏都有对应免费专栏,只是收费专栏的文章介绍更具体、内容更深入、案例更多。
对于缺乏Python基础的同仁,可以通过老猿的免费专栏《专栏:Python基础教程目录》从零开始学习Python。
如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。