光流法

光流场

所谓光流场就是很多光流的集合。

当计算出一幅图片中每个像素的光流,就能形成光流场。

构建光流场就是试图重现现实世界中的运动场,用以运动分析。

光流法基本原理

1.基本假设条件

(1)亮度恒定不变,同一目标在不同帧间运动时,其亮度不会发生改变。

(2)时间连续或运动是"小运动",时间的变化不会引起目标位置的距离变化,相邻帧之间对象的位移是很小的

2.基本约束方程

考虑一个像素I(x,y,t)在第一帧的光强度(t为所在时间维度),到下帧它移动了(dx,dy)的距离,用了dt时间。因是同一像素点,且假设该像素在运动前后的光强度是不变的,即:

将(1)式右端进行泰勒展开,得:

再将(2)代入(1)同除dt,可得:

设u,v分别是光流沿X轴与Y轴的速度矢量,得:

分别表示图像中像素点的灰度沿X、Y、T方向的偏导数.

综上所述,式(3)简化为:

           

其中,Ix,Iy,It均可由图像数据求得,而(u,v)即为所求光流矢量。

约束方程只有一个,方程未知量有两个,此时无法求得u和v的确切值。

================================================================================================

3.稠密光流与稀疏光流

(1)稠密光流

       稠密光流是一种针对图像或指定的一片区域进行逐点匹配的图像配准方法,它计算图像上所有的点的偏移量,从而形成一个稠密的光流场。通过这个稠密的光流场,可以进行像素级别的图像配准。

       Horn-Schunck算法以及基于区域匹配的大多数光流法都属于稠密光流的范畴。

       由于光流矢量稠密,所以其配准后的效果明显优于稀疏光流配准的效果。但其副作用也比较明显,因要计算每个像素的偏移量,其计算量也明显较大,时效性较差。

OpenCV Code:

import cv2
import numpy as np
cap = cv2.VideoCapture("../video/VID_20190710_165704.mp4")
ret, frame1 = cap.read()
prvs = cv2.cvtColor(frame1,cv2.COLOR_BGR2GRAY)
hsv = np.zeros_like(frame1)
hsv[...,1] = 255
c = 1
timeF = 1
while True:
    ret, frame2 = cap.read()
    next = cv2.cvtColor(frame2,cv2.COLOR_BGR2GRAY)
    flow = cv2.calcOpticalFlowFarneback(prvs,next, None, 0.5, 3, 15, 3, 5, 1.2, 0)
    mag, ang = cv2.cartToPolar(flow[...,0], flow[...,1])
    hsv[..., 0] = ang * 180 / np.pi / 2
    hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
    rgb = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
    cv2.imshow('frame2', rgb)
    # if c % timeF == 0:
    #     cv2.imshow('frame2', rgb)
    # c = c+1
    k = cv2.waitKey(30) & 0xff
    if k == 27:
        break
    elif k == ord('s'):
         cv2.imwrite('opticalfb.png', frame2)
         cv2.imwrite('opticalhsv.png', rgb)
    prvs = next
cap.release()
cv2.destroyAllWindows()

结果图:

(2)稀疏光流

       稀疏光流并不对图像的每个像素点进行逐点计算,它通常需要指定一组点进行跟踪,这组点最好具有某种明显的特性,例如Harris角点等,跟踪才会相对稳定和可靠。稀疏跟踪的计算开销比稠密跟踪小得多。

基于特征的匹配方法是典型的属于稀疏光流的算法。

================================================================================================

4. Lucas-Kanade光流法

       假设,除了光流法基本的两个假设外,还有如下额外的一个假设

(3)邻域内光流一致,一个场景中的同一表面的局部邻域内具有相似的运动,在图像平面上的投影也在邻近区域,且邻近点速度一致(认为邻域内所有像素点的运动是一致的)。这是Lucas-Kanade光流法特有的假定。

Code:

import cv2
import numpy as np


