干货 | 视频插帧的方案实现与对比~~

对于视频网站、电视厂商以及进行视频压制的用户来说,改变视频的帧率算是一个比较常见的需求。

视频网站改变帧率主要是为了向不同级别的网站用户提供差异化服务;电视厂商则是以提供更好的显示效果作为电视的卖点;

对视频压制有所研究的用户会为了更好的显示效果而追求更高的帧率,或者为了更高的压缩率而选择更低的帧率。

帧率的变化能分为两种:低帧率变为高帧率;高帧率变为低帧率。虽然两者出于不同的需求,但是采取的是同一实现方式。

一般来说,视频中相邻的两帧之间有相同的时间间隔,例如帧率为24的视频的相邻两帧之间的间隔为1/24秒,帧率为60的视频的相邻两帧之间的间隔为1/60秒。

如果要把帧率为24的视频转换为60的帧率,则需要通过位于0,1/24,2/24,…秒上的帧来构造出位于0,1/60,2/60,…秒的帧;

如果要把帧率为24的视频转换为10的帧率,那么则需要构造分别位于0,1/10,2/10,…秒的帧。

本质上说,提高帧率以及降低帧率同样都是构造出不存在于源视频上的帧,两者只存在构造的帧的数量上的差别。

构造不存在的帧,我们称之为插帧(Frame Interpolation),插帧有三种实现方式:

  • Duplication,复制相近的帧。

  • Blend,用相邻的两帧进行混合。

  • Motion Interpolation,结合图像运动来构造中间帧。

下面对比了这三种不同的实现方式的插帧效果,把每秒15帧的视频插帧成每秒30帧:

32463696931a39f6348db5f57536e7d6.gif

每秒播放1帧可以明显看出采用不同实现方法的时不同表现

226378b7e66f9104f71f6b71d66dd476.png

下面分析三种不同实现方式的具体实现。

Duplication

输出的时间节点上的帧,就是我们需要生成的帧,此处称之为中间帧

在生成当前的中间帧的过程中涉及到两个输入帧,分别为小于输出时间并且最接近该输出时间的输入帧(假设为第n帧),以及大于输出时间并且最接近该输出时间的输入帧(假设为第n+1帧),我们可以称它们为参考帧。

从这两个参考帧中选取时间上最接近中间帧输出时间的一帧,对这一帧进行复制,作为当前的中间帧进行输出。

508c5b6c12164e4768f3550421c96ee1.png

Blend

与前面Dup的讨论相同,中间帧也涉及到左右相邻的两个参考帧,不过blend的实现是把这两个参考帧按照一定方式进行混合。

混合方式就是分别为两帧分配一个权重(或者称之为透明度,不透明时权重为1,完全透明时权重为0),两帧的各个像素在乘上各自的权重后进行相加,即可得到中间帧对应位置上的像素值。

这两个权重应该满足两个条件:

  • 两个权重应该为[0,1]区间上的数值,并且两者相加等于1。

  • 距离中间帧远的帧的透明度更高,即权重更小;距离中间帧帧近的帧的透明度更低,即权重更大。

如此一来,利用中间帧与其左右相邻的参考帧在时间上的关系就能计算出这两个参考帧的权重。假设中间帧与参考帧之间在时间上有以下关系

23c6c3733b41f81f090e0cebec6c9c3d.png

左边的参考帧的权重应该为(L-α)/L,右边的参考帧的透明度应该为α/L。两个参考帧乘上各自的权重后相加即可得到中间帧。

7f62a049775e5b01383fb9ae979cdcdd.png

Motion Interpolation

一般来说,视频中相邻两帧的时间间隔很短,因此如果这两帧中的内容的变化较小(在场景切换的时候,或者说两帧中的内容变化较大时,直接复制前一帧进行输出即可),我们可以把两帧中内容的变化看作线性运动。

如果能够求出该线性运动的运动轨迹,就能根据该运动轨迹以及输入输出帧的时间关系来进行内容位置的调整,这种实现方法被称为运动内插(Motion Interpolation)

这种利用物体的运动对视频进行插帧的方法会使得插帧后的视频显得更为流畅。

