写在前面

原始视频(30fps)

补帧后的视频(240fps)

  本文是博主在做实验的过程中使用到的方法,刚好也做为了本科毕设的翻译文章,现在把它搬运到博客上来,因为觉得这篇文章的思路真的不错。

  这篇文章的简要思路:整个网络由两个U-Net构成,第一个U-Net负责计算光流,第二个U-Net负责矫正光流(有点借鉴了残差的意思),从而对视频进行补帧。

  参考资料:

  转载请注明出处,谢谢。

  PS:文章有些内容涉及到公式,不方便搬运,所以采用了图片的方式。

摘要

  在给定两个连续帧的情况下,视频插值的目标是生成中间帧,形成时空相干的视频序列。大多数现有的视频插值方法都集中在单帧插值上,我们提出了一种端到端的卷积神经网络,用于任意多帧的视频插值,该网络中的运动解释和遮挡推理是联合建模的。我们首先使用U-Net结构来计算相邻输入图像之间的双向光流。然后,在每个时间步长上对这些光流进行线性拟合,以近似中间帧的双向光流。然而,这些近似的光流只在局部平滑区域有用,而在运动边界附近产生了伪影。为了解决这一问题,我们使用另一个U-Net来对近似的光流进行改善,并且预测柔性可见性映射关系。最后,将输入的两张图像进行扭曲和线性融合,从而形成中间帧。通过在融合前的扭曲图像上应用可见性映射关系,我们解决了被遮挡的像素对中间帧的影响,从而避免了伪影的产生。由于我们所学习的网络参数没有一个是与时间相关的,因此我们的方法能够根据需要生成尽可能多的中间帧。为了训练我们的网络,我们使用了1132个240帧的视频段,其中包含30万个独立的视频帧。在多个数据集上的实验结果表明,我们的方法比现有的方法具有更好的时空连续性。

1 引言

  在你的生活中有着许多难忘的时刻,比如婴儿第一次学会走路,一个很困难的滑板技巧,一只刚接住球的狗,等等。但由于它们很难看清楚细节,所以你可能想用慢镜头记录下来。虽然用手机拍摄240帧的视频是有可能的,但想要获得更高帧数高速摄像机仍是需要的。此外,很多我们想要慢下来的时刻是不可预测的,所以通常这些时刻都是以标准帧速来被记录下来的。以高帧率记录一切是不切实际的,它需要很大的内存,而且对移动设备来说耗电量也是一大难题。

  因此,从已有的视频中生成高质量的慢动作视频具有重要的意义。除了将标准视频转换为高帧率视频外,还可以使用视频插值来生成平滑的视频过场镜头。它在自监督学习中也有有趣的应用,它可以作为监督信号来从未标记的视频中学习光流运算。

  生成多个视频中间帧是一项挑战,因为这些帧必须在时间和空间上保持连续性。例如,从标准的30帧视频生成240帧视频需要相邻帧之间插入7个中间帧。一个优秀的算法不仅要正确地解释输入的相邻帧之间的运动(隐式或显式),还要理解遮挡。否则,它可能会在生成的中间帧内产生严重的伪影,尤其是在运动边界周围。

  现有的方法主要集中于单帧视频插值,对于该问题人们已经取得了令人印象深刻的性能。然而,这些方法不能直接用于生成任意高帧率的视频。虽然递归地应用单帧视频插值方法生成多个中间帧是一个很有吸引力的想法,但是这种方法至少有两个限制。首先,递归的单帧插值不能完全并行化计算,因此速度很慢,因为一些中间帧在其他帧完成之前是无法计算的。而且错误也会在递归运算中累加。其次,它只能生成个中间帧。因此,这种方法不能用于从24帧视频生成1008帧视频,因为其需要在每帧之间生成额外的41帧中间帧。

  本文提出了一种高质量的变长多帧插值方法,它可以在两帧之间的任意时间步长上插上一帧。我们的主要思想是将输入的两幅图像扭曲到特定的时间步长,然后自适应地融合这两幅扭曲的图像,从而生成中间图像,运动解释和遮挡推理都放在了一个端到端的可训练网络中进行建模。具体来说,我们首先使用一个计算光流的CNN来计算输入的相邻图像的双向光流,然后用线性拟合的方式来近似所需的中间光流,用于对输入的图像进行扭曲。这种近似方法在平滑区域效果较好,但在运动边界附近效果很差。因此,我们使用了另一个计算光流插值的CNN来改善光流的近似和预测可见性映射关系。通过将可见性映射关系应用到融合前的扭曲图像,我们解决了被遮挡的像素对插值中间帧的影响,减少了伪影。我们的光流计算网络和插值网络的参数都不依赖于被插值帧的特定时间步长(时间步长被做为网络的输入)。因此,我们的方法可以并行生成所需的任意多的中间帧。

  为了训练我们的网络,我们从YouTube和手提摄像机上收集了多个240帧的视频。总计收集了1100个视频段,由30万张1080×720分辨率的独立的视频帧组成。然后我们在一系列的其他独立的数据集上验证了我们训练好的模型,这些数据集需要不同数量的插值,包括Middlebury,UCF101,slowflow数据集和高帧率MPI Sintel。实验结果表明我们的研究在这些数据集上比现有的方法性能上有了显著的提高。我们还在无监督学习光流计算比赛KITTI2012上验证了我们的结果,获得了比近期方法还要好的结果。

