文章目录
- 概要
- 什么是光流?
- 稀疏光流与密集光流
- 实现稀疏光流
-
- 1. 设置环境
- 2.配置OpenCV读取视频并设置参数
- 3. Grayscaling 3. 灰度化
- 4. Shi-Tomasi 角点检测器 – 选择要跟踪的像素
- 5. Lucas-Kanade:稀疏光流
- 6. 可视化
- 实现密集光流
-
- 1. 设置环境
- 2. 配置 OpenCV 读取视频
- 3. 灰度
- 4. Farneback光流
- 5.可视化
- 使用深度学习的光流
-
- 光流应用:语义分割
- 光流应用:[物体检测和跟踪](https://openaccess.thecvf.com/content_cvpr_2018_workshops/papers/w3/Hua_Vehicle_Tracking_and_CVPR_2018_paper.pdf)
- 结论
- 参考
概要
计算机视觉研究的进步通过利用诸如用于识别属于特定类别的对象的对象检测和用于像素级分类的语义分割等技术,彻底改变了机器感知环境的方式。然而,当涉及实时视频处理时,这些技术的大多数实现仅考虑同一帧(x,y)内对象的空间关系,而忽略时间方面(t)。这意味着每个帧都是独立评估的,与之前或未来的帧没有任何关联。但是,如果我们需要连续帧之间的关系怎么办?例如,如果我们想要跟踪车辆跨帧的运动以估计其当前速度并预测其在下一帧中的位置该怎么办?
交通的稀疏光流(每个箭头都指向相应像素的预测流的方向)。
或者,如果我们需要连续帧之间的人体姿势关系信息来识别射箭、棒球和篮球等人类动作,该怎么办?
各种行动分类
使用光流对动作进行分类
在本教程中,我们将了解光流是什么,如何实现它的两个主要变体(稀疏和密集),并全面了解涉及深度学习的最新方法和有前途的未来方向。
什么是光流?
让我们从对光流的高层次理解开始。光流是对象在序列的连续帧之间的运动,由对象和相机之间的相对运动引起。光流问题可以表示为:
光流问题
在连续帧之间,我们可以将图像强度 (I) 表示为空间 (x,y) 和时间 (t) 的函数。换句话说,如果我们获取第一张图像 I(x,y,t) 并在 t 时间内将其像素移动 (dx,dy),我们将获得新图像 I(x+dx,y+dy,t+dt) )。
首先,我们假设物体的像素强度在连续帧之间是恒定的。
光流的恒定强度假设
其次,我们采用RHS的泰勒级数近似,并去除常用项。
泰勒级数:像素强度的近似值
第三,我们除以dt来推导出光流方程:
光流方程,其中 u=dx/dt 和 v=dy/dt
dI/dx、dI/dy 和 dI/dt 是沿横轴、纵轴和时间的图像梯度。因此,我们总结了光流问题,即求解 u(dx/dt) 和 v(dy/dt) 以确定随时间的运动。您可能会注意到,我们无法直接求解 u 和 v 的光流方程,因为两个未知变量只有一个方程。我们将实施一些方法,例如 Lucas-Kanade 方法来解决这个问题。
稀疏光流与密集光流
稀疏光流给出了帧内一些“有趣的特征”(例如描绘物体边缘或角落的几个像素)的流动向量,而密集光流,它给出了整个帧(所有像素)的流动向量——每个像素最多一个流动向量。正如您已经猜到的那样,密集光流具有更高的精度,但代价是速度慢/计算成本高。
左:稀疏光流 – 跟踪几个“特征”像素;右图:密集光流 – 估计图像中所有像素的流量。
实现稀疏光流
稀疏光流选择一组稀疏的像素特征(例如,有趣的特征,如边缘和角落)来跟踪其速度矢量(运动)。提取的特征在光流函数中从一帧传递到另一帧,以确保跟踪相同的点。稀疏光流有多种实现方式,包括 Lucas-Kanade 方法、Horn-Schunck 方法、Buxton-Buxton 方法等。我们将使用 Lucas-Kanade 方法与 OpenCV(一个开源的计算机视觉算法库)进行实现。
1. 设置环境
如果您尚未安装 OpenCV,请打开终端并运行:
pip install opencv-python
现在,克隆教程软件仓库:
git clone https://github.com/chuanenlin/optical-flow.git
接下来,使用文本编辑器打开 sparse-starter.py。我们将在这个 Python 文件中编写所有代码。
2.配置OpenCV读取视频并设置参数
import cv2 as cv
import numpy as np
# Parameters for Shi-Tomasi corner detection
feature_params = dict(maxCorners = 300, qualityLevel = 0.2, minDistance = 2, blockSize = 7)
# Parameters for Lucas-Kanade optical flow
lk_params = dict(winSize = (15,15), maxLevel = 2, criteria = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03))
# The video feed is read in as a VideoCapture object
cap = cv.VideoCapture("shibuya.mp4")
# Variable for color to draw optical flow track
color = (0, 255, 0)
# ret = a boolean return value from getting the frame, first_frame = the first frame in the entire video sequence
ret, first_frame = cap.read()
while(cap.isOpened()):
# ret = a boolean return value from getting the frame, frame = the current frame being projected in the video
ret, frame = cap.read()
# Frames are read by intervals of 10 milliseconds. The programs breaks out of the while loop when the user presses the 'q' key
if cv.waitKey(10) & 0xFF == ord('q'):
break
# The following frees up resources and closes all windows
cap.release()
cv.destroyAllWindows()
3. Grayscaling 3. 灰度化
import cv2 as cv
import numpy as np
# Parameters for Shi-Tomasi corner detection
# feature_params = dict(maxCorners = 300, qualityLevel = 0.2, minDistance = 2, blockSize = 7)
# Parameters for Lucas-Kanade optical flow
# lk_params = dict(winSize = (15,15), maxLevel = 2, criteria = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03))
# The video feed is read in as a VideoCapture object
# cap = cv.VideoCapture("shibuya.mp4")
# Variable for color to draw optical flow track
# color = (0, 255, 0)
# ret = a boolean return value from getting the frame, first_frame = the first frame in the entire video sequence
# ret, first_frame = cap.read()
# Converts frame to grayscale because we only need the luminance channel for detecting edges - less computationally expensive