OpenCV – Gunnar-Farneback 光流
在本文中,我们将了解 Gunnar FarneBack 技术的 Dense Optical Flow,它发表在 Gunnar Farneback 于 2003 年发表的名为“基于多项式展开的双帧运动估计”的研究论文中。
先决条件: OpenCV
光流:
光流被称为物体的视运动模式,即,它是在序列的每两个连续帧之间的物体的运动,它是由被捕获的物体或捕获它的相机的运动引起的。考虑一个强度为I (x, y, t)的物体,在时间dt之后,它移动到dx和dy ,现在,新的强度将是I (x+dx, y+dy, t+dt) 。
我们假设两帧之间的像素强度是恒定的,即
I (x, y, t) = I (x+dx, y+dy, t+dt)
泰勒近似是在 RHS 一侧进行的,结果是,
除以δt ,我们得到光流方程,即
其中, u = dx/dt和v = dy/dt 。
此外, dI/dx是沿水平轴的图像梯度, dI/dy是沿垂直轴的图像梯度,dI/dt 是沿时间的。
因为,我们只有一个方程可以找到两个未知数,所以我们使用不同的方法来求解,
- 稀疏光流(Lucas Kanade 方法)
- 密集光流(Gunnar Farneback 方法)
Gunnar Farneback 光流
在密集光流中,我们查看所有的点(不像 Lucas Kanade,它只对 Shi-Tomasi 算法检测到的角点起作用)并检测两帧之间的像素强度变化,从而在转换后生成具有高亮像素的图像转换为 hsv 格式以便清晰可见。
它根据流向量的数组计算光流的大小和方向,即(dx/dt, dy/dt) 。后来它通过色调可视化流动的角度(方向),通过 HSV 颜色表示的值可视化流动的距离(大小)。为了获得最佳可见性,HSV 的强度设置为 255。OpenCV 提供了一个函数cv2.calcOpticalFlowFarneback来查看成密集的光流。
句法:
cv2.calcOpticalFlowFarneback(prev, next, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, flags[, flow])
参数:
- prev :第一张 8 位单通道格式的输入图像。
- next :与prev相同类型和相同大小的第二个输入图像。
- pyr_scale :参数指定为每个图像构建金字塔的图像比例(比例 < 1)。经典金字塔一般为 0.5 级,每增加一层,前一层减半。
- levels : levels=1表示,没有额外的层(只有初始图像)。它是包括第一张图像的金字塔层数。
- winsize :它是平均窗口大小,大小越大,算法对噪声的鲁棒性越强,并提供快速运动检测,但会产生模糊的运动场。
- 迭代次数:在每个金字塔级别执行的迭代次数。
- poly_n :通常为 5 或 7,它是像素邻域的大小,用于查找像素之间的多项式展开。
- poly_sigma :作为多项式展开的基础,导数平滑的高斯标准差。对于poly= 5 ,它可以是 1.1,对于poly = 7,它可以是 1.5。
- flow :计算出的流图像,其大小与prev相似,类型为 CV_32FC2。
- 标志:它可以是 -
OPTFLOW_USE_INITIAL_FLOW 使用输入流作为初始近似值。
OPTFLOW_FARNEBACK_GAUSSIAN 使用高斯winsize*winsize过滤器。
代码:
Python3
# Importing libraries
import cv2
import numpy as np
# Capturing the video file 0 for videocam else you can provide the url
capture = cv2.VideoCapture("video_file.avi")
# Reading the first frame
_, frame1 = capture.read()
# Convert to gray scale
prvs = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
# Create mask
hsv_mask = np.zeros_like(frame1)
# Make image saturation to a maximum value
hsv_mask[..., 1] = 255
# Till you scan the video
while(1):
# Capture another frame and convert to gray scale
_, frame2 = capture.read()
next = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
# Optical flow is now calculated
flow = cv2.calcOpticalFlowFarneback(prvs, next, None, 0.5, 3, 15, 3, 5, 1.2, 0)
# Compute magnite and angle of 2D vector
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
# Set image hue value according to the angle of optical flow
hsv_mask[..., 0] = ang * 180 / np.pi / 2
# Set value as per the normalized magnitude of optical flow
hsv_mask[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
# Convert to rgb
rgb_representation = cv2.cvtColor(hsv_mask, cv2.COLOR_HSV2BGR)
cv2.imshow('frame2', rgb_representation)
kk = cv2.waitKey(20) & 0xff
# Press 'e' to exit the video
if kk == ord('e'):
break
# Press 's' to save the video
elif kk == ord('s'):
cv2.imwrite('Optical_image.png', frame2)
cv2.imwrite('HSV_converted_image.png', rgb_representation)
prvs = next
capture.release()
cv2.destroyAllWindows()
输入
输出:
- https://docs.opencv.org/2.4/modules/video/doc/motion_analysis_and_object_tracking.html