# cap = cv2.VideoCapture('../video/VID_20190710_165704.mp4')
cap = cv2.VideoCapture('../video/driver_recorder.mp4')
ret, fm_1 = cap.read()
fm_1 = cv2.GaussianBlur(fm_1,(3,3),0)
fm_1_gray = cv2.cvtColor(fm_1,cv2.COLOR_BGR2GRAY)

corners_0 = cv2.goodFeaturesToTrack(fm_1_gray,20,0.1,5)

# 创建一些随机Color
color = np.random.randint(0,255,(100,3))

# 创建一个mask掩码图画图
mask = np.zeros_like(fm_1)

lk_params = dict(winSize=(15,15),
                 maxLevel=2,
                 criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 100, 0.01))
while True:
    ret, fm = cap.read()
    fm = cv2.GaussianBlur(fm, (3, 3), 0)
    fm_gray = cv2.cvtColor(fm,cv2.COLOR_BGR2GRAY)

    # 计算光流
    p1,st, err = cv2.calcOpticalFlowPyrLK(fm_1_gray, fm_gray, corners_0, None, **lk_params)
    # 选择好的point角点
    good_new = p1[st == 1]
    good_old = corners_0[st == 1]

    # 画出轨迹
    for i, (new,old) in enumerate(zip(good_new,good_old)):
        a,b = new.ravel()
        c,d = old.ravel()
        mask = cv2.line(mask,(a,b),(c,d),color[i].tolist(),2)
        fm = cv2.circle(fm,(a,b),5,color[i].tolist(),-1)
    img = cv2.add(fm,mask)
    cv2.imshow('fm',img)
    k = cv2.waitKey(0)
    if k == 27:
        break
    # 更新上一帧和point
    fm_1 = fm_gray.copy()
    corners_0 = good_new.reshape(-1,1,2)

cv2.destroyAllWindows()
cap.release()

结果图:

5.基于金字塔分层的LK光流法

      上述提到,LK光流法第2条是假定运动是小运动,当运动快速时如何做呢?

      考虑两帧之间物体的运动位移较大(运动快速)时,算法会出现较大误差。就希望减少图像中物体的运动位移。可通过缩小图像的尺寸实现。假设当图像为400*400时,物体位移为【16 16】,当图像缩小为200*200时,位移变为【8 8】,缩小为100*100时,位移减少到【4 4】。在原图像缩放了很多以后,LK光流法又变得适用了。

      Bouguet提出使用金字塔分层的方式,将原图像逐层分解。简单说,下层金字塔中的一个像素可以代表上层(低分辨率)的两个像素。如此利用金字塔结构,自上而下修正运动量。

      具体做法:

         一、首先,对每一帧建立一个高斯金字塔,最低分辨率图像在最顶层,原始图片在底层。

        二、如何计算光流呢?从顶层(Lm层)开始,通过最小化每个点的邻域范围内的匹配误差和,得到顶层图像中每个点的光流。

    假设图像的尺寸每次缩放为原来的一半,共缩放了Lm层,第0层为原图像。设已知原图的位移为d,则每层的位移为:

                 

         三、顶层的光流计算结果(位移情况)反馈到第Lm-1层,作为该层初始时的光流值的估计g。

                

         四、这样沿着金字塔向下反馈,重复估计动作,直到到达金字塔的底层(即原图像)。

                   

          (准确值=估计值+残差),这个"残差",是本算法的关键。

=========================================================================

处理目的:

     得到从第一帧到第二帧图像中每个点运动的光流情况。即,对于前一帧的图像上一点(x0,y0),I(x0,y0),要在后一帧图像上找到一点(x0+dx,y0+dy)与之相匹配,即灰度值I(x0,y0)与I(x0+dx,y0+dy)最接近。那么向量d=[dx,dy]就是图像在点(x0,y0)处的运动位移,也就是像素点(x0,y0)的光流。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值