FlowNet: Learning Optical Flow with Convolutional Networks
pdf与相关代码: https://lmb.informatik.uni-freiburg.de/resources/binaries/

光流(Optical Flow)介绍

1. 光流原理

光流分为稀疏光流和稠密光流,稀疏光流就是只计算图片中特定点的光流,而稠密光流则是每个像素都要计算光流。
简单地说就是在连续图片序列中,从第t帧到第t+1帧,每个像素的运动速度和运动方向。
比如第t帧的时候A点的位置是(x1, y1),那么我们在第t+1帧的时候再找到A点,假如它的位置是(x2,y2),即It(x1,y1)=It+1(x2,y2)=It+1(x1+ux,x1+uy) I t ( x 1 , y 1 ) = I t + 1 ( x 2 , y 2 ) = I t + 1 ( x 1 + u x , x 1 + u y ) , 那么我们t->t+1的光流即为:(ux,vy) ( u x , v y ) 。所以给定一对图片(t -> t-1),就可以计算出这对图片之间的光流图,大小和两帧的图片相同。
有了t->t+1的光流,我们可以利用t+1帧的图片和这个光流将t+1帧warp到t帧,得到t帧的图片。怎么计算呢?对于第t帧上的每个像素点It(x1,y1) I t ( x 1 , y 1 ) ,都有It(x1,y1)=It+1(x1+ux,x1+uy) I t ( x 1 , y 1 ) = I t + 1 ( x 1 + u x , x 1 + u y ) ,直接在t+1帧上取出(x1+ux,x1+uy) ( x 1 + u x , x 1 + u y ) 位置处的值就好,这个坐标极有可能是浮点数,双线性插值即可。
想通过光流推测某一帧图片,只要计算该帧到已知帧的光流即可通过warp得到
比如我们想通过光流增强特征,已知t-1,t-3的特征,想用它们增强当前帧t的特征,只需要计算t->t-1和t->t-3的光流,然后利用这两个光流就可以把t-1,t-3的特征warp到t了。更多应用可查看我另一篇博客利用光流提升视频识别的速度和精度

2. 光流可视化

光流场是图片中每个像素都有一个x方向和y方向的位移,所以在上面那些光流计算结束后得到的光流flow是个和原来图像大小相等的双通道图像。

不同颜色表示不同的运动方向,深浅表示运动的速度。

深度学习 光流估计 光流技术_光流


讲x和y转为极坐标,夹角(actan2(y,x))代表方向,极径(x和y的平方和开根号)代表位移大小,刚好用一下hsv的图像表示。上图的光流可以看到,红色的人在往右边动,那个蓝色的东西在往左上动

深度学习 光流估计 光流技术_光流_02

def viz_flow(flow):
    # 色调H:用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°
    # 饱和度S:取值范围为0.0~1.0
    # 亮度V:取值范围为0.0(黑色)~1.0(白色)
    h, w = flow.shape[:2]
    hsv = np.zeros((h, w, 3), np.uint8)
    mag, ang = cv2.cartToPolar(flow[...,0], flow[...,1])
    hsv[...,0] = ang*180/np.pi/2
    hsv[...,1] = cv2.normalize(mag,None,0,255,cv2.NORM_MINMAX)
    # flownet是将V赋值为255, 此函数遵循flownet,饱和度S代表像素位移的大小,亮度都为最大,便于观看
    # 也有的光流可视化讲s赋值为255,亮度代表像素位移的大小,整个图片会很暗,很少这样用
    hsv[...,2] = 255
    bgr = cv2.cvtColor(hsv,cv2.COLOR_HSV2BGR)
    return bgr

论文主要贡献

  1. 首次将CNN运用到光流预测上,设计了两种网络结构
  2. 提出了一个Flying chairs的数据集,并利用这个虚拟合成的数据集训练网络,得到的模型能很好的泛化到实际图片中,而且效果达到了state of art

网络结构

由于卷积神经网络中一层有一层pooling后特征图越来越小,而最终预测的光流是要和原图大小相同,所以还需要放大(unconv),所以网络整体上分为两个部分,一个缩小还有一个放大

