Opencv之光流估计

光流估计

定义

光流是空间运动物体在观测成像平面上的像素运动的“瞬时速度”,根据各个像素点的速度矢量特征,可以对图像进行动态分析,例如目标跟踪。

特点

  • 亮度恒定:同一点随着时间的变化,其亮度不会发生改变。

  • 小运动:随着时间的变化不会引起位置的剧烈变化,只有小运动情况下才能用前后帧之间单位位置变化引起的灰度变化去近似灰度对位置的偏导数。

  • 空间一致:一个场景上邻近的点投影到图像上也是邻近点,且邻近点速度一致。因为光流法基本方程约束只有一个,而要求x,y方向的速度,有两个未知变量。所以需要连立n多个方程求解。

计算速度的方法

Lucas-Kanade 算法

在这里插入图片描述利用Sobel算法,可以很轻松地求出图像的梯度,即 I x I_{x} Ix I y I_{y} Iy。由于图像被逐帧读入,故 I t I_{t} It可以直接用两帧图片相减获得。故最终得到的式子中只有两个未知数,即x方向上和y方向上的速度u和v。此时我们需要两个点才能求解,而在此算法中,我们取图像中的一个窗口,假设窗口大小为 5 × 5 5\times 5 5×5,则共有25个像素点,如下图中的 A 25 × 2 A_{25\times 2} A25×2

在这里插入图片描述但对于 A T A A^{T}A ATA来说,在绝大多数情况下是不可逆的,只有在对角化后得到的特征值 λ 1 \lambda_{1} λ1 λ 2 \lambda_{2} λ2足够大的情况下才是可逆的,而要想发生这种情况,我们让取的点是角点即可。(相关原理请参考:Opencv之Harris角点检测

代码实现

1、引入需要的库

import numpy as np
import cv2

2、导入视频

cap = cv2.VideoCapture('test.avi')

3、定义Lucas-Kanade算法所需要的参数

lk_params = dict( winSize  = (15,15),
                  maxLevel = 2)

4、定义随机颜色条

color = np.random.randint(0,255,(100,3))

5、拿到第一帧图像并作灰度处理

ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)

6、角点检测

函数说明:
p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, maxCorners, qualityLevel, minDistance)

输入参数:

  • old_gray:灰度图像
  • mask:掩码
  • maxCorners:角点最大数量
  • qualityLevel:品质因子,特征值越大的越好,用来筛选,品质因子越大,得到的角点越少
  • minDistance:最小距离,相当于在这个距离中有其他角点比这个角点更适合,就舍弃这个弱的角点

返回值:

  • 所有检测到的角点
feature_params = dict( maxCorners = 100,
                       qualityLevel = 0.3,
                       minDistance = 7)
p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params)

7、完成光流估计

  • 逐帧读取图片
  • 使用Lucas-Kanade算法得到跟踪特征点向量
  • 绘制轨迹
  • 更新Lucas-Kanade算法输入的图像

函数说明:
cv2.calcOpticalFlowPyrLK():

输入参数:

  • prevImage 前一帧图像

  • nextImage 当前帧图像

  • prevPts 待跟踪的特征点向量

  • winSize 搜索窗口的大小

  • maxLevel 最大的金字塔层数

返回值:

  • nextPts 输出跟踪特征点向量

  • status 特征点是否找到,找到的状态为1,未找到的状态为0

  • error 错误点,一般用不到

# 创建一个mask
mask = np.zeros_like(old_frame)
while(True):
    ret,frame = cap.read()
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # 需要传入前一帧和当前图像以及前一帧检测到的角点
    p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)

    # st=1表示
    good_new = p1[st==1]
    good_old = p0[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)
        frame = cv2.circle(frame,(a,b),5,color[i].tolist(),-1)
    img = cv2.add(frame,mask)

    cv2.imshow('frame',img)
    k = cv2.waitKey(150) & 0xff
    if k == 27:
        break

    # 更新
    old_gray = frame_gray.copy()
    p0 = good_new.reshape(-1,1,2)

cv2.destroyAllWindows()
cap.release()
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cofisher

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值