OpenCV-Python(40):光流算法

news2024/10/6 16:18:37

目标

  • 光流的概念以及Lucas-Kanade 光流法
  • 使用函数cv2.calcOpticalFlowPyrLK() 对图像中的特征点进行跟踪

光流

        介绍

        由于目标对象或者摄像机的移动造成的图像对象在连续两帧图像中的移动被称为光流。它是一个2D 向量场,可以用来显示一个点从第一帧图像到第二帧图像之间的移动。如下图所示:

        上图显示了一个点在连续的五帧图像间的移动。箭头表示光流场向量。光流算法是一种用于估计图像序列中像素运动的计算机视觉技术。它基于一个简单的假设:1. 在连续的两帧图像之间(目标对象)的像素的灰度值不改变。2. 相邻的像素具有相同的运动.根据这个假设,光流算法通过计算相邻帧之间的像素差异来确定像素的运动方向和速度。第一帧图像中的像素I (x,y,t) 在时间 dt 后移动到第二帧图像的(x+dx,y+dy)处。根据第一条假设:灰度值不变。所以我们可以得到:

对等号右侧进行泰勒级数展开,消去相同项,两边都除以dt,得到如下方程:

        上面的等式叫做光流方程。其中fx 和fy 是图像梯度,同样ft 是时间方向的梯度。但(u,v)是不知道的。我们不能在一个等式中求解两个未知数。有几个方法可以帮我们解决这个问题,其中的一个是Lucas-Kanade 法 。

原理及应用

        光流算法的基本原理是,对于两个连续的图像帧,我们可以将第一个图像的每个像素点在第二个图像中进行寻找。通过在第二个图像中找到与第一个图像中每个像素最相似的像素,我们可以得到一个像素点的位移向量。这个位移向量表示了该像素在两个图像帧之间的运动。在实际应用中,光流算法通常使用稀疏特征点来估计像素运动。首先,在第一个图像帧中检测到一组特征点,如角点或边缘点。然后,使用光流算法来追踪这些特征点在第二个图像帧中的位置。最常用的光流算法之一是Lucas-Kanade算法,它使用金字塔图像结构来提高计算的效率。

        光流算法在计算机视觉中有广泛的应用。它可以用于运动分析(运动重建结构)、目标跟踪、视频及图像稳定、视频压缩等任务。例如,在运动分析中,光流算法可以帮助我们理解相机运动、物体运动和场景的深度信息。在目标跟踪中,光流算法可以用于估计目标的运动轨迹,并预测目标的未来位置。在图像稳定中,光流算法可以用于校正由于相机抖动引起的图像模糊。

Lucas-Kanade算法

        现在我们使用第二条假设,邻域内的所有点都有相似的运动。Lucas-Kanade 法就是利用一个3x3 邻域中的9 个点具有相同运动的这一点。这样我们就可以找到 9 个点的光流方程,用它们组成一个具有两个未知数9 个等式的方程组,这是一个约束条件过多的方程组。一个好的解决方法就是使用最小二乘拟合。下面就是求解结果:

        有没有发现上面的逆矩阵与Harris 角点检测器非常相似,这说明角点很适合用来做跟踪。
        从使用者的角度来看,想法很简单,我们取跟踪一些点,然后我们就会获得这些点的光流向量。但是还有一些问题。直到现在我们处理的都是很小的运动。如果有大的运动怎么办呢?图像金字塔。我们可以使用图像金字塔的顶层,此时小的运动被移除,大的运动转换成了小的运动,现在再使用Lucas-Kanade算法,我们就会得到尺度空间上的光流。 

OpenCV中的Lucas-Kanade光流

        上面所有过程都被OpenCV 打包成了一个函数:cv2.calcOpticalFlowPyrLK()。现在我们使用这个函数创建一个小程序来跟踪视频中的一些点。要跟踪哪些些点呢?我们使用函数cv2.goodFeatureToTrack() 来确定要跟踪的点。我们首先在视频的第一帧图像中检测一些Shi-Tomasi 角点,然后我们使用Lucas-Kanade 算法迭代跟踪这些角点。我们要给函数cv2.calcOpticlaFlowPyrLK()传入前一帧图像和其中的点,以及下一帧图像。函数将返回带有状态数的点,如果状态数是1,说明在下一帧图像中找到了这个点(上一帧中角点)如果状态数是0,就说明没有在下一帧图像中找到这个点。我们再把这些点作为参数传给函数,如此跌代下去实现跟踪。代码如下:

import numpy as np
import cv2

cap = cv2.VideoCapture('slow.flv')
# params for ShiTomasi corner detection
feature_params = dict(  maxCorners = 100,
                        qualityLevel = 0.3,
                        minDistance = 7,
                        blockSize = 7 )