2 相关研究

2.1 视频插值

  传统的视频插值方法都是基于光流的,而光流算法常常使用插值精度来评价。这种方法可以在两个输入帧之间的任意时间生成中间帧。外卖的实验结果表明,最先进的光流算法与遮挡推理相结合,可以作为视频帧插值的一个强有效的参考基线。然而,运动边界和严重的遮挡对现有的基于光流的插值方法仍然具有挑战性,因此插值帧往往会在运动对象边界附近产生伪影。此外,中间帧的光流插值计算和遮挡推理都是基于启发式的算法,而不是端到端可训练的。

  马哈詹等人将图像的梯度移动到给定的时间步长,并求解泊松方程来重构插值帧。该方法还可以生成多个中间帧,但由于该算法是一个复杂的优化问题,所以计算量太大。迈耶等人提出在视频插值的时候,将相位信息通过多尺度金字塔传播。这种方法虽然取得了令人印象深刻的性能,但对于运动较大的高频内容效果仍然不好。

  深度学习在高级视觉任务中的成功,激发了许多低级视觉任务的深度模型,其中就包括帧插值。隆等人利用帧内插作为监控信号,来学习CNN光流模型。然而,它们的主要目标是光流,导致了插值帧往往是模糊的。尼克劳斯等人将帧插值看作是两个输入帧上的局部卷积,并使用CNN学习每个像素的空间自适应卷积核。他们的方法取得了高质量的结果。然而,为每个像素计算一个卷积核的计算开销和内存消耗都很高。尼克劳斯等人通过计算可分离的内核提高了效率。但是可以处理的运动范围受到卷积核大小(最多51个像素)的限制。刘等人开发了一种用于帧插值的CNN模型,该模型具有用于运动估计的显式子网络。他们的方法不仅得到了很好的插值结果,而且在无监督的KITTI 2012数据集上也得到了很好的光流估计结果。但是,如前所述,这些基于CNN的单帧插值方法不适用于多帧插值。

  王等人研究了如何使用另一个普通相机拍摄的视频帧作为参考来生成光场视频的中间帧。相比之下,我们的方法是针对普通视频生成中间帧,不需要参考图像。

2.2 学习光流

  最先进的光流计算方法采用Horn-Schunck引入的变分方法。特征匹配常被用来处理小而快速移动的对象。然而,这种方法需要对复杂的目标函数进行优化,所以通常计算开销很大。用学习的方法计算光流也常常局限于几个参数。

  近年来,基于CNN的模型在学习输入图像间的光流方面越来越受欢迎。多索维斯基等人开发了两个网络架构:FlowNetS和FlowNetC,并证明了使用CNN模型学习从两个输入图像映射到光流的可行性。艾尔吉等人进一步使用FlowNetS和FlowNetC作为基础块来设计更大的网络FlowNet2来实现更好的性能。最近还提出了两种方法来将光流的经典原理算法构建到网络中,与FlowNet2相比,这种方法实现了更好的结果,并且只需更少的计算量。

  除了有监督的学习方法外,学者们还探索了利用CNN进行无监督学习光流的方法。其主要思想是使用预测的光流将一个输入图像扭曲到另一个。重建误差是训练网络的损失函数。此外,一种存储模块也被学者提出,这种存储模块不仅仅考虑两帧,而是保存了视频序列的时间信息。与我们的工作类似,梁等人通过在视频帧上进行推理,来训练光流的计算,但他们的训练方法使用了EpicFlow方法作为额外的目标函数。

