MMEditing 是面向底层视觉任务的工具包,属于 OpenMMLab 开源算法体系。近期,我们在 MMEditing 中拓展了一个新的方向:视频插帧。本文将简要介绍视频插帧的技术原理,并带大家使用 MMEditing 实现一个视频插帧的 Demo。
难度:入门
经过社区开发者的不懈努力,MMEditing 已经支持了大量先进的超分辨率模型,可以将视频和图像从低分辨率无损放大到高分辨率,解决了观众对超清画质的追求与经典电影欠佳的画质之间的矛盾。
然而这还不够,影响观看体验的不仅仅是画质,还有流畅度,否则。。
技术层面上,画质对应分辨率,而流畅度则对应帧率。 视频是连续播放的图像序列,帧率则表示图像序列的播放速度。帧率通常以 FPS(Frames per second),即每秒帧数为单位,帧率越高,视频的流畅度越高,观感体验越好。在知乎上,相关的讨论也层出不穷。 现如今,主流视频平台上 30 FPS、60 FPS 的视频随处可见,部分平台已支持 120 FPS 的视频。但受限于早期摄影技术以及互联网有限传输带宽,许多经典影视作品只有 24 FPS 甚至 15 FPS 的帧率,让我们在回味经典时不免有些小遗憾。而视频插帧技术可以提高低帧率视频的流畅度,让经典重现精彩。
视频插帧旨在提高视频的帧率和流畅度,让视频看起来更加“丝滑”。 提升帧率似乎并不困难,只需要在相邻的视频帧之间插入一个新的视频帧,视频的帧率就可以提高一倍。但问题是,这一帧图像的内容应该是什么样的? 假设当前帧为
,下一帧为
,中间帧为
,三者均为
的三维数组。 我们可以令
或
,但这样只是形式上提高了帧率,视频流畅度没有得到改善。 我们也可以令
,其中
,即通过像素加权平均产生模糊的中间帧,从而起到一定的过渡效果。但这种方法会降低单帧图像的质量,产生虚影。如下图所示,第1、5、8帧是清晰的,而其余中间帧都包含虚影。
而最优方案,则是根据视频中物体运动状态,估计出一个清晰的中间帧,如下图所示。但这个方法有一定难度,因为这个理想的中间帧并不存在于原视频中,也不能通过简单的像素平均从相邻帧获得。因此,视频插帧与图像超分辨率类似,都需要解决“无中生有”的问题。
图片出处:https://commons.wikimedia.org/wiki/File:Motion_interpolation_example.jpg 在深度学习出现之前,视频插帧的主流技术大多基于光流。简单来说,我们通过光流估计算法,得到当前帧
和下一帧
之间的运动矢量场
,再通过图像扭曲(Image wrapping)技术,用一半矢量场
对图像
做扭曲,就可以得到中间帧
,如下示意图所示:
这种方法依赖光流的估计,而传统的光流估计算法通常速度较慢,精度也较低。
插播一条广告:OpenMMLab 开源算法体系中的 MMFlow 是首个光流算法的统一框架,支持多种基于深度学习的光流算法。
随着深度学习技术的出现,光流估计、视频插帧技术也得到了发展。目前,基于深度学习的视频插帧算法可分为以下几类:
各类算法各有优劣,目前 MMEditing 已支持的 CAIN 算法属于基于 CNN 的算法,下面的视频就是使用 MMEditing 支持的 CAIN 算法进行两次插帧,将帧率从 24 FPS 提高到 96 FPS 的效果。为了凸显差异,我们将视频慢放,可明显看出插帧处理的效果。 (视频可见原文链接)
目前 MMEditing 已支持 CAIN 算法,接下来将详细介绍其调用方法。
准备环境
a. 创建 Python 环境 我们推荐使用 Conda 创建 Python 环境,以 Python 3.8 为例:
conda create -n mmedit python=3.8 -y
conda activate mmedit
b. 安装 PyTorch 和 MMCV MMEditing 基于 PyTorch 和 MMCV,支持 PyTorch 1.5 以上的所有版本,此处以 PyTorch 1.7 为例。
例:安装 CUDA 版本的 PyTorch 和 MMCV
conda install pytorch==1.7.1 torchvision cudatoolkit=10.1 -c pytorch
pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/cu101/torch1.7/index.html "opencv-python<=4.5.4.60"
例:安装 CPU 版本的 PyTorch 和 MMCV
conda install pytorch==1.7.1 torchvision cudatoolkit=10.1 -c pytorch
pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/cu101/torch1.7/index.html "opencv-python<=4.5.4.60"
您可以根据需要调整 PyTorch 的版本,但需要根据 PyTorch 的版本调整 MMCV 的下载路径,具体请参考 安装 MMCV — mmcv 1.4.5 文档 针对 macOS 平台,您需要从源码编译 MMCV,详见 从源码编译 MMCV — mmcv 1.4.5 文档
c. 克隆 MMEditing 代码仓库
git clone https://github.com/open-mmlab/mmediting.git
cd mmediting
d. 安装 MMEditing 使用 pip 安装相关依赖,并从源码安装 MMEditing
pip install -r requirements.txt
pip install -v -e . # or "python setup.py develop"
e. 验证安装
安装完成后,可以切换到 /home
目录,并尝试在 python 中导入 mmedit
,导入成功则证明安装成功
$ cd ~
$ python
>>> import mmedit
>>> mmedit.__version__
'0.12.0'
我们提供了一个插帧的小 demo 方便大家测试视频插帧的效果,调用命令如下:
python demo/video_interpolation_demo.py \
configs/video_interpolators/cain/cain_b5_320k_vimeo-triplet.py \
https://download.openmmlab.com/mmediting/video_interpolators/cain/cain_b5_320k_vimeo-triple_20220117-647f3de2.pth \
${INPUT_PATH} \
${OUTPUT_PATH} \
[--fps_multiplier ${FPS_MULTIPLIER}] \
[--fps ${FPS}]
其中,INPUT_PATH
是输入视频的路径,OUTPUT_PATH
是输出视频的路径。路径可以是一个视频文件路径,也可以是包含若干图像的文件夹(图像排列需要有序)。
输出视频的帧率(FPS)可由 --fps
参数指定,例如:
python demo/video_interpolation_demo.py \
configs/video_interpolators/cain/cain_b5_320k_vimeo-triplet.py \
https://download.openmmlab.com/mmediting/video_interpolators/cain/cain_b5_320k_vimeo-triple_20220117-647f3de2.pth \
input.mp4 \
output.mp4 \
--fps 60
也可根据 --fps_multiplier
在输入视频帧率的基础上倍增(前提是 INPUT_PATH
为视频文件路径)
python demo/video_interpolation_demo.py \
configs/video_interpolators/cain/cain_b5_320k_vimeo-triplet.py \
https://download.openmmlab.com/mmediting/video_interpolators/cain/cain_b5_320k_vimeo-triple_20220117-647f3de2.pth \
input.mp4 \
output.mp4 \
--fps_multiplier 2.0
可使用重复调用插帧程序,以获得更高帧率的视频:
下面这段代码可以将两个视频左右拼接,并放慢速度,得到文章开头的对比视频。代码行数虽然较多,但逻辑并不复杂,仅调用 MMCV 和 OpenCV 视频相关的功能,限于篇幅我们这里就不详细介绍啦。
import cv2
import mmcv
import numpy as np
def vfi_cain_demo(ori_path, vfi_path, result_path, slow=1.0):
"""Compare ori video and interpolated video.
Args:
ori_path (str): Path of original video.
vfi_path (str): Path of interpolated video.
result_path (str): Path of the result video.
slow (float): Slow factor.
"""
print(f'load the original videos: {vfi_path}')
ori_reader = mmcv.VideoReader(ori_path)
ori_fps = ori_reader.fps
ori_images = []
for img in ori_reader:
ori_images.append(img)
print(f'load the interpolated video: {vfi_path}')
vfi_reader = mmcv.VideoReader(vfi_path)
vfi_fps = vfi_reader.fps
vfi_images = []
for img in vfi_reader:
vfi_images.append(img)
print(f'merge videos and save to {result_path}')
h, w = vfi_images[0].shape[:2]
rate = round(len(vfi_images) / len(ori_images))
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
video_writer = cv2.VideoWriter(result_path, fourcc, vfi_fps/slow, (w, h))
for i in range(len(vfi_images)):
image = np.zeros_like(vfi_images[i])
print(i, rate, i//rate)
image[:, :w//2] = ori_images[i//rate][:, :w//2]
image[:, w//2:] = vfi_images[i][:, w//2:]
image[:, w//2:w//2+1] = 0
video_writer.write(image)
cv2.destroyAllWindows()
拷贝并调用以上函数即可获得对比视频。
如果大家对视频插帧、底层视觉和 MMEditing 感兴趣,可以关注我们的代码库:
https://github.com/open-mmlab/mmeditinggithub.com/open-mmlab/mmediting
点亮右上角的小星星。
相信一致和模块化的设计可以减少大家复现各个算法的难度,提升使用体验。 未来我们会添加更多视频插帧算法,并发布插帧算法的系列教程。小伙伴们有什么想法可以积极留言,提issue。MMEditing 是共创共享的非盈利项目,我们也欢迎大家参与建设,多提 PR。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。