1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
# 计算前后帧之间的光流
flow = cv2.calcOpticalFlowFarneback(pre_frame_grey, next_frame_grey)
# 笛卡尔坐标系下x, y方向上的位移[u, v]被转化成极坐标下的幅值和角度[mag, ang]
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
# 归一化为HSV域上的UINT8范围 (H范围为0-179度)
hsv[..., 0] = ang*180/np.pi/2
hsv[..., 1] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
hsv[..., 2] = 255 # (255则背景纯白, 0则背景纯黑)
# 转化为BGR域便于显示
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
cv2.imshow('optical-flow', bgr)
介绍完传统算法, 下面根据两篇具体的文章看看深度学习算法是怎么实现光流预测的.
暴力CNN: 输入是连续的两帧RGB图concatenate在一起, 一共是6层channel; 输出是光流图, 猜测是2层通道. 其实就是U-Net的Encoder-Decoder + Skip connection结构. 思路很直接, 做法比较硬核.
人工correlation CNN: 像前面那样暴力丢数据让网络去硬学输入和输出之间的联系, 可能没有学习到问题的本质. 所以在这里加了人工干预, 让连续两帧之间产生刻意的联系. 具体的来说, 两帧分别做两路输入, 然后在某一层级的feature上, 采用”人工卷积”让两路合并成一路, 剩下的结构与”暴力CNN”相同. “人工卷积”的操作如下, 即在两路feature上做空间卷积(图中黄色箭头部分).
在第一帧的像素点上, 使用第二帧对应位置邻域上的feature值做相互的卷积操作, 以这种方式学习得到像素点在前后两帧间的差异. 这是一种无网络参数的操作, 不占显存.
真实场景下, 是无法标定光流的, 所以只能采用人造数据集的方式. 先给定设计好的运动, 这样光流其实就是已知的, 然后依据假设好的光流给定图片中物体的运动轨迹, 作为训练数据.
上图中, 椅子其实是单独的贴图, 给定第一张图中椅子的仿射变换矩阵, 就能计算出第二张图中椅子的位置, 同时光流也能直接给出.
模型结果及评价
自然场景下表现
以深度学习的方式, 达到了差不多接近于传统算法的效果. 虽然得分上略低, 但是文中argue说Note that even though the EPE of FlowNets is usually worse than that of EpicFlow, the networks often better preserve fine details. 文章的成功之处在于, 一是实现了端到端的CNN算法预测光流, 虽然得分不及传统算法, 但是也是开辟了一条新路径; 二是使用自制的数据集, 训练出来的模型在自然场景下也能适用, 这具有很强的现实意义. 给我们带来的启示是, 在训练模型时, 没有数据该怎么办? 数据没法标怎么办? 此文是”人工逆向造数据的成功典范”.
论文链接: FlowNet: Learning Optical Flow with Convolutional Networks
文中提到All state-of-the-art optical flow approaches rely on iterative methods. Can deep networks also benefit from iterative refinement?, 借鉴了传统算法的迭代做法, 将多个子网络叠加在一起. 同时, 文中还提到: We conducted this experiment and found that applying a network with the same weights multiple times and also fine-tuning this recurrent part does not improve results (see supplemental material for details)., 也就是说, 简单地堆叠相同的网络其实并没有带来好处. 依据Boosting的思想, 基学习器之间还是存在差异比较好, 如果基学习器之间没有明显差距的话, 就跟把同一个网络来回循环一样了, 是得不到好的结果的.
因此, 文中做了几组实验, 分别把FlowNetSimple(用s/S代表, 小写代表channel数更少)和FlowNetCorr(用c/C代表)反复堆叠数层. 最后发现确实是越深越好, 但同时计算时间也会越久.
在细节上, Boosting的残差体现在, 下一个子网络的输入是上一个网络预测的光流矫正后的图片(图中的Image2 + Warped), 即利用当前预测的光流对图片进行一次平移, 这时候frame2和frame1可能还没有完全对齐, 于是紧接着送入下一轮预测剩余的光流(残差).
$\hat I_i(x, y)=I_{i-1}(x+u_i, y+v_i)$
这里主要是learning rate schedule和训练集的加载方式. 总的来说, 训练迭代次数长的fine tune方式带来的精度最高. 训练集方面, Chairs是自制的”漂浮椅子贴图”数据集, 表现形式比较简单, 主要是平面运动; 而Things3D是进阶3D版的”漂移椅子贴图”, 运动形式比较复杂, 存在三维变换和光线明暗变化. 最终, 先在简单Chairs上训练, 再到复杂Things3D上微调效果最好. 文中给的解释是, We conjecture that the simpler Chairs dataset helps the network learn the general concept of color matching without developing possibly confusing priors for 3D motion and realistic lighting too early, 即不能一上来就让网络学习太难的数据集, 要像教小学生一样循序渐进, 难度逐渐增加, 才能学习到问题的本质.
模型在自制数据集和真实场景下都有很好的结果, 边缘和细节比较清晰, 同时速度还比传统算法快, 实现了SOTA.
整篇文章读下来, 感觉就是在FlowNet 1.0的基础上”调参”, 实打实地作为一个算法工程师在调参. 调网络结构、channel数, 调数据, 调学习率, 各种fine tune. 总结一下, 该文是”如何科学调参的正确示范”.
论文链接: FlowNet 2.0: Evolution of Optical Flow Estimation with Deep Networks
参考资料:
OpenCV关于Optical-flow的例子:
https://docs.opencv.org/3.4.5/d7/d8b/tutorial_py_lucas_kanade.html
FlowNet 2.0站点:
https://lmb.informatik.uni-freiburg.de/Publications/2017/IMSKDB17/
1 传统算法 – Lucas-Kanade - 1.1 OpenCV实验
- 1.2 光流的可视化
2 FlowNet: Learning Optical Flow with Convolutional Networks (ICCV 2015) - 2.1 网络结构
- 2.2 训练数据
- 2.3 模型结果及评价
3 FlowNet 2.0: Evolution of Optical Flow Estimation with Deep Networks (CVPR 2017) - 3.1 网络结构
- 3.2 训练策略
- 3.3 针对小位移的子网络
- 3.4 模型效果及思考
- 3.4.1 参考资料:
|