3 本文方法

  在本节中,我们首先在3.1节中介绍了基于光流的中间帧合成。然后,我们将在3.2节中详细解释我们的光流计算和光流插值网络。在3.3节中,我们定义了用于训练网络的损失函数。

3.1 中间帧合成

3.2 任意时间的光流插值

3.3 训练

4 实验

4.1 数据集

  为了训练我们的网络,我们使用了从[29]中用手持摄像机拍摄的240帧视频。我们还从YouTube上收集了240帧的一些视频数据集。表1总结了这两个数据集的统计数据,图5展示了从中随机挑选处的视频帧截图:

表1:用于训练网络的数据集统计数据。

图5:训练数据截图。

  我们总计有1132个视频段和37.6万张独立的视频帧。从室内到室外,从静态相机到动态相机,从日常活动到专业运动,这两个数据集中都有大量的场景。

  我们使用所有的数据来训练网络,并在几个独立的数据集中测试模型,包括Middlebury基准数据集、UCF101、slowflow数据集和高帧率Sintel序列。对于Middlebury数据集,我们将8个序列的单帧视频插值结果提交给它的评估服务器。对于UCF101,在每三帧中,第一帧和第三帧作为输入,使用[15]提供的379个序列预测第二帧。slowflow数据集包含46个用专业高速摄像机拍摄的视频。我们使用第一帧和第八帧作为输入,并插入中间的7帧,相当于将一个30帧的视频转换为一个240帧的视频。原始Sintel序列[4]以24帧每秒的速度呈现。其中13个在1008 fps[10]重新渲染。要使用视频帧插值方法将24帧转换为1008帧,需要插入41帧之间的帧。但是,正如在介绍中所讨论的,使用递归单帧插值方法[19,20,15]是不可能直接做到这一点的。因此,我们在帧与帧之间预测31帧,以便与之前的方法进行公平的对比。

  我们的网络使用Adam优化器[12]进行了500轮的训练。初始化学习率为0.0001,每200轮降低10倍。在训练过程中,所有的视频片段首先被分成较短的视频片段,每个视频片段有12帧,两个视频片段之间没有重叠。为了增强数据,我们随机反转整个序列的方向,选择9个连续帧进行训练。在图像层面,将每个视频帧的长宽调整为360个像素,随机裁剪成352×352的图片,外加水平翻转。

  为了验证模型,我们计算了预测的视频中间帧与真实中间帧之间的峰值信噪比(PSNR)和结构相似度(SSIM)评分,以及插值误差(IE)[1],其定义为真实图像与插值图像之间的均方根差(RMS)。

4.2 可行性研究

  在本节中,我们进行对比实验来分析我们的模型。在前两个实验中,我们从Adobe240帧数据集中随机抽取107个视频进行训练,其余12个视频用于测试。

4.2.1 多帧视频插值的有效性

  首先,我们测试了同时预测多个中间帧是否能改善视频插值结果。直观地说,同时预测一组中间帧可能隐式地强制让网络生成时间相干的序列。

  为此,我们训练了模型的三种变体:预测单帧、三帧和七帧,它们都均匀地分布在时间步长上。在测试时,我们使用每个模型来预测7个中间帧。表2清楚地表明了我们在训练中预测的中间帧越多,模型就越好。

表2:多帧视频插值在Adobe240帧数据集上的有效性。

4.2.2 不同组件设计的影响

我们还研究了模型中每个组件的贡献。尤其是光流插值的效果,通过从第二个U-Net中删除对光流的改善(保留可见性映射关系)。我们进一步研究了使用可见性映射关系作为遮挡推理的方法。从表3可以看处,删除这三个组件都会影响性能。

表3:不同组件的有效性。

  其中,光流插值起着至关重要的作用,验证了我们引入第二个网络来改善中间光流近似的目的。添加可见性映射关系稍微提高了插值的性能。没有它,就会在运动边界附近产生伪影,如图3所示。这两种方法都验证了我们的假设,即同时学习运动解释和遮挡推理有助于视频插值。

  我们还研究了不同的损失项,其中扭曲损失是最重要的一项。虽然添加平滑项会对性能造成一定影响,但我们发现它生成的光流会更满足视觉上的需求。

4.2.3 训练样本数量的影响

  最后,我们研究了训练样本数量的影响。我们比较了两个模型:一个只针对Adobe240帧数据集进行训练,另一个针对完整数据集进行训练。这两个模型在UCF101数据集上的性能如表4的最后两行所示:

表4:在UCF101数据集上的结果。

  我们可以看到我们的模型适合更多的训练数据。

4.3 与最新方法的对比

  在本节中,我们将我们的方法与现有的方法进行比较,包括基于相位的插值[18]、可分离自适应卷积[20]和深度体素流[15]。我们还使用[1]中提出的插值算法实现了基准方法,其中我们使用FlowNet2[9]来计算两个输入图像之间的双向光流结果。FlowNet2能够很好地捕捉光流的全局背景运动,恢复光流的锐化运动边界。因此,当与遮挡推理[1]相结合时,FlowNet2能够作为一个强有力的基准。

4.3.1 单帧视频插值

  Middlebury数据集中每个序列的插值误差(IE)得分如图6所示:

图6:在Middlebury数据集的每个序列上的性能比较。数据从Middlebury验证服务器上获取。

  除了SepConv,我们还将我们的模型与Middlebury数据集上其他三个性能最好的模型进行了比较,其中插值算法[1]与不同的光流方法耦合,包括MDP-Flow2[37]、PMMST[39]和DeepFlow[34]。我们的模型在所有8个序列中有6个序列的性能最好。特别是城市视频序列是综合性能最好的,泰迪熊视频序列实际上包含两对立体对。模型的性能验证了该方法的泛化能力。

  在UCF101数据集上,我们使用[15]提供的运动掩码来计算所有性能指标,结果如表4所示,突出了各插值模型处理复杂运动区域能力的表现。我们的模型始终优于非神经网络方法[18]和基于CNN的方法[20, 15]。在UCF101数据集上插值结果的样例展示在图7中,更多的结果可以在补充资料中找到。

 图7:UCF101数据集上的结果。我们的模型在画笔和手的周围产生的伪影更少(在颜色上看效果最好)。如果需要更多图像和视频结果,请参阅补充资料。

4.3.2 多帧视频插值

  对于slowflow数据集,我们预测7帧中间帧。所有实验均在分辨率为1280×1024的半分辨率图像上进行。在该数据集上,我们的方法获得了最佳的PSNR和SSIM评分,而FlowNet2获得了最佳的SSIM和L1错误评分。FlowNet2善于捕捉全局运动,从而对这些背景区域产生了清晰的预测结果,这些背景区域遵循全局运动模式。详细的视觉对比可以在我们的补充资料中找到。

表5:在slowflow数据集上的结果。

  在具有挑战性的高帧率Sintel数据集上,我们的方法明显优于其他所有方法。我们还在图8中显示了每一步的PSNR得分。我们的方法为每个时间间隔步骤生成最佳预测,除了最后一个时间步的结果会比SepConv稍差一些。

表6:在高帧率Sintel数据集上的结果。

图8:在高帧率Sintel数据集上生成31个中间帧时每一步的PSNR。

  综上,我们的方法可以在所有数据集上获得最好的结果,生成单个或多个中间帧。值得注意的是,我们的模型可以直接应用于不同的场景而无需任何修改。

4.4 无监督的光流学习

  我们的视频帧插值方法有一个无监督(自监督)网络(光流计算CNN),可以计算两个输入图像之间的双向光流。在[15]之后,我们在KITTI 2012光流基准[6]测试集上评估了我们的无监督正向光流结果。不同方法的平均点误差(EPE)得分见表7:

表7:在KITTI2012基准数据集上的光流计算结果。

  与以前的无监督方法DVF[15]相比,我们的模型平均EPE为13.0,相对提高了11%。这种改进很可能是由于多帧视频插值设置的结果,因为DVF[15]具有类似于我们的U-Net架构。

5 总结

  我们提出了一种端到端可训练的CNN,它可以在两个输入图像之间生成任意多的中间视频帧。我们首先使用光流计算CNN来估计两个输入帧之间的双向光流,并将两个光流场进行线性融合来近似中间光流场。然后,我们使用光流插值CNN对近似的光流场进行改善,并预测用于插值的柔性可见性映射关系。我们使用超过1100个 240帧的视频段来训练我们的网络,训练时预测7个中间帧。对不同验证集的可行性研究证明了光流插值和可见性映射关系的优点。在Middlebury、UCF101、slowflow和高帧率Sintel数据集中,我们的多帧方法始终优于最先进的单帧视频插值方法。在光流的无监督学习方面,我们的网络在KITTI 2012基准数据集上优于最近的DVF方法[15]。