当然,视频中的内容复杂,并不能单纯地认为一个运动的物体的所有部分都是朝一个方向做线性运动,但是如果把视频分成小块,那么就把运动的物体分解成了一块块运动的色块,对于这些色块,我们则可以认为它们是做线性运动的。(下图为各个16x16大小的块的运动向量)

fd402f6845f0baf5e36300d8f4217e03.png

由于我们此处认为这些小块是线性运动的,因此可以根据时间关系得到中间帧上的小块与参考帧的对应小块之间的运动关系(运动向量)。

660ca609e0fd38300bd840a002f35fb7.png

通过运动向量可以定位到参考帧的两个参考块,以及中间帧上所需要生成的块的位置,然后就采用类似于上述blend的方法对块进行合成。

当把帧内的所有块都执行完合成操作后,就能得到所需的运动内插的帧。

1fbeef064fab8dfdaa3b7c712f7e1523.png

运动向量搜索

按照前面的描述,在构造中间帧之前,必须先求出两个参考帧之间各个块的运动向量,这需要把一个参考帧作为「当前帧」,另一个参考帧作为「参考帧」。参考上图,在求运动向量时,我们把序号为n的帧当作「当前帧」,把序号为n+1的帧当作「参考帧」。

运动向量搜索就是把「当前帧」分割成小块,并顺次从「参考帧」中搜寻各个小块的最优匹配块,这与视频编码时的运动向量搜索是基本一致的,在搜索时可以选择各种各样的搜索算法。

735c64c1bbc4a63611994591e68bdabc.png

此外还有一种运动向量搜索方案,该方案以中间帧为基准,把中间帧分割成小块,顺次地把这些小块当作「当前块」进行运动向量搜索。

这种搜索方案要求:对「当前块」求的所有运动向量都需要通过「当前块」,即以「当前块」为中心。

具体是把「当前块」作为中心点(0,0),如果运动向量为(x, y),那么「当前帧」上的块的相对位置为(-xα/L, -yα/L),「参考帧」上的块的相对位置为(x(L-α)/L, -y(L-α)/L)。

9ab3b056d731ff44ac0643747737b66d.png

这种方案在计算运动向量上会增加额外的消耗,为了减少这种消耗,在实际实现的时候可能会假设中间帧位于两个参考帧的正中间,并以此去求运动向量,求得的运动向量会被当作穿过实际中间帧上的「当前块」的运动向量,该运动向量在进行运动补偿时会按照中间帧的实际位置分割运动向量。

如下图,可见「当前帧」(n)中的块与「参考帧」(n+1)中的块都存在了一定程度的偏移,即进行运动向量搜索时采用的两个块并非后续进行运动补偿的两个块,这需要我们采取一些补救措施。

496de98ecfbd44b784c0b87a1ccc95d1.png

运动补偿

我们把通过运动向量来得到源块并生成目标块的这一过程称为运动补偿(motion compensation)。根据上方两种不同的运动向量搜索方式,分别有两种不同的运动补偿方案。

如果采用上述第一种运动向量搜索方案,在运动补偿时时,会以这两个参考帧以及中间帧之间的时间关系来对运动向量进行分割,分割点就是插帧生成的块的位置,如下图

c0141850d2f48d2f6956d96f842cddf6.png

如果采用上述第二种运动向量搜索方案,在运动补偿时,是中间帧上的各个块就是插帧生成的块的位置,如下图

c6662aab590515fae202ba7508a1174e.png

对比两个中不同方案:

  • 在进行运动向量搜索时,方案一相对于方案二节省了运动向量的计算的消耗。

  • 在进行运动补偿时方案一无法保证完全填充中间帧,因此总会出现未填充区域,而方案二则可以完全覆盖整个中间帧。

  • 方案一如果为了节省运动向量搜索时的消耗而采取我们前面所说的优化处理,则会导致执行运动补偿的块并非运动向量搜索时得到的块。

为了提高方案二对中间帧的覆盖率,以及提高方案一中运动向量搜索所得的块与运动补偿的块之间的相关性,我们在保持块位置不变的情况下把块的宽高提升为两倍。

