CVPR2021论文:PWCNet: CNNs for Optical Flow Using Pyramid,
作者:禅与计算机程序设计艺术
1.简介
作为一名技术专家, 我渴望与同样热爱技术领域的人分享我的所学所得. 在此过程中, 我致力于将自己已发表或正在撰写的论文的心路历程进行提炼, 整理成学习笔记, 以期为更多人提供帮助.
在涵盖图像识别、机器视觉以及自动驾驶等领域的研究中
PWC-Net是在最近CVPR会议上开创性提出的用于光流估计的深度学习模型,在该模型在光流估计领域采用了深度学习方法,并且其核心创新点体现在...
- 基于pyramid、warping以及cost volume等技术构建CNN输入模块,能够有效处理空间相关性问题;
- 构建一种新型的图像金字塔网络架构,在保证深度学习模型整体性能的基础上显著提升了特征提取能力;
- 通过优化并协调多个CNN子网络之间的连接方案,并引入多分支结构以提高预测精度;
- 开发了一种新的优化目标函数用于光流场估计,并将以往难以有效整合的关键性能指标纳入同一个综合优化框架。
PWC-Net包含三个主要组成部分:Encoder、Decoder和Warper,各自负责提取图像特征信息、估计光流场信息以及实现变形图像的重建。
本文将着重介绍基于光流估计的新一代CNN模型——PWC-Net。文章将从该网络的主要创新点、基本原理以及在不同场景中的应用领域展开论述。接着采用逐步说明的方式,系统地讲解其结构组成及运行机制,并深入分析其核心模块实现细节。最后部分将总结该网络的优势与不足,并探讨未来研究方向及技术改进路径。
本篇论文假定读者有一定计算机视觉、机器学习、数学基础。
2.引言
2.1 PWC-Net概述
基于深度学习技术的光流估计一直是当前研究中的一个复杂课题。受CNN网络独特架构的影响,在现有方法中普遍存在的问题是过分依赖相邻像素间的共生关系。这种依赖不仅限制了算法精度,并且显著增加了计算负担。PWC-Net通过构建多尺度图像金字塔结构,并结合不同尺度下图像间的差异信息实现光流估计。该方法成功突破了传统CNN模型在空间关联方面的局限,并成功解决了这一长期存在的难题。
PWC-Net的主要创新点如下:
- 采用不同尺度的图像作为CNN的输入,在一定程度上可以处理不同尺度的对象并避免直接计算空间关联性。
- 在构建图像金字塔时,在各层之间引入多分支结构设计框架,并通过这种方式提升预测精度。
- 基于cost volume模型的设计框架下,在局部区域中可以有效提取光流信息。
- 基于光流场中各点处的空间梯度变化特征,在优化目标函数的设计过程中充分考虑这些因素,并在此基础上构建相应的网络模型架构以提高其鲁棒性和稳定性。
PWC-网在光流估计任务方面具有广泛的适用性。然而,在准确性和计算复杂度方面仍存在一定的瓶颈。此外,在这一领域中还存在着若干研究工作致力于通过CNN实现光流估计技术的改进与优化,在此基础上提出了FlowNet、Supervised Image Distillation(SID)等方法。值得注意的是,在现有研究中采用的网络架构设计各有特色,并且这些方法在实际应用中往往难以满足特定场景的需求。
2.2 PWC-Net原理
2.2.1 数据集与数据集划分
PWC-Net主要使用 FlyingChairs、FlyingThings3D 以及 KITTI 这三个数据集,在 FlyingChairs 数据集中,图片尺寸相对较小,在 FlyingThings3D 和 KITTI 等数据集中通常达到 4K 分辨率。为确保不同尺度下的图像能够全面涵盖光流变化范围,则采用了不同尺寸的图像配置。具体而言,KITTI 的数据分辨率设置为 480\times 640 因此仅需调整短边长度即可完成适应;而对于其余两个数据集则分别设置了 768\times 960 和 2048\times 2448 的分辨率要求
针对每一个数据集,在其图像中均匀地选取相同比例的部分区域进行切割,并将其分割成四张独立的照片。具体而言,在 FlyingChairs 数据集中选取了四张照片:正视图(front)、俯视图(top)、侧视图(side)以及水平视图(horizontal)。每一张照片上都包含五个物体,在图像中它们的位置是随机分布的,并且各物体中心点的位置坐标也是随机设定的。这种处理方式有助于构建更加具有真实感和多样性的数据集
2.2.2 模型结构
PWC-Net的结构如图1所示,由三个主要部分组成,即:Encoder、Decoder、Warper。
Encoder
由多个卷积模块构成的Encoder随后包含三个连续的三维空间可学习核(分别为32、64及128通道),随后附加了两个大小均为3\times 3且分别生成256及512通道的空间可学习核。在整个网络架构中均匀地引入批归一化操作。所有convolution layers均采用step size为1,并采用The zero-padding policy is set to reflect策略填充零值。激活函数选择ReLU作为激活机制。
图像金字塔的生成方式如下:首先对原始图片进行尺寸互换操作后得到高宽比更大的图片,并将其缩放到1/32倍大小。随后对图片进行重采样处理从而得到四个尺寸一致的图像其中一张是原始图片的一半大小另外再重采样一次并上下颠倒一张从而最终得到四个不同方向的图像分别来自x轴、y轴、z轴以及平面视图四个方向。接着将这些图像输入到Encoder模块中进行特征提取过程以获取四种尺度下的特征图
Decoder
Decoder包含两个主要组成部分,即左半部分和上半部分。具体来说,左半部分是由左半部特征图融合而得,而上半部分则是通过融合上半部特征图与左半部特征图来构建的。
左右两路分别由两个连续的3×3卷积模块构成(第一个模块输出512个通道、第二个模块输出256个通道)。随后引入一个5×5尺寸的卷积模块(输出通道数为128),其中池化操作采用最大值池化策略、步长设置为2。随后利用反向卷积极上采样的机制将特征图恢复到与原始输入图像尺寸一致的空间尺度。
顶部分支包括三个连续的3\times 3卷积层(分别输出128、64与32个通道)随后增加一个3\times 3卷积层(仅输出2个通道)其激活函数采用双曲正切函数。该模块最终生成两个向量它们分别代表光流场在x轴与y轴方向上的位移估计值
Warper
Warper是一种图像变形网络,在接收原始图片以及预测得到的偏移量的基础上,在x轴和y轴方向上相应地进行平移操作以实现对原始图像的变形处理从而生成最终变形后的图像
PWC-Net采用了光流估计的整体性方法论进行处理:首先,在第一阶段中调整输入图像的空间维度并将其转换为高宽长格式后通过Encoder模块生成多尺度特征图;随后在第二阶段中经过Decoder模块解码出左、右以及顶部分支特征;最后在第三阶段中利用Warper模块将原始图像与预测偏移量进行融合合成变形后的图像
2.2.3 优化目标函数
PWC-Net视光流估计为单目相机场景下的图像配准问题,并其优化目标函数可表示为:
其中,
\tilde{I}_i为原始图像,
\hat{u}_i代表第i幅图像中的光流场;
对应的预测偏移量为\hat{v};
损失函数通常采用交叉熵损失(cross-entropy loss)来衡量预测误差;
网络参数由变量θ表示。
该网络将光流估计任务划分为两个主要阶段:编码阶段与解码阶段。在编码阶段中(即第一部分),该网络通过Encoder模块生成多尺度特征图序列;在解码阶段中(即第二部分),该网络通过Decoder模块整合多个分支信息并预测出各尺度范围内的光流场分布。最后将各个光流场融合处理以获得最优全局光流场
在PWC-Net中,在解码环节中,每张图片都需要其光流场通过Warper进行变形处理;从而生成了经变形处理后的图像。
其中:W_t代表Warper系统的运行状态参数;\tilde{I}代表源图像;p代表经过图像预处理得到的像素坐标;\hat{u}代表运动向量场。
本节将阐述PWC-Net是如何通过计算光流场来进行运动估计的。在正式介绍Cost Volume之前,请注意该模块能够有效提取并整合图像区域内的运动信息。
该模型通过计算函数f和g在点p处关于x和y方向的偏导数乘积之差的模长平方来定义误差项。
其中f和g表示两个图像,在a和b分别代表该图像的空间位置坐标;而C_{ab}(p)则表示对应的Cost Volume值。Cost Volume实际上代表了两张图像在光流梯度矢量上的平方差。其计算公式与空间位置坐标之间的对应关系直接相关。
当预测出来的光流场为\hat{u}时,我们可以通过如下公式计算Cost Volume:
\widehat{C}_{ab}在点p处的估计值等于由I沿(u_x, u_y)方向与沿(v_x, v_y)方向的变化率所构成的差分项与另一个差分项的乘积之差的绝对值平方。具体而言,在x方向上的变化率为\frac{\partial I}{(x_a + u_x, y_a + u_y) - (x_b + v_x, y_b + v_v)}而在y方向上的变化率为\frac{\partial I}{(x_a + u_v, y_a + u_u) - (x_b + v_v, y_b + v_u)}。将这两个方向上的变化率分别相乘后相减得到的结果取其绝对值平方即为所需计算结果,并记作\mathcal{H}空间中的范数形式表示为方程(4)所示
其中:u=(u_x,u_y)是光流场向量,v=(v_x,v_y)是另一条光流场向量。
因为Cost Volume在图像坐标的对应关系上直接影响其值的变化,在构建优化目标函数时应当考虑这一因素的影响程度,并将其纳入约束因素以确保优化过程的有效性
其中:c_{ij}(p+\hat{u}_i)被定义为Cost Volume;而R(\theta)则代表正则化项。\lambda作为一个调节参数,在一定程度上影响着Cost Volume的权重设置。
3.核心算法细节
3.1 图像金字塔
图像金字塔通过调整原始图片的不同尺寸比例生成一系列缩略图,并使每幅缩略图与原图的比例关系为1:n(n表示放大倍数)。随后将这些经过尺寸调整的图像输入到卷积神经网络(CNN)中进行特征提取,在不同分辨率下获取各层次的特征表示。最终将各个尺度下的特征信息整合起来能够生成全面而准确的图像描述符
同一图像的不同尺度层次所包含的信息具有差异性,在实际应用中我们只能提取有限数量的高频信息用于检测,并不能有效地实现多尺度检测。鉴于此,在设计相关算法时需要找到一种平衡手段以确保所有尺度特征都能得到充分挖掘
在PWC-Net中, 作者采用了基于平滑插值的方法来生成图像金字塔. 其具体操作包括: 首先将原始图像旋转90度以获得高宽比与原图成反比的新尺寸, 然后按照512→800→224→40→16的比例逐步缩小尺寸, 直至获得分辨率800像素的图像. 这样就能得到四张不同视角(x轴,y轴,z轴,平面视图)的图像样本. 这四个级别的图像样本各自代表不同的尺度层次. 最后将这些图像输入到Encoder模块中, 从而能够提取出不同尺度下的特征图
3.2 Multi-Branch Structure
其核心创新点在于引入多分支结构。该架构旨在通过多分支设计来显著增强网络深度及特征提取能力。在现有CNN架构中,通常仅采用单层或多层卷积神经网络以获取图像信息。这种单一层次的设计限制了信息传递路径的完整性与全面性,在某些场景下可能导致整体效果欠佳的情况。
其主要理念在于通过在卷积层间引入多条分支来实现信息整合。其中左右两支与顶部支均各自由两个连续的3×3卷积层以及一个单独的3×3卷积层构成。左边路径接收原始图像并结合预测偏移信息生成左部特征图;右边路径同样接收原始图像并生成右部特征图。顶部路径则整合左部与右部特征信息并输出最终顶部特征及其对应偏移量。这种架构显著提升了模型的整体预测精度。
3.3 Cost Volume
Cost Volume负责提取局部运动信息。在传统CNN网络中,光流信息通常仅能反映局部运动情况,并缺乏整体特征这一显著缺陷。因此基于CNN的传统方法难以有效捕捉全局运动模式。
因而,PWC-网创造出了' CostVolume '这一概念.该系统将其应用于图像金字塔的不同层次之间.其中,PWC-网通过计算两张图片光流梯度差值的平方作为 CostVolumes,并利用这些 Volumes对 CNN 网络进行约束.
3.4 Optimizing the Loss Function
PWC-Net基于引入Cost Volume来提升网络的鲁棒性和稳定性。此外,它还利用光流场的偏导数信息构建优化目标函数用于提升网络的鲁棒性和稳定性。优化目标函数如下:
其中符号表示为:
-E 表示损失函数;
-u 表示预测得到的光流场;
-C 表示 Cost Volume;
-$\lambda 表示权重因子;
-R 表示正则项;
-p 表示特征图中任一点的空间坐标位置;
-i 代表第 i 张图片;
-j 代表第 j 类特征图.
4.代码实例
4.1 安装与测试环境
!pip install opencv-python matplotlib
import cv2
import numpy as np
from matplotlib import pyplot as plt
# test environment
print('opencv version:', cv2.__version__) # should be >= 4.2
print('numpy version:', np.__version__) # should be >= 1.18
print('matplotlib version:', plt.__version__) # should be >= 3.2.1
代码解读
4.2 测试数据集
这里下载两个数据集FlyingChairs和KITTI,用来测试我们的代码:
数据的准备工作已经完成,读者可以根据自身情况修改代码路径。
4.3 数据预处理
读取RGB图片、转换成灰度图、调整图像尺寸、裁剪图像边缘。
def preprocess_img(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
h, w = img.shape[:2]
if h > w:
dw = h - w
padding = int(dw / 2)
img = cv2.copyMakeBorder(img, 0, 0, padding, padding, cv2.BORDER_CONSTANT, value=[0, 0, 0])
elif w > h:
dh = w - h
padding = int(dh / 2)
img = cv2.copyMakeBorder(img, padding, padding, 0, 0, cv2.BORDER_CONSTANT, value=[0, 0, 0])
resized = cv2.resize(gray, (480, 640))
cropped = resized[64:-64, 64:-64].astype(np.float32) / 255.0
return cropped
代码解读
4.4 数据加载器
开发了一个数据加载器,负责读取输入的数据并输出一批图像样本及其对应的光流场特征图。
class FlyingChairsDataset():
def __init__(self, root='./data', mode='train'):
self.root = root
assert mode in ['train', 'val']
self.mode = mode
self.img_names = []
self.flows = []
with open('{}/{}.txt'.format(root, mode)) as f:
lines = [line.strip() for line in f.readlines()]
for line in lines:
items = line.split(' ')
img1_name = '{}/{:05d}.ppm'.format(root, int(items[0]))
img2_name = '{}/{:05d}.ppm'.format(root, int(items[1]))
flow_name = '{}/{}-{}_flow.flo'.format(root, os.path.basename(img1_name).replace('.ppm', ''), os.path.basename(img2_name).replace('.ppm', ''))
img1 = cv2.imread(img1_name)
img2 = cv2.imread(img2_name)
flow = read_flow(flow_name)
self.img_names += [[img1_name, img2_name]]
self.flows += [flow]
def __getitem__(self, index):
pair = self.img_names[index]
flow = self.flows[index]
img1 = cv2.imread(pair[0])
img2 = cv2.imread(pair[1])
inputs = {}
inputs['input_frames'] = np.stack([preprocess_img(img1), preprocess_img(img2)], axis=-1)[None]
targets = {'target_flow': flow[..., None]}
return inputs, targets
def __len__(self):
return len(self.img_names)
def read_flow(filename):
""" Read.flo file in Middlebury format"""
# Code adapted from:
# http://stackoverflow.com/questions/28013200/reading-middlebury-flow-files-with-python-bytes-array-numpy
# WARNING: this will work on little-endian architectures (eg Intel x86) only!
# print 'Reading %s' % filename
with open(filename, 'rb') as f:
magic = np.fromfile(f, np.float32, count=1)
if 202021.25!= magic:
print('Magic number incorrect. Invalid.flo file')
return None
else:
w = np.fromfile(f, np.int32, count=1)[0]
h = np.fromfile(f, np.int32, count=1)[0]
# print 'Reading %d x %d flo file\n' % (w,h)
data = np.fromfile(f, np.float32, count=2*w*h)
# Reshape data into 3D array (columns, rows, bands)
flow = np.resize(data, (h, w, 2))
return flow.astype(np.float32)
代码解读
4.5 PWC-Net模型
编写了一个PWC-Net模型,包括Encoder、Decoder、Warper三个主要部分。
Encoder由多个卷积模块构成,并包含三个不同的卷积操作依次输出通道数分别为32、64和128。随后加入两个连续的3×3尺寸的滤波器分别生成大小为256和512个特征图。每个这样的滤波器操作后均接一个Batch Normalization过程,并且所有这些模块均采用步长为1的设计方案,在补零策略上采用的是反射模式,并选用ReLU函数作为激活函数。
图像金字塔的构建步骤如下:首先将原始图片的长宽比例交换为高宽长,并将其缩放到1/32的比例尺寸。随后通过重复采样技术生成四份大小一致的子图像:其中一张是原始图片的一半尺寸、另外两张则分别上下颠倒排列。这样总共获得了四张具有不同方向特性的子图像(分别对应x轴、y轴、z轴以及平面视图的方向)。最后将这些预处理后的子图像输入到Encoder模块中进行特征提取操作,并通过多尺度采样机制获取了四种不同分辨率下的特征图输出。
Decoder包含两个主要组成部分:一是左部子网络(Left Branch),二是右部子网络(Right Branch)。左部子网络主要负责提取图像的局部细节信息;右部子网络则整合了上层全局信息与局部细节;主干网络(Main Body)则综合各层次提取的信息进行深度学习;主干网络又被称为中间级表示模块(Middle-Level Representation Module)。
左边和右边各有两组3×3卷积层(分别为512通道和256通道),构成其主干结构。接着加入一个大小为5×5的卷积层(输出128通道)。最大池化操作步长设为2。随后经过反卷接上采样模块将特征图恢复到原始尺寸。
顶部分支包含依次生成128、64和32通道的三个3×3卷积层,在随后添加一个同样大小的卷积层(输出2通道),其激活函数采用Tanh函数。生成的结果包括两个向量,分别代表光流场在x轴和y轴上的偏移值。
Warper属于图像变形技术的一种,在接收原始图片及预测出的偏移量后,根据这些参数进行x轴和y轴方向上的位移操作,从而生成最终的变形图像。
4.5.1 测试Encoder
测试Encoder是否正确运行:
inputs = np.random.randn(1, 2, 3, 240, 320) # input shape is NCHW
encoder = Encoder().to('cuda')
outputs = encoder(torch.tensor(inputs).permute(0, 3, 4, 2, 1).to('cuda')).detach().cpu().numpy()[0][..., :256] # remove depth dimension
fig, axes = plt.subplots(nrows=4, ncols=8, figsize=(20, 10))
for i, ax in enumerate(axes.flatten()):
ax.imshow(outputs[i], cmap='jet')
ax.axis('off')
plt.show()
代码解读
测试结果如图2所示:
图2展示了Encoder生成的不同尺度下的特征图。
4.5.2 测试Decoder
测试Decoder是否正确运行:
features = np.random.randn(1, 512, 60, 80) # features shape is CHWD
decoder = Decoder().to('cuda')
output = decoder({'input_frames': torch.tensor(inputs).to('cuda'),
'left_feature': torch.tensor(features).unsqueeze(-1).to('cuda')}
).detach().cpu().numpy()[0]
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 10))
axes[0][0].imshow(output[:, :, 0], cmap='jet')
axes[0][0].set_title('x-offset')
axes[0][0].axis('off')
axes[0][1].imshow(output[:, :, 1], cmap='jet')
axes[0][1].set_title('y-offset')
axes[0][1].axis('off')
plt.show()
代码解读
测试结果如图3所示:
图3展示了Decoder预测的光流场偏移值图。
4.5.3 测试Warper
测试Warper是否正确运行:
warper = Warper().to('cuda')
inputs = np.random.randn(1, 2, 3, 240, 320) # input shape is NCHW
targets = {'target_flow': np.zeros((240//4, 320//4, 2))} # target shape is HW2
outputs = warper({'input_frames': torch.tensor(inputs).permute(0, 3, 4, 2, 1).to('cuda'),
'target_flow': torch.tensor(targets).permute(2, 0, 1).unsqueeze(0).to('cuda')}
).detach().cpu().numpy()[0]
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 10))
axes[0][0].imshow(outputs[0], cmap='jet')
axes[0][0].set_title('Warped Image')
axes[0][0].axis('off')
axes[0][1].imshow(targets['target_flow'][::-1, :, 0])
axes[0][1].set_title('Target X-Offset')
axes[0][1].axis('off')
axes[1][0].imshow(targets['target_flow'][::-1, :, 1])
axes[1][0].set_title('Target Y-Offset')
axes[1][0].axis('off')
plt.show()
代码解读
测试结果如图4所示:
图4展示了Warper将原始图片变形后的效果。
4.5.4 测试PWC-Net模型
测试PWC-Net模型是否正确运行:
model = PWCNet().to('cuda')
inputs = np.random.randn(1, 2, 3, 240, 320) # input shape is NCHW
outputs = model({'input_frames': torch.tensor(inputs).permute(0, 3, 4, 2, 1).to('cuda')}
)['target_flow'].squeeze().permute(1, 2, 0).detach().cpu().numpy()
fig, axes = plt.subplots(figsize=(10, 10))
axes.quiver(range(outputs.shape[0]), range(outputs.shape[1]), outputs[:,:,0], outputs[:,:,1])
plt.show()
代码解读
测试结果如图5所示:
图5展示了PWC-Net的预测结果。
5.总结与讨论
5.1 概括
PWC-Net旨在最近几年CVPR会议上首次提出一种用于光流估计的深度学习模型;其关键创新点在于:
- 基于Pyramid、Warping以及Cost Volume等技术构建CNN模型输入层。
- 开发出了一种新型图像金字塔网络结构(IPN)以增强深度学习网络的能力。
- 通过优化整合各子网络间的连接方式,并采用多分支架构以提高预测精度。
- 开发了一种新的优化目标函数用于光流场学习,并成功将之前难以单独优化的各项指标整合到一个统一的目标中。
同时,PWC-Net也具有一定的优点:
- 相较于现有的其他光流估计模型,PWC-Net具备更好的性能和精度。
- PWC-Net通过学习更深层次的语义特征而成功地获取了更为复杂的光流信息。
- PWC-Net采用了多分支结构这一设计以提高模型的鲁棒性,并在此基础上实现了预测精度的显著提升。
不过,PWC-Net也存在一些缺点:
- 必须建立多层次的图像金字塔以实现计算开销显著;
- 必须构建复杂而精密的优化目标函数模块以便获取高细节度的光流特征;
- 该系统受相机畸变、遮挡现象及噪声干扰的影响较为明显;
- 必须依靠大规模的数据集来进行训练工作。
由此可见,在当前阶段,PWC-Net仍属于一种新型的深度学习模型。为了进一步提高其准确性,更多的研究工作还需要进行。
5.2 个人看法
PWC-Net是一种极具吸引力的研究工作,在减少图像空间相关性的过程中采用了图像金字塔结构,并从不同尺度提取信息从而展现出更好的性能。研究者分别在编码与解码两个阶段进行处理,在解码过程中采用光流场作为输入并利用多分支架构提升模型的鲁棒性。该方法的目标函数整合了以往难以优化的关键指标从而带来耳目一新的感受
然而
总的来说,PWC-Net是一个很有潜力的模型,希望能在将来看到它的应用。
