目标

在本章中,

  • 我们将了解光流的概念及其使用Lucas-Kanade方法的估计。
  • 我们将使用cv.calcOpticalFlowPyrLK()之类的函数来跟踪视频中的特征点。
  • 我们将使用cv.calcOpticalFlowFarneback()方法创建一个密集的光流场。

光流

光流是由物体或照相机的运动引起的两个连续帧之间图像物体的视运动的模式。它是2D向量场,其中每个向量都是位移向量,表示点从第一帧到第二帧的运动。考虑下面的图片(图片提供:Wikipedia关于Optical Flow的文章)。

它显示了一个球连续5帧运动。箭头显示其位移向量。光流在以下领域具有许多应用:

  • 运动的结构
  • 视频压缩
  • 视频稳定…

光流基于以下几个假设进行工作:

  1. 在连续的帧之间,对象的像素强度不变。
  2. 相邻像素具有相似的运动。

考虑第一帧中的像素I(x,y,t)I(x,y,t)I(x,y,t)(在此处添加新维度:时间。之前我们只处理图像,因此不需要时间)。它在dtdtdt时间之后拍摄的下一帧中按距离(dx,dy)(dx,dy)(dx,dy)移动。因此,由于这些像素相同且强度不变,因此可以说

I(x,y,t)=I(x+dx,y+dy,t+dt)
I(x,y,t) = I(x+dx, y+dy, t+dt)
I(x,y,t)=I(x+dx,y+dy,t+dt)

然后采用泰勒级数的右侧逼近,去掉常用项并除以dtdtdt得到下面的式子

fxu+fyv+ft=0  
f_x u + f_y v + f_t = 0 \;
fx​u+fy​v+ft​=0

其中

fx=∂f∂x  ;  fy=∂f∂y
f_x = \frac{\partial f}{\partial x} \; ; \; f_y = \frac{\partial f}{\partial y}
fx​=∂x∂f​;fy​=∂y∂f​

u=dxdt  ;  v=dydt
u = \frac{dx}{dt} \; ; \; v = \frac{dy}{dt}
u=dtdx​;v=dtdy​

上述方程式称为光流方程式。在其中,我们可以找到fxf_xfx​和fyf_yfy​,它们是图像渐变。同样,ftf_tft​是随时间变化的梯度。但是(u,v)(u,v)(u,v)是未知的。我们不能用两个未知变量来求解这个方程。因此,提供了几种解决此问题的方法,其中一种是Lucas-Kanade。

Lucas-Kanade 方法

之前我们已经看到一个假设,即所有相邻像素将具有相似的运动。Lucas-Kanade方法在该点周围需要3x3色块。因此,所有9个点都具有相同的运动。我们可以找到这9点的(fx,fy,ft)(fx,fy,ft)(fx,fy,ft)。所以现在我们的问题变成了求解带有两个未知变量的9个方程组的问题。用最小二乘拟合法可获得更好的解决方案。下面是最终的解决方案,它是两个方程式-两个未知变量问题,求解以获得解决答案。

[uv]=[∑ifxi2∑ifxifyi∑ifxifyi∑ifyi2]−1[−∑ifxifti−∑ifyifti]
\begin{bmatrix} u \\ v \end{bmatrix} = \begin{bmatrix} \sum_{i}{f_{x_i}}^2 & \sum_{i}{f_{x_i} f_{y_i} } \\ \sum_{i}{f_{x_i} f_{y_i}} & \sum_{i}{f_{y_i}}^2 \end{bmatrix}^{-1} \begin{bmatrix} - \sum_{i}{f_{x_i} f_{t_i}} \\ - \sum_{i}{f_{y_i} f_{t_i}} \end{bmatrix}
[uv​]=[∑i​fxi​​2∑i​fxi​​fyi​​​∑i​fxi​​fyi​​∑i​fyi​​2​]−1[−∑i​fxi​​fti​​−∑i​fyi​​fti​​​]

(用哈里斯拐角检测器检查逆矩阵的相似性。这表示拐角是更好的跟踪点。)因此,从用户的角度来看,这个想法很简单,我们给一些跟踪点,我们接收到这些光流矢量点。但是同样存在一些问题。到现在为止,我们只处理小动作,所以当大动作时它就失败了。为了解决这个问题,我们使用金字塔。当我们上金字塔时,较小的动作将被删除,较大的动作将变为较小的动作。因此,通过在此处应用Lucas-Kanade,我们可以获得与尺度一致的光流。

OpenCV中的Lucas-Kanade

OpenCV在单个函数cv.calcOpticalFlowPyrLK()中提供所有这些功能。在这里,我们创建一个简单的应用程序来跟踪视频中的某些点。为了确定点,我们使用cv.goodFeaturesToTrack()。我们采用第一帧,检测其中的一些Shi-Tomasi角点,然后使用Lucas-Kanade光流迭代地跟踪这些点。对于函数cv.calcOpticalFlowPyrLK(),我们传递前一帧,前一点和下一帧。它返回下一个点以及一些状态码,如果找到下一个点,状态码的值为1,否则为零。我们将这些下一个点迭代地传递为下一步中的上一个点。请参见下面的代码:

import numpy as np
import cv2 as cv
import argparse
parser = argparse.ArgumentParser(description='This sample demonstrates Lucas-Kanade Optical Flow calculation. \
The example file can be downloaded from: \
https://www.bogotobogo.com/python/OpenCV_Python/images/mean_shift_tracking/slow_traffic_small.mp4')
parser.add_argument('image', type=str, help='path to image file')
args = parser.parse_args()
cap = cv.VideoCapture(args.image)
# 用于ShiTomasi拐点检测的参数
feature_params = dict( maxCorners = 100,
qualityLevel = 0.3,
minDistance = 7,
blockSize = 7 )
# lucas kanade光流参数
lk_params = dict( winSize = (15,15),
maxLevel = 2,
criteria = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03))
# 创建一些随机的颜色
color = np.random.randint(0,255,(100,3))
# 拍摄第一帧并在其中找到拐角
ret, old_frame = cap.read()
old_gray = cv.cvtColor(old_frame, cv.COLOR_BGR2GRAY)
p0 = cv.goodFeaturesToTrack(old_gray, mask = None, **feature_params)
# 创建用于作图的掩码图像
mask = np.zeros_like(old_frame)
while(1):
ret,frame = cap.read()
frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
# 计算光流
p1, st, err = cv.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
# 选择良好点
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 = cv.line(mask, (a,b),(c,d), color[i].tolist(), 2)
frame = cv.circle(frame,(a,b),5,color[i].tolist(),-1)
img = cv.add(frame,mask)
cv.imshow('frame',img)
k = cv.waitKey(30) & 0xff
if k == 27:
break
# 现在更新之前的帧和点
old_gray = frame_gray.copy()
p0 = good_new.reshape(-1,1,2)

(此代码不会检查下一个关键点的正确性。因此,即使任何特征点在图像中消失了,光流也有可能找到下一个看起来可能与它接近的下一个点。因此,对于稳健的跟踪,实际上 应该以特定的时间间隔检测点。OpenCV样本附带了这样一个样本,该样本每5帧发现一次特征点,并且还对光流点进行了后向检查,以仅选择良好的流点。请参阅代码 samples/python/lk_track.py)。

查看我们得到的结果:

OpenCV中的密集光流

Lucas-Kanade方法计算稀疏特征集的光流(在我们的示例中为使用Shi-Tomasi算法检测到的角)。OpenCV提供了另一种算法来查找密集的光流。它计算帧中所有点的光通量。它基于Gunner Farneback的算法,在2003年Gunner Farneback的“基于多项式展开的两帧运动估计”中对此进行了解释。

下面的示例显示了如何使用上述算法找到密集的光流。我们得到一个带有光流矢量(u,v)(u,v)(u,v)的2通道阵列。我们找到了它们的大小和方向。我们对结果进行颜色编码,以实现更好的可视化。方向对应于图像的色相值。幅度对应于值平面。请参见下面的代码:

import numpy as np
import cv2 as cv
cap = cv.VideoCapture(cv.samples.findFile("vtest.avi"))
ret, frame1 = cap.read()
prvs = cv.cvtColor(frame1,cv.COLOR_BGR2GRAY)
hsv = np.zeros_like(frame1)
hsv[...,1] = 255
while(1):
ret, frame2 = cap.read()
next = cv.cvtColor(frame2,cv.COLOR_BGR2GRAY)
flow = cv.calcOpticalFlowFarneback(prvs,next, None, 0.5, 3, 15, 3, 5, 1.2, 0)
mag, ang = cv.cartToPolar(flow[...,0], flow[...,1])
hsv[...,0] = ang*180/np.pi/2
hsv[...,2] = cv.normalize(mag,None,0,255,cv.NORM_MINMAX)
bgr = cv.cvtColor(hsv,cv.COLOR_HSV2BGR)
cv.imshow('frame2',bgr)
k = cv.waitKey(30) & 0xff
if k == 27:
break
elif k == ord('s'):
cv.imwrite('opticalfb.png',frame2)
cv.imwrite('opticalhsv.png',bgr)
prvs = next

查看以下结果:

作者|OpenCV-Python Tutorials

编译|Vincent

来源|OpenCV-Python Tutorials

欢迎关注磐创博客资源汇总站:

http://docs.panchuang.net/

欢迎关注PyTorch官方中文教程站:

http://pytorch.panchuang.net/

OpenCV中文官方文档:

http://woshicver.com/