例如,原本各个块的大小为16x16,原本各个块的位置位于(0, 0), (0, 16), (0, 32),…,(16, 0), (16, 16), (16, 32), … 提升后的各个块的大小为32x32,即在运动向量搜索以及运动补偿的时候块的大小都是32x32,但是各个块的位置不变。

049186d936537c1657b8e74c0e5de533.png

此时无论是方案一还是方案二,在执行运动补偿的时候都会出现生成的块之间相互覆盖的情况,但是这并非我们需要的效果,我们可以为一个块中的各个像素分配一个权重,在进行运动补偿的时候就可以按照这个权重对相互覆盖的块的像素进行混合。

通常为了更好的显示效果,混合的像素应该平滑地过渡,因此越靠近块的边缘的像素应该权重更小,越靠近块的中心的像素的权重更大。

最后,对于方案一,即使提高了中间帧的覆盖率,但是还是很有可能出现无法覆盖的区域,对于这种区域,只能用两个参考帧的对应位置上的像素来进行混合。

其它优化措施

对于方案一,上面的描述只采用了单向运动预测,采用双向运动预测可以有更高的中间帧覆盖率,在实现的时候只需要把序号为n+1帧作为「当前帧」,序号为n的帧作为「参考帧」。

对于方案二,在运动补偿的时候由于各个块之间的重叠区域是固定的,因此我们可以去比较重叠区域之间的cost来调整重叠区域的权重。

为了进行更精确的运动补偿,我们可以对运动向量进行分类。

我们把相差不大的运动向量的块归为一类,把一类看作一个内容,如果相邻的块的运动向量相差较大,则表明相邻块并非位于同一个内容之中,而是处于两个内容之间的边界,对于这种情况,可以采用更小的块来进行小范围的搜索,以求得更准确的运动向量,从而在运动补偿的时候也能生成更准确的块。

来源:https://www.cnblogs.com/TaigaCon/p/10612354.html

e9a499bdcf6849ef7fde879eaead4589.png

技术交流,欢迎加我微信:ezglumes ,拉你入技术交流群。

6a4ad57b8068326055469a8af54789ee.png

私信领取相关资料

推荐阅读:

音视频开发工作经验分享 || 视频版

OpenGL ES 学习资源分享

开通专辑 | 细数那些年写过的技术文章专辑

Android NDK 免费视频在线学习!!!

你想要的音视频开发资料库来了

推荐几个堪称教科书级别的 Android 音视频入门项目

觉得不错,点个在看呗~

9c04229b6a3b2ee3f2aa47046ee57e78.gif