缩小(卷积)部分

  1. FlowNetSimple
    第一种缩小(卷积)方案是最朴素的方法的,就是将这一对图片的通道concat起来,网络结构图中可以看到输入的data层的channel是6.
  2. FlowNetCorr
    第二中方案是这一对图片分开处理,分别进入卷积网路,得到各自的特征图,然后再找到它们特征图之间的联系。
    两个特征图分别为f1,f2: w * h * c, 然后corr层比较这两个特征图各个块。比如以x1为中心的一块和以x2为中心的一块,它们之间的联系用以下公式计算,块长为K:= 2k+1,大小为 K*K。

深度学习 光流估计 光流技术_光流_03

该公式和卷积的操作是一样的,以x1为中心的patch和以x2为中心的patch,对应位置相乘然后相加,这就是卷积核在图片上的操作啊,只是卷积网络里是和filter之间进行卷积,且它的weight是不需训练或不可训练。计算这两块之间的联系计算复杂度是 c * K * K,而f1上每个块都要与f2上所有块计算联系,f1上有w * h个块(每个像素点都可以做一个块的中心点),f2上也有w * h个块,所有整个计算复杂度是c * K * K * ( w * h) * ( w * h),这里是假设每个块在下一张图上时,可以移动任何位置。但是这样计算复杂度太高了,所以我们可以约束位移范围为d(上下左右移动d),就是每个块只和它附近D: 2d+1的位置块计算联系,而且以x1为中心的块去和它附近D范围计算联系时,还可以加上步长,就是不必和D范围的每个点都进行计算,可以跳着。
我们先假设没有步长,这样每次和D范围内一个点计算联系就得到一个 w * h * 1的 特征图,然后和D内的所有点即D * D个点,得到 w * h * D^2个特征图

深度学习 光流估计 光流技术_caffe_04

看图中有个441+32=473地方,论文实验就是这是位移最大值为d=10,所以D=21, 21*21=441,然后32个channel是1x1卷积后得到,这里的原因可能是用1x1减少了一下channel(256->32),这里还有个不明白的地是为什么只把第t帧的32个channel附到441后面,而t+1帧则没有。还有就是这里的sqrt是什么没有看到解释,是直接对得到的441个channel的数值开根号吗。

放大部分

深度学习 光流估计 光流技术_数据集_05

这里的放大和fcn十分类似,一边向后unconv,一边直接在小的特征图上预测,然后把结果双线性插值然后concat在unconv后的特征图上,然后接着往后传,重复四次后,得到的预测光流分辨率依然是输入的1/4,再重复之前的操作已没有太多提升,所以可以直接双线性插值得到和输入相同分辨率的光流预测图。
在最后的双线性插值放大上还有个可选方案就是variational approach参考:Large displacement optical flow: de-
scriptor matching in variational motion estimation

FlowNetS和FlowNetC的对比

深度学习 光流估计 光流技术_caffe_06


其中:EPE是一种对光流预测错误率的一种评估方式。

指所有像素点的gound truth和预测出来的光流之间差别距离(欧氏距离)的平均值,越低越好。

论文上说FlowNetS能和FlowNetC媲美,甚至有些数据集要好于FlowNetC,但是在实际数据集上FlowNetC应该更好,因为FlowNetC在flyingchair和sintel clean数据集的表现要好于FlowNetS,注意到sintel clean是没有运动blur和fog特效等的,和flyingchair数据集比较类似,这意味着FlowNetC网络能更好的学习训练数据集,更加过拟合over-fitting
所以如果使用更好的训练数据集,FlowNetC网络会更有优势。


参考和引用了以下博客,特别感谢!

【论文学习】神经光流网络——用卷积网络实现光流预测(FlowNet: Learning Optical Flow with Convolutional Networks)

光流Optical Flow介绍与OpenCV实现

hsv的可视图引用自: 图像处理中的全局优化技术(Global optimization techniques in image processing and computer vision) (三)