目标

在本章中,

  • 我们将了解光流的概念及其使用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. ubuntu 18.04门等字不正常

    sudo vim /etc/fonts/conf.d/64-language-selector-prefer.conf 该文件配置了 Noto Sans CJK 的优先级.i进入编辑后,可以看到,JP ...

  2. Day 3 DP

    1. P1015 精卫填海 01背包 + 判断 #include <iostream> using namespace std; , MAXV = ; int v, n, m, f[MAX ...

  3. 不要忽视Managed code stripping的副作用

    0x00 前言 Unity 2018.3之后,新的“Managed Stripping Level”选项将替换 player settings 中原有的“Stripping Level”选项. 这个新 ...

  4. DSO 运行 —— dso_ros + Android 手机摄像头

    转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12425855.html 本文要点: dso 配置安装 dso 离线 ...

  5. 面试题57-II.和为s的连续正数序列

    面试题57-II.和为s的连续正数序列 1.题目 LeetCode-面试题57-II.和为s的连续正数序列 输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数 ...

  6. CentOS7.5源码编译安装mysql5.7.29

    #查看系统版本 [root@ctos3 ~]# cat /etc/redhat-release CentOS Linux release (Core) #下载源码包,需要注意的是mysql5.7 编译 ...

  7. [面试专题]前端需要知道的web安全知识

    前端需要知道的web安全知识 标签(空格分隔): 未分类 安全 [Doc] Crypto (加密) [Doc] TLS/SSL [Doc] HTTPS [Point] XSS [Point] CSRF ...

  8. Chrome 63 - What"s New in DevTools(中文字幕)

    大家好,这是代码之声(codefm)第一期,今天给大家带来的是 What's New In DevTools (Chrome 63). Chrome 一般会每隔 6 周发布一次主版本.​目前 Chro ...

  9. 组件(4):使用slot进行内容分发

    组件的作用域(一) 父组件模板的内容在父组件作用域内编译:子组件模板的内容在子组件作用域内编译. 父子组件的编译相互独立,编译时只能使用各自作用域中的属性和方法,例如,你不可以在父组件模板内,将一个指 ...

  10. LeetCode 278.First Bad Version(E)(P)

    题目: You are a product manager and currently leading a team to develop a new product. Unfortunately, ...