视频超分:EDVR(EDVR: Video Restoration with Enhanced Deformable Convolutional Networks)

在这里插入图片描述
论文:EDVR:视频超分与加强的可变形卷积网络
文章检索出处: 2019 ICCV

摘要和简介

为了处理较大的运动,我们设计了一个金字塔,级联和可变形对齐模块 (PCD)。在该模块中,使用可变形卷积从粗到精的方式在特征级别完成了帧对齐。其次,提出了时空注意融合模块 (TSA),在时间和空间上都应用注意以强调后续恢复的重要特征。该模型在NTIRE19上夺冠。
在本文中,我们将介绍NTIRE2019在视频恢复和增强方面的挑战中的获奖解决方案。该任务中使用REDS为数据集,与现有数据集相比,REDS中的视频包含更大,更复杂的运动。
PCD模块受TDAN启发,使用可变形卷积将相邻帧与参考帧对齐。与TDAN不同,我们以从粗到精的方式执行对齐,以处理大型和复杂的运动。 具体来说,我们使用金字塔结构,该结构首先使用粗略估计将低比例的特征对齐,然后将偏移量和对齐的特征传播到较高的比例以促进精确的运动补偿,在金字塔对准操作之后级联可变形卷积,以进一步提高对准的鲁棒性。通过计算参考帧和每个帧的特征之间的逐元素关系来引入时间注意进行相邻特征的加权与后续的特征融合,然后进一步应用空间注意为每个通道的每个位置分配权重,以更有效的利用跨通道和空间信息。在这里插入图片描述

方法

Overview

给定2N+1低分辨率帧 I { t − N : t + N } I_{\{t-N:t+N}\} I{tN:t+N},定义中间帧 I t I_t It为参考帧,其他帧为相邻帧。目的是估计接近高分辨率帧 O t O_t Ot的参考帧 O ^ t \hat O_t O^t。 PCD对齐模块在功能级别将每个相邻帧与参考帧对齐,TSA融合模块融合不同帧的图像信息,然后融合的特征通过重建模块,该模块是EDVR中的残留块的级联,可以用单个图像SR中的任何其他高级模块替换。 在网络的末端执行上采样操作以增加空间大小。 最后,通过将预测图像残差添加到直接上采样的图像中来获得高分辨率帧。
在这里插入图片描述

金字塔,级联和可变形卷积的对齐

可变形对齐应用于每个帧的特征,记做 F t + i , i ∈ [ − N : + N ] F_{t+i},i∈[-N:+N] Ft+i,i[N:+N]。其他可变形卷积部分可参见 TDAN:可变形卷积 这篇文章,本文不再进行叙述。
我们使用金字塔和级联精炼去解决对准中的复杂运动和大时差问题。具体来说,为了生成 l l l F t + i l F_{t+i}^l Ft+il,使用strided convolution filter 将第( l l l-1)个金字塔的特征下采样x2,获得 l l l层的特征。在第 l l l层,从第( l l l+1)层通过x2上采样的偏移量和对齐特征来预测本层的偏移量和对其特征(紫色线)。流程图如下:在这里插入图片描述
公式如下:在这里插入图片描述
其中, Δ P t + i l \Delta P_{t+i}^l ΔPt+il表示偏移量, f f f是由几个卷积层组成的通用函数,“ , ”代表串联, ( ) ↑ s ()^{↑s} ()s表示上采样s倍,DConv表示可变形卷积,g表示具有多个卷积层的通用函数。采样采用双线性插值法,使用3层的金字塔结构, 为了减少计算成本,不会随着空间大小的减少而增加通道数。

时空注意力融合

我们在融合的时候采用了时空注意。在特征空间中,应该更加注意与参考帧更相似的相邻框架。对于每个帧i∈{-N:+N},相似距离h可以计算为:在这里插入图片描述
其中 θ ( F t + i a ) \theta (F_{t+i}^a) θ(Ft+ia) ∅ ( F t a ) \varnothing(F_t^a) (Fta)是两个embeddings,可以使用简单的卷积滤波器实现。sigmoid激活函数用于将输出限制为[0,1],稳定梯度反向传播。然后将时间注意图与原始对齐特征 F t + i a F_{t+i}^a Ft+ia相乘,用一个额外的融合卷积层来聚合这些注意力调制特征 F ^ t + i a \hat F_{t+i}^a F^t+ia在这里插入图片描述
[.,.,.,]表示级联。然后从融合特征中计算出空间注意蒙版。 采用金字塔设计以增加注意力接收范围。 此后,融合的特征由掩码通过逐元素的乘法和加法来调制。

二级恢复

单个EDVR可以达到最先进的性能,但是还原后的图像并不完美,故采用两阶段策略来进一步提升性能。具体的来说,将一个类似但较浅的EDVR网络进行级联,以完善第一级的输出帧。好处有二:(1)有效地消除了先前模型中无法处理的严重运动模糊,提高了修复质量; (2)减轻了输出帧之间的不一致。

实验

