光流估计

要是觉得内容枯燥,您可以点击左下角的播放按钮,让您在音乐的熏陶下愉快的阅读

本文总字数:2385

光流估计

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

三个前提条件:

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

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

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

Lucas—Kanade算法

  如何求解方程组呢?看起来一个像素点根本不够,在物体移动过程中还有哪些特性呢?

  注意前提条件里的第三个空间一致还没有使用

  例如对于一个n*n的像素范围点1和点2邻近和点3邻近...由空间一致得

 最终可以表示为

但ATA 不一定可逆。由于可逆矩阵的特征值非0。

若ATA可逆,则λ1,λ2非0,联想到角点检测λ1,λ2都不靠近0时,即λ1,λ2都很大时,为角点

所以,可以利用判断是否是角点来判断是否可逆

当是角点是,成立。

 

步骤:

- 1.读入视频

- 2. 对视频的每一帧操作,转换为灰度图

- 3.检测角点

- 4 .创建掩膜

- 5.利用cv2.calcOpticalFlowPyrLK跟踪特征向量

  参数:
  - prevImage 前一帧图像

  - nextImage 当前帧图像

  - prevPts 待跟踪的特征点向量

  - winSize 搜索窗口的大小

  - maxLevel 最大的金字塔层数

  返回:

  - nextPts 输出跟踪特征点向量

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

- 6.对于找到的特征点绘制轨迹

- 7.展示

- 8.更新旧特征点

 

复制代码
cap = cv2.VideoCapture('test.avi')

#角点检测所需参数
feature_params = dict(maxCorners=100, qualityLevel=0.3, minDistance=7)

#lucas kanade参数
lk_params = dict(winSize=(15, 15), maxLevel=2)

#随机颜色条
color = np.random.randint(0, 255, (100, 3))

#拿到第一帧图像
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
#退回所有检测特征点,需要输入图像,角点最大数量(效率),品质因子(特征值越大的越好,来筛选)
#距离相当于这个区间有比这个角点强的,就不要这个弱的了

p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)

#创建一个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)
    #绘制轨迹
    for i, (new, old) in enumerate(zip(good_new, good_old)):
        a = new.ravel()
        b = old.ravel()
        mask = cv2.line(mask, tuple(a), tuple(b), color[i].tolist(), 2)
        frame = cv2.circle(frame, tuple(a), 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)

cap.release()
cv2.destroyAllWindows()
复制代码

 

 

 

posted @   MMMMinoz  阅读(401)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示