这篇文章是对Opencv 3.4.2中所有密集光流的算法进行总结。
部分算法在opencv-contrib中提供,所以需要事先安装好这个包。
光流简介
光流是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。一般而言,光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。
当人的眼睛观察运动物体时,物体的景象在人眼的视网膜上形成一系列连续变化的图像,这一系列连续变化的信息不断“流过”视网膜(即图像平面),好像一种光的“流”,故称之为光流(optical flow)。光流表达了图像的变化,由于它包含了目标运动的信息,因此可被观察者用来确定目标的运动情况。
光流场的表现形式
光流算法的输入:连续的两张 h * w * 3 的RGB图像,或 h * w 的灰度图像
光流算法的输出:一张h * w * 2的光流场,其中每个像素值为输入帧上该像素在x方向和y方向的位移,如下图所示。
OpenCV提供算法及部分算法效果
- farneback
prvs = cv2.cvtColor(prvs, cv2.COLOR_BGR2GRAY)
next = cv2.cvtColor(next, cv2.COLOR_BGR2GRAY)
flow = cv2.calcOpticalFlowFarneback(prev=prvs, next=next, flow=None, pyr_scale=0.5, levels=5,
winsize=15,
iterations=3, poly_n=3, poly_sigma=1.2,
flags=cv2.OPTFLOW_FARNEBACK_GAUSSIAN)
- deepflow (需安装opencv_contrib)
prvs = cv2.cvtColor(prvs, cv2.COLOR_BGR2GRAY)
next = cv2.cvtColor(next, cv2.COLOR_BGR2GRAY)
inst = cv2.optflow.createOptFlow_DeepFlow()
flow = inst.calc(prvs, next, None)
- simpleflow(需安装opencv_contrib)
flow = cv2.optflow.calcOpticalFlowSF(prvs, next, 2, 2, 4)
- sparse to dense flow(需安装opencv_contrib)
flow = cv2.optflow.calcOpticalFlowSparseToDense(prvs, next)
- pca flow(需安装opencv_contrib)
inst = cv2.optflow.createOptFlow_PCAFlow()
flow = inst.calc(prvs, next, None)
- disflow(需安装opencv_contrib)
prvs = cv2.cvtColor(prvs, cv2.COLOR_BGR2GRAY)
next = cv2.cvtColor(next, cv2.COLOR_BGR2GRAY)
inst = cv2.optflow.createOptFlow_DIS(cv2.optflow.DISOPTICAL_FLOW_PRESET_MEDIUM)
inst.setUseSpatialPropagation(True)
flow = inst.calc(prvs, next, None)
光流场的可视化
介绍可视化方法之前,我们需要对HSV色彩空间有一定了解。
HSV是一种将RGB色彩模型中的点在圆柱坐标系中的表示法,这种表示法试图做到比基于笛卡尔坐标系的几何结构RGB更加直观。
色相(H)是色彩的基本属性,就是平常所说的颜色名称,如红色、黄色等。 饱和度(S)是指色彩的纯度,越高色彩越纯,低则逐渐变灰,取0-100%的数值。 明度(V),亮度(L),取0-100%,如下图所示。
为了更直观地表示光流场,我们可以将h * w * 2的光流场转化成h * w * 3的HSV图像。H通道表示该像素点移动的方向,S或V通道表示该像素点移动的快慢。
代码如下:
def show_flow_hsv(flow, show_style=1):
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])#将直角坐标系光流场转成极坐标系
hsv = np.zeros((flow.shape[0], flow.shape[1], 3), np.uint8)
#光流可视化的颜色模式
if show_style == 1:
hsv[..., 0] = ang * 180 / np.pi / 2 #angle弧度转角度
hsv[..., 1] = 255
hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)#magnitude归到0~255之间
elif show_type == 2:
hsv[..., 0] = ang * 180 / np.pi / 2
hsv[..., 1] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
hsv[..., 2] = 255
#hsv转bgr
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
return bgr