致谢

  我们要感谢Oliver Wang慷慨地分享了Adobe240帧数据。Yang致谢国家科学基金会的支持(批准号:1149783)。

6 附录

6.1 网络结构

  我们的光流计算和光流插值CNN共享同一个U-Net结构,如图9所示:

图9:光流计算和光流插值CNN网络结构示意图。

6.2 UCF101数据集的可视化对比

  图10和图11展示了UCF101数据集上单帧插值结果的可视化对比。更多的可视化对比请参考我们的补充视频:http://jianghz.me/projects/superslomo/superslomo_public.mp4

图10:UCF101数据集上的可视化对比。(a)真实中间帧,插值结果有(b)基于相位的插值[18],(c)FlowNet2[7,9],(d)SepConv[20],(e)DVF[15],和(f)我们的方法。

图11:UCF101数据集上的可视化对比。(a)真实中间帧,插值结果有(b)基于相位的插值[18],(c)FlowNet2[7,9],(d)SepConv[20],(e)DVF[15],和(f)我们的方法。

写在后面

其实看论文不如看代码来的快,很多细节都写在代码里了,以下是我看代码时的笔记,仅供大家参考:

模型一:flow computation flowComp:UNet(6, 4) 输入两幅图像,所以是6个通道,输出两个光流,所以是4个通道(光流分为x方向和y方向)。

模型二:arbitrary-time flow interpolation ArbTimeFlowIntrp:UNet(20, 5) 输入两幅图像(6)、两幅光流(4)、两个g(10),输出两个光流差(4)和1个遮挡判断(1)

模型三:trainFlowBackWarp:backWarp(352, 352)

模型四:validationFlowBackWarp:backWarp(640, 352)

Loss:L1_lossFn 、 MSE_LossFn

optimizer = optim.Adam

scheduler = MultiStepLR

vgg16_conv_4_3 禁用梯度

validate过程

取三帧,把前后两帧送入flowComp,得到双向光流。

然后用这两个光流来近似计算中间帧的双向光流 F_t_0、F_t_1

然后用backWarp来warp出中间图像g_I0_F_t_0 = I0 + F_t_0         g_I1_F_t_1 = I1 + F_t_1   

然后把一堆东西

输入 ArbTimeFlowIntrp( I0(3) + I1(3) + F_0_1(2) + F_1_0(2) + F_t_1(2) + F_t_0(2) + g_I1_F_t_1(3) + g_I0_F_t_0(3) = 20 )

输出 intrpOut( ΔF_t_0_f(2) + ΔF_t_1_f(2) + V_t_0(1) = 5 )

由网络输出的光流Δ量来计算 F_t_0_f = ΔF_t_0_f + F_t_0            F_t_1_f = ΔF_t_1_f + F_t_1

然后用这两个光流来warp出中间图像 g_I0_F_t_0_f = I0 + F_t_0_f               g_I1_F_t_1_f = I1 + F_t_1_f

然后用这两个中间图像和遮挡变量V来算出 Ft_p

计算Loss: recnLoss: 由Ft_p和IFrame(中间帧)计算L1重建损失、prcpLoss: 用vgg16来提取特征,再用MSE来计算两个图像的语义差、warpLoss: g_I0_F_t_0和IFrame的L1损失+g_I1_F_t_1和IFrame的重建损失+由I0和F_1_0 warp出的图像和I1的L1损失 + 由I1和F_0_1 warp出的图像和I0的L1损失

然后smooth一下loss,再计算出来加起来就好了

训练过程

过程和validate一样