### 回答1: Spark Streaming 和 Flink 都是流处理框架,但在一些方面有所不同。 1. 数据处理模型 Spark Streaming 基于批处理模型,将流数据分成一批批进行处理。而 Flink 则是基于流处理模型,可以实时处理数据流。 2. 窗口处理 Spark Streaming 的窗口处理是基于时间的,即将一段时间内的数据作为一个窗口进行处理。而 Flink 的窗口处理可以基于时间和数据量,可以更加灵活地进行窗口处理。 3. 状态管理 Spark Streaming 的状态管理是基于 RDD 的,需要将状态存储在内存中。而 Flink 的状态管理是基于内存和磁盘的,可以更加灵活地管理状态。 4. 容错性 Flink 的容错性比 Spark Streaming 更加强大,可以在节点故障时快速恢复,而 Spark Streaming 则需要重新计算整个批次的数据。 总的来说,Flink 在流处理方面更加强大和灵活,而 Spark Streaming 则更适合批处理和数据仓库等场景。 ### 回答2: Spark Streaming 和 Flink 都是流处理框架,它们都支持低延迟的流处理和高吞吐量的批处理。但是,它们在处理数据流的方式和性能上有许多不同之处。下面是它们的详细比较: 1. 处理模型 Spark Streaming 采用离散化流处理模型(DPM),将长周期的数据流划分为离散化的小批量,每个批次的数据被存储在 RDD 中进行处理,因此 Spark Streaming 具有较好的容错性和可靠性。而 Flink 采用连续流处理模型(CPM),能够在其流处理过程中进行事件时间处理和状态管理,因此 Flink 更适合处理需要精确时间戳和状态管理的应用场景。 2. 数据延迟 Spark Streaming 在处理数据流时会有一定的延迟,主要是由于对数据进行缓存和离散化处理的原因。而 Flink 的数据延迟比 Spark Streaming 更低,因为 Flink 的数据处理和计算过程是实时进行的,不需要缓存和离散化处理。 3. 机器资源和负载均衡 Spark Streaming 采用了 Spark 的机器资源调度和负载均衡机制,它们之间具有相同的容错和资源管理特性。而 Flink 使用 Yarn 和 Mesos 等分布式计算框架进行机器资源调度和负载均衡,因此 Flink 在大规模集群上的性能表现更好。 4. 数据窗口处理 Spark Streaming 提供了滑动、翻转和窗口操作等灵活的数据窗口处理功能,可以使用户更好地控制数据处理的逻辑。而 Flink 也提供了滚动窗口和滑动窗口处理功能,但相对于 Spark Streaming 更加灵活,可以在事件时间和处理时间上进行窗口处理,并且支持增量聚合和全量聚合两种方式。 5. 集成生态系统 Spark Streaming 作为 Apache Spark 的一部分,可以充分利用 Spark 的分布式计算和批处理生态系统,并且支持许多不同类型的数据源,包括Kafka、Flume和HDFS等。而 Flink 提供了完整的流处理生态系统,包括流SQL查询、流机器学习和流图形处理等功能,能够灵活地适应不同的业务场景。 总之,Spark Streaming 和 Flink 都是出色的流处理框架,在不同的场景下都能够发挥出很好的性能。选择哪种框架取决于实际需求和业务场景。 ### 回答3: Spark Streaming和Flink都是流处理引擎,但它们的设计和实现方式有所不同。在下面的对比中,我们将比较这两种流处理引擎的主要特点和差异。 1. 处理模型 Spark Streaming采用离散流处理模型,即将数据按时间间隔分割成一批一批数据进行处理。这种方式可以使得Spark Streaming具有高吞吐量和低延迟,但也会导致数据处理的粒度比较粗,难以应对大量实时事件的高吞吐量。 相比之下,Flink采用连续流处理模型,即数据的处理是连续的、实时的。与Spark Streaming不同,Flink的流处理引擎能够应对各种不同的实时场景。Flink的实时流处理能力更强,因此在某些特定的场景下,它的性能可能比Spark Streaming更好。 2. 窗口计算 Spark Streaming内置了许多的窗口计算支持,如滑动窗口、滚动窗口,但支持的窗口计算的灵活性较低,只适合于一些简单的窗口计算。而Flink的窗口计算支持非常灵活,可以支持任意窗口大小或滑动跨度。 3. 数据库支持 在处理大数据时,存储和读取数据是非常重要的。Spark Streaming通常使用HDFS作为其数据存储底层的系统。而Flink支持许多不同的数据存储形式,包括HDFS,以及许多其他开源和商业的数据存储,如Kafka、Cassandra和Elasticsearch等。 4. 处理性能 Spark Streaming的性能比Flink慢一些,尤其是在特定的情况下,例如在处理高吞吐量的数据时,在某些情况下可能受制于分批处理的架构。Flink通过其流处理模型和不同的调度器和优化器来支持更高效的实时数据处理。 5. 生态系统 Spark有着庞大的生态系统,具有成熟的ML库、图处理库、SQL框架等等。而Flink的生态系统相对较小,但它正在不断地发展壮大。 6. 规模性 Spark Streaming适用于规模小且不太复杂的项目。而Flink可扩展性更好,适用于更大、更复杂的项目。Flink也可以处理无限制的数据流。 综上所述,Spark Streaming和Flink都是流处理引擎,它们有各自的优缺点。在选择使用哪一个流处理引擎时,需要根据实际业务场景和需求进行选择。如果你的业务场景较为复杂,需要处理海量数据并且需要比较灵活的窗口计算支持,那么Flink可能是更好的选择;如果你只需要简单的流处理和一些通用的窗口计算,Spark Streaming是更为简单的选择。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值