OpenCV-Python 光流 | 四十八的更多相关文章

  1. python第四十八课——类函数和对象函数

    5.类函数和对象函数 类函数:在定义函数的上面一行书写@classmethod,特点:没有self 有cls 对象函数:定义在class中的普通的def函数 演示类函数和对象函数的定义使用: 总结: ...

  2. 【OpenCV新手教程之十八】OpenCV仿射变换 & SURF特征点描写叙述合辑

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/33320997 作者:毛星云(浅墨)  ...

  3. NeHe OpenGL教程 第四十八课:轨迹球

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  4. SQL注入之Sqli-labs系列第四十七关,第四十八关,第四十九关(ORDER BY注入)

    0x1 源码区别点 将id变为字符型:$sql = "SELECT * FROM users ORDER BY '$id'"; 0x2实例测试 (1)and rand相结合的方式 ...

  5. 孤荷凌寒自学python第四十九天继续研究跨不同类型数据库的通用数据表操作函数

    孤荷凌寒自学python第四十九天继续研究跨不同类型数据库的通用数据表操作函数 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 今天继续建构自感觉用起来顺手些的自定义模块和类的代码. 不同类型 ...

  6. 孤荷凌寒自学python第四十六天开始建构自己用起来更顺手一点的Python模块与类尝试第一天

     孤荷凌寒自学python第四十六天开始建构自己用起来更顺手一点的Python模块与类,尝试第一天 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 按上一天的规划,这是根据过去我自学其它编程语 ...

  7. 孤荷凌寒自学python第四十五天Python初学基础基本结束的下阶段预安装准备

     孤荷凌寒自学python第四十五天Python初学基础基本结束的下阶段预安装准备 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 今天本来应当继续学习Python的数据库操作,但根据过去我自 ...

  8. 孤荷凌寒自学python第四十四天Python操作 数据库之准备工作

     孤荷凌寒自学python第四十四天Python操作数据库之准备工作 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 今天非常激动地开始接触Python的数据库操作的学习了,数据库是系统化设计 ...

  9. 孤荷凌寒自学python第四十天python 的线程锁RLock

     孤荷凌寒自学python第四十天python的线程锁RLock (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 因为研究同时在多线程中读写同一个文本文件引发冲突,所以使用Lock锁尝试同步, ...

随机推荐

  1. 使用C#开发pdf阅读器初探(基于WPF,没有使用开源库)

    前言 pdf是最流行的版式格式文件标准,已成为国际标准.pdf相关的开源软件非常多,也基本能满足日常需要了.相关商业软件更是林林总总,几乎应有尽有!似乎没必要自己再独立自主开发!但,本人基于以下考虑, ...

  2. USB小白学习之路(4)HID键盘程序

    HID键盘程序 1. 特别注意 需要特别注意,各个例程中的设备描述符,配置描述符等各种描述符都是已经配置好了的,我们需要做的只是在例程中将代码修改为自己需要的部分即可,一般情况下是不可以串搭配的. 2 ...

  3. MySQL之单表多表查询

    #1.单表查询 #单表查询语法 select <字段1,字段2....> from <表名> where <表达式> group by field 分组 havin ...

  4. centos7搭建ceph集群

    一.服务器规划 主机名 主机IP 磁盘配比 角色 node1 public-ip:10.0.0.130cluster-ip:192.168.2.130 sda,sdb,sdcsda是系统盘,另外两块数 ...

  5. 200行代码,7个对象——让你了解ASP.NET Core框架的本质[3.x版]

    2019年1月19日,微软技术(苏州)俱乐部成立,我受邀在成立大会上作了一个名为<ASP.NET Core框架揭秘>的分享.在此次分享中,我按照ASP.NET Core自身的运行原理和设计 ...

  6. 《Javascript中 == 和 === 的区别》

    在js中 ==(相等运算符) 和 === (严格运算符)是两种判断两个变量是否相等的运算符. == :判断是否相等,忽略类型进行值的比较.(存在隐式类型转换的比较) ===:判断是否相等,先判断值是否 ...

  7. 前端传json数组 ,后端的接收

    前端传输: var updateGoodsId=$(this).val();//get id var updateGoodsPrice=$("#IngoodsPrice"+upda ...

  8. 一起了解 .Net Foundation 项目 No.17

    .Net 基金会中包含有很多优秀的项目,今天就和笔者一起了解一下其中的一些优秀作品吧. 中文介绍 中文介绍内容翻译自英文介绍,主要采用意译.如与原文存在出入,请以原文为准. Peachpie Comp ...

  9. 20 本地SQL查询

    Spring Data JPA同样也支持sql语句的查询 //nativeQuery : 使用本地sql的方式查询 @Query(value="select * from customer& ...

  10. win下安装virtualenv和创建django项目

    一.由于一直在Linux环境下开发,想了解一下winPython开发环境: 1.打开cmd,pip install virtualenv 2.virtualenv test 由于这样需要进入到目录下才 ...