[AI] 论文笔记 - CVPR2018 Super SloMo: High Quality Estimation of Multiple Intermediate Frames for Video Interpolation的更多相关文章

  1. [AI] 论文笔记 - U-Net 简单而又接近本质的分割网络

    越简单越接近本质. 参考资料 U-Net: Convolutional Networks for Biomedical Image Segmentation Abstract & Introd ...

  2. 论文笔记(5):Fully Convolutional Multi-Class Multiple Instance Learning

    这篇论文主要介绍了如何使用图片级标注对像素级分割任务进行训练.想法很简单却达到了比较好的效果.文中所提到的loss比较有启发性. 大体思路: 首先同FCN一样,这个网络只有8层(5层VGG,3层全卷积 ...

  3. 论文笔记之:Heterogeneous Face Attribute Estimation: A Deep Multi-Task Learning Approach

    Heterogeneous Face Attribute Estimation: A Deep Multi-Task Learning Approach  2017.11.28 Introductio ...

  4. 【论文笔记】Learning Fashion Compatibility with Bidirectional LSTMs

    论文:<Learning Fashion Compatibility with Bidirectional LSTMs> 论文地址:https://arxiv.org/abs/1707.0 ...

  5. 论文阅读笔记(十六)【AAAI2018】:Region-Based Quality Estimation Network for Large-Scale Person Re-Identification

    Introduction (1)Motivation: 当前的行人重识别方法都只能在标准的数据集上取得好的效果,但当行人被遮挡或者肢体移动时,往往效果不佳. (2)Contribution: ① 提出 ...

  6. Deep Learning论文笔记之(八)Deep Learning最新综述

    Deep Learning论文笔记之(八)Deep Learning最新综述 zouxy09@qq.com http://blog.csdn.net/zouxy09 自己平时看了一些论文,但老感觉看完 ...

  7. 论文笔记:Mastering the game of Go with deep neural networks and tree search

    Mastering the game of Go with deep neural networks and tree search Nature 2015  这是本人论文笔记系列第二篇 Nature ...

  8. 论文笔记:CNN经典结构1(AlexNet,ZFNet,OverFeat,VGG,GoogleNet,ResNet)

    前言 本文主要介绍2012-2015年的一些经典CNN结构,从AlexNet,ZFNet,OverFeat到VGG,GoogleNetv1-v4,ResNetv1-v2. 在论文笔记:CNN经典结构2 ...

  9. AI理论学习笔记(一):深度学习的前世今生

    AI理论学习笔记(一):深度学习的前世今生 大家还记得以深度学习技术为基础的电脑程序AlphaGo吗?这是人类历史中在某种意义的第一次机器打败人类的例子,其最大的魅力就是深度学习(Deep Learn ...

随机推荐

  1. 2019杭电多校第二场hdu6601 Keen On Everything But Triangle

    Keen On Everything But Triangle 题目传送门 解题思路 利用主席树求区间第k小,先求区间内最大的值,再求第二大,第三大--直到找到连续的三个数可以构成一个三角形.因为对于 ...

  2. FSCapture 取色工具(绿色版 )

    百度云: 链接:http://pan.baidu.com/s/1kV7BhVD 密码:zel3

  3. K-Means(K均值)、GMM(高斯混合模型),通俗易懂,先收藏了!

    1. 聚类算法都是无监督学习吗? 什么是聚类算法?聚类是一种机器学习技术,它涉及到数据点的分组.给定一组数据点,我们可以使用聚类算法将每个数据点划分为一个特定的组.理论上,同一组中的数据点应该具有相似 ...

  4. 201809-2买菜 ccf

    只得了90分,很奇怪,有大佬指导一下吗 #include<stdio.h> int main() { ,sum=; scanf("%d",&n); *n],b[ ...

  5. IntegerCache的妙用和陷阱

    转载自IntegerCache的妙用和陷阱 考虑下面的小程序,你认为会输出为什么结果? public class Test {     public static void main(String[] ...

  6. hdu第十场Cyclic

    本题主要是对用容斥的使用,正难则反,对于要求满足题意的可以求不满足题意的 先考虑对于长度至少为2的连续序列,易得其排列C(n,1)*(n-2)!,意为从剩下n个数字中选取连续的两个. 方法总计为n,即 ...

  7. Java多线程笔记总结

    1.线程的三种创建方式 对比三种方式: 通过继承Thread类实现 通过实现Runnable接口 实现Callable接口 第1种方式无法继承其他类,第2,3种可以继承其他类: 第2,3种方式多线程可 ...

  8. Integrating Thymeleaf with Spring

    这个是基于注解的配置方式,基于配置文件的http://www.cnblogs.com/honger/p/6875148.html 一.整体结构图 二.web.xml文件,这里使用了注解的方式 < ...

  9. 【iOS】edgesForExtendedLayout

    在 iOS 7.0 中,苹果引入了一个新的属性,叫做 edgesForExtendedLayou,它的默认值为 UIRectEdgeAll. 当你的容器是 navigationController 时 ...

  10. Linux基础管道管理

    一.I/O重定向 标准输入,标准输出,标准错误 file descriptors (FD, 文件描述符或Process I/O channels); 进程使用文件描述符来管理打开的文件 [root@l ...