本文将详细说明光流法是如何进行多帧融合的,或者说两张图片对齐的。
首先两张图片,前提是灰度相同,或者说亮度相同。
如图所示,假设俩小人除了位置发生变化,其他肢体动作等都完全相同。
小人在左边的图定义为L图,在右边定义为R图。
我们使用稠密光流去解决问题,稠密光流:
calcOpticalFlowFarneback
- prev:前一帧图像
- next: 后一帧图像
- flow: 输出的光流矩阵。矩阵大小同输入的图像一样大,但是矩阵中的每一个元素可不是一个值,而是两个值,分别表示这个点在x方向与y方向的运动量(偏移量)。
- pyr_scale: 金字塔上下两层之间的尺度关系
- levels: 金字塔层数
- winsize: 均值窗口大小,越大越能denoise并且能够检测快速移动目标,但会引起模糊运动区域
- iterations: 迭代次数
- poly_n: 像素领域大小,一般为5,7等
- poly_sigma: 高斯标注差,一般为1-1.5
- flags: 计算方法 * 使用cv2.OPTFLOW_FARNEBACK_GAUSSIAN 参数可以更准确的找到光流,但是更耗时。
稠密光流算法:Farneback算法
简单来说可以理解为,求每一个像素的搜索范围内的距离最小值。
用我们的例子来说光流如图:
最直观的小人所发生的位移向量可以被光流所找到,具体来说比如头上的某个点A(10,10),到了B的位置(100,10)。那么在(10,10)位置上的光流向量就应该为(90,0)。
接下来在remap操作的时候,首先要知道ramap的输入是R图和光流向量。也就是说R图上原本就不存在小人在左边的信息,R图的左边是空的背景,这时候就要映射了,还是拿A,B两点举例,对于没有发生位移的地方,直接去R图原始位置上的值即可,直到到了A点,这时的光流向量不为0了,A点的光流向量为(90,0)那么这时,remap出新图的(10,10)位置的像素点会取R图中(10+90,10+0)位置的像素点,这也就等于把小人从右侧移回到了左侧。同理所有的像素点都这样替换,在小人本身完全不发生任何肢体等变化时,理论上是可以完全把右侧的小人移动回左侧的,可是实际中很难做到这样的效果,所以我的理解,这也就是为什么光流有一个前提是”小位移“
。
文字如果说不清,那么请看第二种情况:
还是俩小人,只不过这次,小人不仅往右边移动了,而且还举起了右手。(小人只是在x轴上平移,暂时没有发生y轴上的变化,图画的不标准。)
*左侧小人依旧是L图,右侧为R图。
这种情况看上去难度更大了,但是由于是像素点的数学计算,理论上讲仍然是可以找到位移的。
继续说回刚才,如下图,我们找到了A的位移光流,假设在近乎完美的情况整个小人都被1:1的移回到了左边。那么问题出现了,右侧的小人位置上的像素点该取什么?在光流假设前提下,背景没有发生变化,理论上取L图的像素替代效果最佳(这里暂时不考虑亮度变化),可是remap函数的输入只有一张R图和一个光流向量,并没有L图的任何信息。
所以我们回到开始的求光流环节,我们的参考图是L图,在L图的A点,可以找到在R图(当前帧)所对应的B点,从而求出一个位移向量由A到B,那么在L图的B点呢?L图上的B点,也会在R图上像素找到一个最小距离,而L图上的B点位置是背景,所以从理论上讲L图上B点位置在R图上找到的距离最小值应该是和L图上B点(背景)相似的区域,可是R图上的B点位置不是背景,而是小人,这里就可以说明了光流是不可能做到1:1的还原的(个人理解,欢迎交流),所以L图上B点位置会在R图上B点位置附近找到一个最相似的点作为距离最小值。但是通过实验测试发现这个找所谓的相似距离最小值点效果并不好,通过很极端的调参最后的结果如图:
参考图:
alt图:
光流图:
remap后结果:
位移太大。
光流的三个假设前提其中有一条叫:小运动。
那么我们再次实验,换成小运动的情况:实验结果如下:
参考图:
alt图:
光流图:
光流remap后的图:
光流remap(通过调参最小化扭曲的结果):
这个结果,在一定程度上确实有还原成参考图的趋势(当然参数可能不是最优),其次不可避免的还是产生了扭曲,但是对比大运动来说,效果有一定的提升,当然也可以通过不断调参去最大程度的减少图像的扭曲。
还有一种情况通过调节参数可以最小化图像扭曲,但是作为代价,原始的alt位置也会被保留,类似于长运动,正常光流扭曲的效果应该是倒数第二张图所示。
关于光流+remap暂时想到的就这样,欢迎讨论交流。