# Parameters for lucas kanade optical flow
#maxLevel 为使用的图像􄮀字塔层数
lk_params = dict( winSize = (15,15),
                  maxLevel = 2,
              criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))

# Create some random colors
color = np.random.randint(0,255,(100,3))

# Take first frame and find corners in it
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params)

# Create a mask image for drawing purposes
mask = np.zeros_like(old_frame)
while(1):
    ret,frame = cap.read()
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # calculate optical flow 能够获取点的新位置
    p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None,**lk_params)
    # Select good points
    good_new = p1[st==1]
    good_old = p0[st==1]
    # draw the tracks
    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(30) & 0xff
    if k == 27:
        break
    # Now update the previous frame and previous points
    old_gray = frame_gray.copy()
    p0 = good_new.reshape(-1,1,2)
cv2.destroyAllWindows()
cap.release()

(上面的代码没有对返回角点的正确性进行检查。图像中的一些特征点甚至在丢失以后,光流还会找到一个预期相似的点。所以为了实现稳定的跟踪,我们应该每个一定间隔就进行一次角点检测。OpenCV 的官方示例中带有这样一个例子,它是每5 帧进行一个特征点检测。它队对光流点使用反向检测来获取好的点进行跟踪,示例为/samples/python2/lk_track.py)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1386087.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用 raise_exception 装饰器,简化 if not ... raise ... 抛出异常的过程

目录 一、前置说明1、总体目录2、相关回顾3、本节目标 二、操作步骤1、项目目录2、代码实现3、测试代码4、日志输出 三、后置说明1、要点小结2、下节准备 一、前置说明 1、总体目录 《 pyparamvalidate 参数校验器,从编码到发布全过程》 2、相关回顾 python 装饰…

多角度展文明风采!成都市第二届公益短视频大赛落幕

近日,“金芙蓉文明让生活更美好”成都市第二届公益短视频大赛揭晓获奖名单,170余部作品脱颖而出。此次大赛共收到700余部参赛作品,以不同手法、从不同角度描绘文明成都。 用短视频弘扬社会主义核心价值观 以真实故事为原型引发更多人共鸣 …

Android-常用数据结构和控件

HashMap 的原理 HashMap 的内部可以看做数组链表的复合结构。数组被分为一个个的桶(bucket)。哈希值决定了键值对在数组中的寻址。具有相同哈希值的键值对会组成链表。需要注意的是当链表长度超过阈值(默认是8)的时候会触发树化,链表会变成树形结构。 把握HashMap的…

线性代数基础【4】线性方程组

第四章 线性方程组 一、线性方程组的基本概念与表达形式 二、线性方程组解的基本定理 定理1 设A为mXn矩阵,则 (1)齐次线性方程组AX0 只有零解的充分必要条件是r(A)n; (2)齐次线性方程组AX0 有非零解(或有无数个解)的充分必要条件是r(A)<n 推论1 设A为n阶矩阵,则…

干货速递|用需求在环仿真扩展基于模型的系统工程实践:起落架系统案例

摘要 仿真已经成为大多数行业大规模采用基于模型的系统工程(MBSE)和基于模型的设计(MBD)工具的至关重要的因素。与此同时,实用的需求工程工具在以文档需求规格为主的生命周期管理之外并未得到显著发展,这使…

【CSS】首个字符占用多行,并自定义样式

效果 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>首字母大写</title><style&…

消息的发送与接收

消息的发送与接收 消息的发送与接收不仅仅是在于聊天功能的实现。其实还有很多种情况也算"消息的发送与接收"。而且我们还可以通过多种方法去实现。我们可以基于实际情况来选择。 WebSocket实现 node做后端。找了好多&#xff0c;前端页面总是用到了jQuery&#x…

AMC8历年详细考点分类,都熟悉了考高分不成问题(2024年也适用)

还有四天&#xff0c;2024年AMC8美国数学思维活动&#xff08;竞赛&#xff09;就要正式开始了&#xff0c;这两天有多位家长咨询六分成长&#xff0c;想了解AMC8的主要考点&#xff0c;或者说经常考的内容。 根据2000-2023年这23年的真题分析&#xff0c;AMC8试题的考点可以分…

Java开发+Intellij-idea+Maven+工程构建

Java开发Intellij-ideaMaven工程构建 Intellij-idea是一款流行的Java集成开发环境&#xff0c;它支持Maven作为项目管理和构建工具。Maven可以帮助开发者自动下载项目依赖的jar包&#xff0c;执行编译、测试、打包等生命周期任务。本资源将介绍如何在Intellij-idea中创建、导入…

