光场深度估计论文阅读
目录
1.Feature Extraction and the SPP Module
3.Attention-based View Selection Module
4.3D CNN and Disparity Regression
介绍
多视角的图像有很多优势:
1、假设某一视角中的物体深度值不明确,可以改变场景的视角,并且重新关注物体,找到该其有效的深度值。
2、光场相机有更快的拍摄速度因为相比于传统相机不需要聚焦。
3、充分利用大量光圈可以更好的应用在光线亮度低的环境。
4、广场相机隐含的记录了深度信息,有很广泛的应用。
难点:
1、从光场图像中提取深度信息还是具有一定的挑战性的,因为子孔径图像的基准值很小;空间和角度分辨率的信息被硬件限制。
2、现如今提出了很多方法,在代价以及准确率上做出平衡。通过使用一组图像的子集来降低开销,但是不能充分利用光场图像的信息。
一、相关工作
1、传统方法:一些深度估计的传统方法使用了极平面图像,该图像包含了2D图像的空间和角度信息。除此之外,EPI图像包含不同线率的线,这些线由同一点从不同视点的投影形成。通过计算这些直线的线率,可以获得一张图像的视差图,(根据视差图可以求出深度图)。
2、深度学习方法:深度学习的方法已经运用在光场许多领域中,视角合成,图像压缩,超分辨,语义分割和深度估计等等。深度估计近年来已有很多的方法,但是在准确率和代价上,许多方法仅仅使用光场图像极平面的结构,只使用水平垂直和对角线的图像,这样无法利用子孔径图像全部的信息。因此,采用基于注意力机制的视角选择模型去寻找重要的子孔径图像来进行深度估计。
二、方法
模型的输入是81个视角,输出是中心视角的深度图。每个子孔径图像输入到光场中都要经过4个基础的残差网络,在第三层和第四层的残差网络,增加了dilation卷积使网络有一个更大的感受野。经过第一步得到的每个视角的特征图片都进入一个SPP(spatial pyramid pooling)模块中,该模块是用来扩展场景的上下文信息。之后将特征图拼接起来构建一个代价体。之后应用一个注意力机制的子孔径视角的选择模块去学习每个视角重要的信息。最后代价体和注意力图进行视差回归模型来预测中心视角的视差。
1.Feature Extraction and the SPP Module
对于预测视差,提取有效的特征是重要的。对于不同的区域,纹理区域和空间角平面区域提取纹理信息是有难度的。SPP模型通过使用层次上下文信息或者临近区域的关系可以提供丰富的特征。SPP模型可以从不同的尺度和子区域来提供层次上下文信息。
SPP模型结构:
1、采用四个不同大小的平均池化层来压缩特征。四个池化模块的大小分别是:2*2,4*4,8*8,16*16。
2、在池化层之后,给每个尺寸的池化层采用1*1的卷积层来降低特征维度。
3、使用bilinear interpolation来进行上采样一些低维度的特征。
4、将所有层级的特征图拼接起来作为SPP模块的输出特征图结果。
def feature_extraction(sz_input, sz_input2):
i = Input(shape=(sz_input, sz_input2, 1))
firstconv = convbn(i, 4, 3, 1, 1)
firstconv = Activation('relu')(firstconv)
firstconv = convbn(firstconv, 4, 3, 1, 1)
firstconv = Activation('relu')(firstconv)
layer1 = _make_layer(firstconv, 4, 2, 1, 1)
layer2 = _make_layer(layer1, 8, 8, 1, 1)
layer3 = _make_layer(layer2, 16, 2, 1, 1)
layer4 = _make_layer(layer3, 16, 2, 1, 2)
layer4_size = (layer4.get_shape().as_list()[1], layer4.get_shape().as_list()[2])
branch1 = AveragePooling2D((2, 2), (2, 2), 'same')(layer4)
branch1 = convbn(branch1, 4, 1, 1, 1)
branch1 = Activation('relu')(branch1)
branch1 = UpSampling2DBilinear(layer4_size)(branch1)
branch2 = AveragePooling2D((4, 4), (4, 4), 'same')(layer4)
branch2 = convbn(branch2, 4, 1, 1, 1)
branch2 = Activation('relu')(branch2)
branch2 = UpSampling2DBilinear(layer4_size)(branch2)
branch3 = AveragePooling2D((8, 8), (8, 8), 'same')(layer4)
branch3 = convbn(branch3, 4, 1, 1, 1)
branch3 = Activation('relu')(branch3)
branch3 = UpSampling2DBilinear(layer4_size)(branch3)
branch4 = AveragePooling2D((16, 16), (16, 16), 'same')(layer4)
branch4 = convbn(branch4, 4, 1, 1, 1)
branch4 = Activation('relu')(branch4)
branch4 = UpSampling2DBilinear(layer4_size)(branch4)
output_feature = concatenate([layer2, layer4, branch4, branch3, branch2, branch1])
lastconv = convbn(output_feature, 16, 3, 1, 1)
lastconv = Activation('relu')(lastconv)
lastconv = Conv2D(4, 1, (1, 1), 'same', use_bias=False)(lastconv)
model = Model(inputs=[i], outputs=[lastconv])
return model
2.Cost Volume Construction
CNN模块由于有限的感受野,很难通过连接特征图来直接估计位移。 如果位移大于感受野,CNN 就不可能预测正确的视差。使用代价体的方式可以充分利用特征信息。
1、通过SPP模块,将输入的图片根据不同的视差等级,沿着u,v方向做转换,这样以后,后面的网络使用相对较小的感受野,也可以直接的看到不同空间位置的像素信息。
2、总共有9个不同的视差等级(-4~4),在转换完特征图之后,将特征图变成5D的代价体,大小为:Batch size × #Disparity × Height × Width × Feature dimension
def _getCostVolume_(inputs):
shape = K.shape(inputs[0])
disparity_costs = []
for d in range(-4, 5):
if d == 0:
tmp_list = []
for i in range(len(inputs)):
tmp_list.append(inputs[i])
else:
tmp_list = []
for i in range(len(inputs)):
(v, u) = divmod(i, 9)
tensor = tf.contrib.image.translate(inputs[i], [d * (u - 4), d * (v - 4)], 'BILINEAR')
tmp_list.append(tensor)
cost = K.concatenate(tmp_list, axis=3)
disparity_costs.append(cost)
cost_volume = K.stack(disparity_costs, axis=1)
cost_volume = K.reshape(cost_volume, (shape[0], 9, shape[1], shape[2], 4*81))
return cost_volume
3.Attention-based View Selection Module
子孔径图像提供大量但冗余的视差信息。由于光场图像的结构是高度对称的,基于注意的视角选择模块可以找到大量的有意义的视角能够提高中心视角视差图的准确率。
1、一共有三种注意力的方式:第一种是每个视角都有一个权重的注意力方式; 第二种是将注意力图对称的沿着u,v进行计算,只需要25个学习的权重,整个图也是镜像的沿着u、v构建; 第三种是对称着沿着u,v和对角线轴进行计算,只需要进行15个权重值。
2、将代价体作为输入,注意力机制的选择模块通过一个全局的池化层和两个全连接层,和一个sigmoid层,生成一个注意力图。
3、之后将代价体的特征与相关的注意力分数乘起来,最终用元素的乘积作为相关注意力得分,每个视角的注意力图被建立起来。
def channel_attention(cost_volume):
x = GlobalAveragePooling3D()(cost_volume)
x = Lambda(lambda y: K.expand_dims(K.expand_dims(K.expand_dims(y, 1), 1), 1))(x)
x = Conv3D(170, 1, 1, 'same')(x)
x = Activation('relu')(x)
x = Conv3D(15, 1, 1, 'same')(x) # [B, 1, 1, 1, 15]
x = Activation('sigmoid')(x)
# 15 -> 25
# 0 1 2 3 4
# 5 6 7 8
# 9 10 11
# 12 13
# 14
#
# 0 1 2 3 4
# 1 5 6 7 8
# 2 6 9 10 11
# 3 7 10 12 13
# 4 8 11 13 14
x = Lambda(lambda y: K.concatenate([y[:, :, :, :, 0:5], y[:, :, :, :, 1:2], y[:, :, :, :, 5:9], y[:, :, :, :, 2:3],
y[:, :, :, :, 6:7], y[:, :, :, :, 9:12], y[:, :, :, :, 3:4], y[:, :, :, :, 7:8],
y[:, :, :, :, 10:11], y[:, :, :, :, 12:14], y[:, :, :, :, 4:5], y[:, :, :, :, 8:9],
y[:, :, :, :, 11:12], y[:, :, :, :, 13:15]], axis=-1))(x)
x = Lambda(lambda y: K.reshape(y, (K.shape(y)[0], 5, 5)))(x)
x = Lambda(lambda y: tf.pad(y, [[0, 0], [0, 4], [0, 4]], 'REFLECT'))(x)
attention = Lambda(lambda y: K.reshape(y, (K.shape(y)[0], 1, 1, 1, 81)))(x)
x = Lambda(lambda y:K.repeat_elements(y, 4, -1))(attention)
return multiply([x, cost_volume]), attention
def channel_attention_free(cost_volume):
x = GlobalAveragePooling3D()(cost_volume)
x = Lambda(lambda y: K.expand_dims(K.expand_dims(K.expand_dims(y, 1), 1), 1))(x)
x = Conv3D(170, 1, 1, 'same')(x)
x = Activation('relu')(x)
x = Conv3D(81, 1, 1, 'same')(x)
x = Activation('sigmoid')(x)
attention = Lambda(lambda y: K.reshape(y, (K.shape(y)[0], 1, 1, 1, 81)))(x)
x = Lambda(lambda y:K.repeat_elements(y, 4, -1))(attention)
return multiply([x, cost_volume]), attention
4.3D CNN and Disparity Regression
1、使用一个3D CNN结构作为代价体的视差回归,结构是由8个3*3*3的卷积层组成,从第3层卷积层到第6层卷积层使用两层残差模块。
2、在经过3D卷积层之后,获得的输出的代价体从5D转换为4D(Batch size × #Disparity × Height × Width)。
3、采取winner-takes-all的算法。采取一个加权求和,能够适用argmin operator。为了计算每个视差值,我们需要采取每个负值来进行代价体的代价预测并且将这些值采用softmax函数进行标准化。
4、在得到每个视差值标准的可能性之后,最终通过对每个图片的视差值权重求和来计算结果。
def basic(cost_volume):
feature = 2*75
dres0 = convbn_3d(cost_volume, feature, 3, 1)
dres0 = Activation('relu')(dres0)
dres0 = convbn_3d(dres0, feature, 3, 1)
cost0 = Activation('relu')(dres0)
dres1 = convbn_3d(cost0, feature, 3, 1)
dres1 = Activation('relu')(dres1)
dres1 = convbn_3d(dres1, feature, 3, 1)
cost0 = add([dres1, cost0])
dres4 = convbn_3d(cost0, feature, 3, 1)
dres4 = Activation('relu')(dres4)
dres4 = convbn_3d(dres4, feature, 3, 1)
cost0 = add([dres4, cost0])
classify = convbn_3d(cost0, feature, 3, 1)
classify = Activation('relu')(classify)
cost = Conv3D(1, 3, 1, 'same', use_bias=False)(classify)
return cost
def disparityregression(input):
shape = K.shape(input)
disparity_values = np.linspace(-4, 4, 9)
x = K.constant(disparity_values, shape=[9])
x = K.expand_dims(K.expand_dims(K.expand_dims(x, 0), 0), 0)
x = tf.tile(x, [shape[0], shape[1], shape[2], 1])
out = K.sum(multiply([input, x]), -1)
return out
总结
提出了注意力机制的选择网络来进行视差估计,并且能够利用全部的视角进行视差估计。