数据集:REDS(720p)包含240个训练剪辑,30个验证剪辑和30个测试剪辑(每个都有100个连续帧)。 在比赛中,由于无法获得测试地面的真实性,我们选择了四个代表性的片段(具有不同的场景和动作)作为测试集,以REDS41表示。 其余的训练和验证剪辑被重新分组为我们的训练数据集(总共266个剪辑)。此外,Vid4和Vimeo-90K-T也一起进行评估。
PCD对齐模块采用五个残差块(RB)进行特征提取。 我们在重建模块中使用40个RB,在第二阶段模型中使用20个RB。 每个残差块中的通道大小设置为128。我们分别使用大小为64x64和256x256的RGB色块作为视频SR和去模糊任务的输入。mini_batch为32。除非另有说明,否则网络将以五个连续的帧(即N = 2)作为输入。 我们通过随机的水平翻转和90旋转来扩充训练数据。 我们仅采用Charbonnier函数作为最终损失。在这里插入图片描述
使用Adam优化器,其中 β 1 \beta_1 β1=0.9, β 2 \beta_2 β2=0.999。初试学习率设置为4x 1 0 − 4 10^{-4} 104,使用8个NVIDIA Titan Xp GPU对其进行训练
在Vid4上与其他模型的PSNR和SSIM对比:
在这里插入图片描述
在Vimeo-90K-T上与其他模型的PSNR和SSIM对比:
在REDS4上与其他模型的PSNR和SSIM对比:在这里插入图片描述
有无PCD和TSA、不同数据集与测试集的消融实验:
在这里插入图片描述

仅供学习使用,请勿转载。

  • 4
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
假设`Edvr.cfg`文件内容如下: ``` [General] Version=1.0 Name=Edvr [Parameters] InputFile=input.mp4 OutputFile=output.mp4 FrameRate=30 ``` 可以通过以下步骤将`Edvr.cfg`文件解析为一个`Config`结构体: 1. 定义`Config`结构体,包含`General`和`Parameters`两个结构体。`General`结构体包含版本号和名称,`Parameters`结构体包含输入文件名、输出文件名和帧率。 ```c typedef struct { struct { float version; char name[50]; } general; struct { char input_file[100]; char output_file[100]; int frame_rate; } parameters; } Config; ``` 2. 编写解析函数,读取`Edvr.cfg`文件,并将读取的内容存储到`Config`结构体中。 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> Config parse_config_file(const char* file_name) { Config config = {0}; char line[100]; char section[20] = ""; FILE* fp; fp = fopen(file_name, "r"); if (fp == NULL) { printf("Failed to open file: %s\n", file_name); return config; } while (fgets(line, sizeof(line), fp) != NULL) { // 去除行末换行符 if (line[strlen(line) - 1] == '\n') { line[strlen(line) - 1] = '\0'; } // 处理段落信息 if (line[0] == '[' && line[strlen(line) - 1] == ']') { strcpy(section, line + 1); section[strlen(section) - 1] = '\0'; } else { // 处理键值对信息 char* key = strtok(line, "="); char* value = strtok(NULL, "="); if (strcmp(section, "General") == 0) { if (strcmp(key, "Version") == 0) { config.general.version = atof(value); } else if (strcmp(key, "Name") == 0) { strncpy(config.general.name, value, sizeof(config.general.name) - 1); config.general.name[sizeof(config.general.name) - 1] = '\0'; } } else if (strcmp(section, "Parameters") == 0) { if (strcmp(key, "InputFile") == 0) { strncpy(config.parameters.input_file, value, sizeof(config.parameters.input_file) - 1); config.parameters.input_file[sizeof(config.parameters.input_file) - 1] = '\0'; } else if (strcmp(key, "OutputFile") == 0) { strncpy(config.parameters.output_file, value, sizeof(config.parameters.output_file) - 1); config.parameters.output_file[sizeof(config.parameters.output_file) - 1] = '\0'; } else if (strcmp(key, "FrameRate") == 0) { config.parameters.frame_rate = atoi(value); } } } } fclose(fp); return config; } ``` 上面的代码中,使用`fgets()`函数逐行读取`Edvr.cfg`文件的内容,然后根据行内容的不同,分别处理段落信息和键值对信息。具体来说: - 如果行内容以方括号开头和结尾,说明这是一个段落信息,需要将方括号中的内容作为当前段落的名称。 - 如果行内容中包含等号,说明这是一个键值对信息,需要将等号左边的字符串作为键,等号右边的字符串作为值。根据当前段落的名称和键的名称,将值存储到`Config`结构体的相应字段中。 3. 调用解析函数,读取`Edvr.cfg`文件并打印配置信息。 ```c int main() { Config config; config = parse_config_file("Edvr.cfg"); printf("General:\n"); printf("Version: %.1f\n", config.general.version); printf("Name: %s\n", config.general.name); printf("Parameters:\n"); printf("InputFile: %s\n", config.parameters.input_file); printf("OutputFile: %s\n", config.parameters.output_file); printf("FrameRate: %d\n", config.parameters.frame_rate); return 0; } ``` 上面的代码中,调用`parse_config_file()`函数解析`Edvr.cfg`文件,并将解析结果存储到`config`结构体中。然后,打印`config`结构体中的各个字段。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值