目标

在本章中,

  • 我们将了解光流的概念及其使用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. Nginx 配置GeoIP2 禁止访问,并允许添加白名单过滤访问设置

    配置环境:Centos 7.6 + Tengine 2.3.2 GeoIP2 下载地址:https://dev.maxmind.com/geoip/geoip2/geolite2/ 1. Nginx  ...

  2. Ueditor富文本编辑器--Ctrl V 粘贴后原有图片显示错误

    最近负责将公司官网从静态网站改版成动态网站,方便公司推广营销人员修改增加文案,避免官网文案维护过于依赖技术人员.在做后台管理系统时用到了富文本编辑器Ueditor,因为公司有一个阿里云文件资源服务器, ...

  3. nginx 命令行参数 启动 重启 重载 停止

    今天和大家分享关于 nginx 的一些参数使用 首先,你应该安装了nginx CentOS 安装 nginx 这是很早之前的一篇博客,可以参考. 之前,我们如何去操作 nginx ##简单粗暴法 pk ...

  4. ES6/JavaScript一些‘巧用’

    前言 第一次发表文章,如有不好的地方请见谅/ 在编写JavaScript代码的时候存在的一些方法和技巧,虽然有时候条条大路都通向罗马,但是也许总会有那么一条最短的路径可走.本文将一些都知道却不怎么用的 ...

  5. 前端每日实战:119# 视频演示如何用纯 CSS 创作一个接扎啤的动画(内含2个视频)

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/rZeOQp 可交互视频 此视频是可 ...

  6. jsvascript篮球梦

    首先让我们先欣赏一下效果图: html文本: <div class="box"> <img id="imgshow" src="la ...

  7. frp 内网穿透访问内网Web服务

    ps:最近想要通过域名(公网)访问或者测试在本地搭建的 web 服务(不想在公网IP服务器上再部署个服务,也不想通过teamview等工具远程卡到爆!), 由于本地机器没有公网 IP,无法将域名解析到 ...

  8. JavaScript的函数(一)

    ,1,在javascript中,函数即对象.函数里面的参数可以是个函数,例如: data.sort(function(a,b){return a-b;}) 函数的返回值,return语句导致函数停止执 ...

  9. celery异步任务 定时任务

    以前项目中用到过 celery ,但是没怎么记笔记,现在在记一下,方便以后用.   Celery.png 问:Celery 是什么? 答:Celery 是一个由 Python 编写的简单.灵活.可靠的 ...

  10. Python面向对象之:三大特性:继承,封装,多态以及类的约束

    前言: python面向对象的三大特性:继承,封装,多态. 1. 封装: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情 ...