视频去模糊相关心得

最近在做视频去模糊相关的工作!因此,想记录一下学习的过程,不到之处请海涵!

视频里面的模糊在播放过程中很难用肉眼去捕获!但实际上这种模糊确实存在并影响到视频的主观感受质量!我们知道视频由连续的多帧图像构成,如果将视频暂停到某一帧上来看能够看出显著的区别!如下图所示:

当然视频的模糊和图像还是有些区别的!图像在视频中存在视觉残留的原因非清晰的图像。

我们分析一下图像模糊的产生的原因,我们知道相机成像的源自于小孔成像,小孔成像的缺陷主要是两个,一是光的衍射效应,造成图像的模糊,小孔过小则造成的,通光量小产生的图像偏暗。二是、增大小孔尺寸,会造成一个像素点的光来自于多个物点同样造成传感器上采集的图像模糊。采用透镜可以改善这类问题,透镜能汇聚光能从而提高信噪比。根据中学的透镜的成像原理我们可以根据透镜的焦距和物距等来计算成像的大小。以及像平面的位置,我们生活在一个三维空间中而像平面是一个二维空间。由于物距的不一致,那么实际成像的像距也不一致。一般而言我们的相机透镜是圆的,如果我们固定像平面(相机传感器所处的平面)不同物距上的点有的能够正常成像有的则投影成一个圆。由于我们人眼也是存在一定的感知范围的当投影的圆半径非常小人眼会认为这个圆是一个点,这时我们看到的图像是清晰的。当圆的半径超过一定的阈值时我们就能明显的感受到图像模糊了。这个阈值决定的圆称为最大弥散圆。一般,我们的相机像距是固定,所以看到在一些距离在符合这些相关的知识在知乎上有一篇文章写的非常清楚。感兴趣的可以详细的看看链接是:https://zhuanlan.zhihu.com/p/97542357

此外,透镜带来的问题还有色偏的问题,这个是由于光的波长不同造成的光经过透镜折射后的颜色发生了分离。和球面的非均匀性造成的一些问题等。我们忽略后两个因素产生的影响,只考虑衍射产生的问题,定义一个物点成像后产生的是一个圆将这种映射定义为点扩散函数(PSF)。那么透镜得到的实际图像可以表示为理想透镜产生的图像与点扩散函数之间的卷积的结果。

这种情况下我们能够得到实际图像,如果我们知道透镜的点扩散函数(PSF)的话我们就能够通过空域和频域的计算关系来计算理想图像。这种情况我们称为非盲去模糊。如果我们能够通过一些迭代算法能估计出PSF的话我们可以通过相同的方式来进行盲去模糊。这里https://zhuanlan.zhihu.com/p/104340592给出了详细的两个去模糊的例子分别是维纳滤波和Richardson-Lucy盲去模糊的算法。

    上述描述的是相机在成像过程中可能产生模糊效果的原因。这种模糊往往是空间分布上的模糊,视频模糊除了空间模糊之外还包含时序上的模糊。在视频拍摄过程中往往伴随着运动目标的移动,和相机运动等由运动带来的一些视频帧产生拖影等效果。这是视频模糊与基于单帧图像模糊之间存在的区别。但视频中信息往往是冗余的。因此可以借鉴相邻帧之间的信息来弥补当前模糊帧缺失的信息。从而提升视频的整体的感知质量。

近些年,深度学习快速发展,图像视频的的增强技术普遍得到进步。视频去模糊也成为其中一个非常重要的的方向。总体而言主要分为两种方案,一种是基于图像的去模糊,另外一种是基于视频的多帧的方案。无论是哪种方案都需要清晰的视频作为参考视频帧,以模糊的视频帧作为输入,实现训练。从数据的角度来看困难的地方主要在我们获取的视频很难同时满足清晰和模糊两个方面的要求。目前大多数方案是在清晰的视频帧上对视频进行模糊处理作为输入。难点就是这些模糊处理的方案如何去逼近真实的模糊的问题。我们知道滤波可以模糊视频,但是这种模糊与我们常见的视频的运动模糊存在区别。采用运动的模型核来模糊视频帧,也只是逼近的一种方式无法与真实场景完全匹配。此外,Reds数据集中采用高速相机来采用多帧合并的方式来模拟运动模糊。这种模糊的效果挺好,但也不能完全的匹配真实的情况,且成本较高。目前公开的视频去模糊数据集模糊处理的方式不一致。因此数据分布上存在较大的区别。如何解决这类问题是一项非常重要非常基础的任务。毕竟数据决定了深度模型的性能。

基于图像的视频去模糊方案:

基于图像的去模糊方案比较典型的有DeblurGAN,有两个版本了,这种基于GAN的图像的方案用于视频中主要存在两个缺陷:一、没有利用相邻帧之间的信息。二、GAN容易生成一些虚假的细节造成视频细节上的连续性较差。所以基于GAN的单帧图像去模糊的办法很难在视频去模糊上取得很好的效果。SRN-DeblurNet在去模糊上没有采用GAN的结构,但目前来看其去模糊效果也只是一般。

 