MATLAB二维与三维绘图实验

本文MATLAB源码&#xff0c;下载后直接打开运行即可[点击跳转下载]-附实验报告https://download.csdn.net/download/Coin_Collecter/88740747 一、实验目的 掌握图形对象属性的基本操作。掌握利用图形对象进行绘图操作的方法。 二、实验内容 利用图形对象绘制曲线&#xff…

亚信安慧AntDB超融合框架——数智化时代数据库管理的新里程碑

在信息科技飞速发展的时代&#xff0c;亚信科技AntDB团队提出了一项颠覆性的“超融合”理念&#xff0c;旨在满足企业日益增长的复杂混合负载和多样化数据类型的业务需求。这一创新性框架的核心思想在于融合多引擎和多能力&#xff0c;充分发挥分布式数据库引擎的架构优势&…

钉钉逐浪AI Agent

文&#xff5c;郝 鑫 编&#xff5c;刘雨琦 “大公司代表落后生产力&#xff0c;是慢半拍的”&#xff0c;“小创新靠大厂&#xff0c;大创新仍然要靠小厂”&#xff0c;这是以李彦宏和王小川为代表的创业老炮&#xff0c;在2023年总结出来的创新规律&#xff0c;从移动互…

图形化编程:以Scratch引领少儿编程思维启蒙之旅

在21世纪科技飞速发展的今天&#xff0c;编程教育已经成为培养未来人才的重要途径。而“少儿编程”这一概念的提出&#xff0c;正是为了让孩子们从小接触并理解计算机逻辑&#xff0c;锻炼他们的创新思维与问题解决能力。其中&#xff0c;图形化编程以其直观易懂、趣味性强的特…

手把手教你VS code文件如何在顶部自动生成作者,修改日期等信息

1、安装插件KoroFileHeader 2、左下角选择管理---设置---输入"fileheader"---点击"在setting.json中编辑" 输入"fileheader"-点击"在setting.json中编辑" fileheader 必须的基础配置: 头部注释模板与函数注释模板 复制&#xff1a;…

C++(1) —— 基础语法入门

目录 一、C初识 1.1 第一个C程序 1.2 注释 1.3 变量 1.4 常量 1.5 关键字 1.6 标识符命名规则 二、数据类型 2.1 整型 2.2 sizeof 关键字 2.3 实型&#xff08;浮点型&#xff09; 2.4 字符型 2.5 转义字符 2.6 字符串型 2.7 布尔类型 bool 2.8 数据的输入 三…

【C++】static_cast和dynamic_cast使用详解

目录 一、static_cast二、dynamic_cast三、总结如果这篇文章对你有所帮助&#xff0c;渴望获得你的一个点赞&#xff01; 一、static_cast static_cast 是 C 中的一种类型转换操作符&#xff0c;用于执行编译时的类型转换。它主要用于在不损失 const 限定的前提下进行各种合法…

【WSL】Win10 使用 WSL2 进行 Linux GPU 开发

1. GPU 驱动 先安装 驱动 参考 https://docs.nvidia.com/cuda/wsl-user-guide/index.html 使用 https://www.nvidia.com/Download/index.aspx 提供的兼容 GeForce 或 NVIDIA RTX/Quadro 显卡在系统上安装 NVIDIA GeForce Game Ready 或 NVIDIA RTX Quadro Windows 11 显示驱动…

Eclipse的安装与使用

Eclipse的安装与使用 “工欲善其事&#xff0c;必先利其器”&#xff0c;高效的开发工具&#xff0c;不但能带来高体验的开发环境&#xff0c;还能带来高效的纠错与开发提示等功能&#xff0c;下面介绍一种Java常用的开发工具——Eclipse。 1.1 Eclipse的安装与启动 Eclipse的…

MK-米客方德TF卡和SD卡的区别

TF卡和SD卡的区别 TF卡也叫MicroSD卡&#xff0c;以MK-米客方德的TF卡和SD卡为例&#xff0c;TF卡和SD卡的区别如下&#xff1a; 1、物理尺寸&#xff1a; TF卡&#xff1a;TF卡是一种较小尺寸的存储卡&#xff0c;也被称为MicroSD卡。其尺寸为15mm 11mm 1mm。 SD卡&#x…

k8s--动态pvc和pv

目录 前情回顾 动态pv 实验模拟 步骤一&#xff1a;在stor01节点上安装nfs&#xff0c;并配置nfs服务 接下来在matser01上配置 步骤二&#xff1a;创建 Service Account&#xff0c;用来管理 NFS Provisioner 在 k8s 集群中运行的权限和动态规则 步骤三&#xff1a;使用 Deploy…