基于视频的多帧去模糊:

视频的去模糊方案很多时候与视频超分等增强方案是在一样的。我以EDVR模型中的视频去模糊为例分析视频去模糊算法中的主要模块。

视频去模糊主要几个模块在,帧间对齐模块,特征融合,重建模块这三大板块理想图像\ast PSF=实际图像

         帧间对齐:光流的方案,动态卷积,递归方案,可变形卷积等方案实现对齐。

笔者最近比较关注两种滤波器的方案会重点介绍一下基本的设计思路。我们先看看EDVR中视频帧对齐模块PCD模块以及里面用到的可变形卷积。PCD模块采用级联的可变形卷积构成金字塔模块实现帧对齐。

这个算法的核心在于形变卷积,关于形变卷积最早用于的是目标检测任务,主要是由于对图像进行了一些resize操作目标发生了一些形变。可形变卷积的是将特征经过一个普通卷积通道增大为原来的特征通道的两倍。将这个新的特征视为偏置叠加到原始特征的索引上刚好满足两个方向的偏移即x方向和y方向。得到新的特征索引,会去掉溢出的一些索引。然后通过双线性插值来获取新的坐标索引下的特征值。

具体代码可以参考https://blog.csdn.net/weixin_36411839/article/details/82715995。然后pytorch的代码可以在github上搜索edvr需要编译才能用。近期看到一篇新的论文讲的是视频超分的采用的是可形变卷积核和形变卷积的综合利用实现的对齐模块称为DKC_Align模块具体的可以去看论文《Deformable Kernel Convolutional Network for Video Extreme Super-Resolution》主要是增大了模型的有效感受野,和实现了空间上的注意力机制提升模型的效果。

除了可形变卷积还有一种动态滤波器的方法用于对齐,动态卷积层如下图所示:

特征x经过一个attention模块得到一组权重\pi _{i},将这组权重参数对卷积核进行加权,然后将这组加权后的核用于普通卷积中。下面是动态卷积的简单的参考代码:

from torch import nn
import torch.nn.functional as F
import torch
class attention2d(nn.Module):
    def __init__(self, in_planes, K,):
        super(attention2d, self).__init__()
        self.avgpool = nn.AdaptiveAvgPool2d(1)
        self.fc1 = nn.Conv2d(in_planes, K, 1,)
        self.fc2 = nn.Conv2d(K, K, 1,)

    def forward(self, x):
        x = self.avgpool(x)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.fc2(x).view(x.size(0), -1)
        return F.softmax(x, 1)
    
class Dynamic_conv2d(nn.Module):
    def __init__(self, in_planes, out_planes, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, K=4,):
        super(Dynamic_conv2d, self).__init__()
        assert in_planes%groups==0
        self.in_planes = in_planes
        self.out_planes = out_planes
        self.kernel_size = kernel_size
        self.stride = stride
        self.padding = padding
        self.dilation = dilation
        self.groups = groups
        self.bias = bias
        self.K = K
        self.attention = attention2d(in_planes, K, )

        self.weight = nn.Parameter(torch.Tensor(K, out_planes, in_planes//groups, kernel_size, kernel_size), requires_grad=True)
        if bias:
            self.bias = nn.Parameter(torch.Tensor(K, out_planes))
        else:
            self.bias = None


    def forward(self, x):
        softmax_attention = self.attention(x)
        batch_size, in_planes, height, width = x.size()
        x = x.view(1, -1, height, width)# 变化成一个维度进行组卷积
        weight = self.weight.view(self.K, -1)

        
        aggregate_weight = torch.mm(softmax_attention, weight).view(-1, self.in_planes, self.kernel_size, self.kernel_size)
        if self.bias is not None:
            aggregate_bias = torch.mm(softmax_attention, self.bias).view(-1)
            output = F.conv2d(x, weight=aggregate_weight, bias=aggregate_bias, stride=self.stride, padding=self.padding,
                              dilation=self.dilation, groups=self.groups*batch_size)
        else:
            output = F.conv2d(x, weight=aggregate_weight, bias=None, stride=self.stride, padding=self.padding,
                              dilation=self.dilation, groups=self.groups * batch_size)

        output = output.view(batch_size, self.out_planes, output.size(-2), output.size(-1))
        return output    
    

上述代码没有后面的BN和激活层。上述是普通的动态卷积滤波,在类似DUF的视频超分项目中有采用动态上采样滤波器不需要运动补偿。论文《Deep Video Super-Resolution Network Using Dynamic Upsampling Filters Without Explicit Motion Compensation》论文链接地址:https://openaccess.thecvf.com/content_cvpr_2018/papers_backup/Jo_Deep_Video_Super-Resolution_CVPR_2018_paper.pdf

整体的结构如下图:

实际上基本原理和动态卷积有点类似,区别在这种对齐方式采用的是一个生成器来生成卷积核而非生成一组权重,且实现的是上采样卷积而非普通卷积。但是这种动态滤波器的方法主要的缺陷在于计算量比普通卷积层大很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值