【python】OpenCV—Optical Flow

在这里插入图片描述

文章目录

  • 1、光流
  • 2、Opencv 中光流的实现
  • 3、稀疏光流
  • 4、密集光流
    • 4.1、farneback
    • 4.2、lucaskanade_dense
    • 4.3、rlof
  • 5、涉及到的库
    • 5.1、cv2.goodFeaturesToTrack
    • 5.2、cv2.calcOpticalFlowPyrLK
    • 5.3、cv2.optflow.calcOpticalFlowSparseToDense
    • 5.4、cv2.calcOpticalFlowFarneback
    • 5.5、cv2.optflow.calcOpticalFlowDenseRLOF
  • 参考

1、光流

光流(Optical Flow)是计算机视觉和图像处理中的一个重要概念,它描述了连续帧图像中像素点随时间的运动轨迹和速度的二维矢量场。以下是关于光流的详细解释:

一、光流的概念

  • 定义:光流是指空间运动物体在观察成像平面上的像素运动瞬时速度。它利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息。
  • 起源:光流的概念最早由Gibson在1950年提出,用于描述视觉场景中物体的运动信息。

稀疏光流:仅计算图像中选定特征点(如角点、边缘点等)的光流。

密集光流:计算图像中每个像素点的光流,从而得到整个图像的光流场。

二、光流的基本假设

光流算法通常基于以下几个基本假设:

  • 亮度恒定:即同一物体在不同帧间运动时,其亮度不会发生改变。这是光流法的基本假定,用于推导光流法的基本方程。
  • 时间连续或“小运动”:即时间的变化不会引起目标位置的剧烈变化,相邻帧之间位移要比较小。这保证了在短时间内,像素的运动可以被认为是连续的。
  • 空间一致性:一个场景中同一表面上邻近的点具有相近的运动,在图像平面上的投影也在邻近区域。这一假设有助于在局部区域内对像素运动进行建模。

三、光流的应用场景

光流法因其实时性和计算简单的特点,在计算机视觉和机器人视觉中有许多应用场景:

  • 视频稳定:通过光流法分析视频帧中像素的运动,可以稳定视频画面,减少运动模糊和震动对视觉感知的影响。
  • 目标跟踪:通过分析连续帧图像中物体的运动情况,光流法可以追踪目标的位置和速度,实现对目标的跟踪和监控。
  • 动作识别:在人体动作识别中,光流法可以提取人体在连续帧图像中的运动信息,用于动作分析和识别。
  • 三维重建:通过分析连续帧图像中物体的运动情况,光流法可以恢复出物体的三维结构和形状,实现物体的三维重建和建模。
  • 智能驾驶:在智能驾驶系统中,光流法可以用于车辆感知和环境感知,提取道路和物体的运动特征,帮助车辆做出决策。
  • 视觉导航:在机器人的视觉导航中,光流法可以分析连续帧图像中地面和障碍物的运动情况,实现机器人对环境的感知和定位。

四、光流的计算方法

光流的计算方法多种多样,主要包括以下几种:

  • 基于梯度(微分)的方法:通过计算图像序列中像素的灰度梯度来估计光流。
  • 基于匹配的方法:包括基于特征和基于区域的方法,通过匹配相邻帧中的特征或区域来计算光流。
  • 基于能量(频率)的方法:首先对输入图像序列进行时空滤波处理,然后利用滤波结果来计算光流。
  • 基于相位的方法:利用带通滤波器输出的相位特性来确定光流的速度和方向。
  • 神经动力学方法:利用神经网络等机器学习方法来模拟生物视觉系统的功能,实现光流的计算。

五、总结

光流作为计算机视觉和图像处理中的一个重要工具,具有广泛的应用前景。通过分析连续帧图像中像素的运动信息,光流法可以实现对物体运动和环境变化的感知和分析,为智能控制和决策提供支持。随着计算机视觉技术的不断发展,光流法的计算精度和效率将不断提高,其应用场景也将更加广泛。

2、Opencv 中光流的实现

OpenCV提供了一些算法实现来解决稀疏光流任务

1)Pyramid Lucas-Kanade

2)Sparse RLOF

仅使用稀疏特征集意味着我们将不会有不包含在其中的像素的运动信息。使用密集光流算法可以消除这一限制,该算法假定为图像中的每个像素计算一个运动向量。

OpenCV中已经实现了一些密集光流算法:

1)Dense Pyramid Lucas-Kanade

2)Farneback

3)PCAFlow

4)SimpleFlow

5)RLOF

6)DeepFlow

7)DualTVL1

3、稀疏光流

Lucas-Kanade 方法

它假设在一个小的窗口内,所有的像素点都有相似的运动

# lucas_kanade.py
import cv2
import numpy as npdef lucas_kanade_method(video_path):cap = cv2.VideoCapture(video_path)# ShiTomasi角点检测的参数feature_params = dict(maxCorners=100, qualityLevel=0.3, minDistance=7, blockSize=7)# lucas kanade光流算法的参数lk_params = dict(winSize=(15, 15),maxLevel=2,criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03),)# 创建一些随机的颜色color = np.random.randint(0, 255, (100, 3))# 取第一帧并在其中找到角点ret, old_frame = cap.read()old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)# 返回检测到的角点坐标p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)# 创建用于绘图的掩模图像mask = np.zeros_like(old_frame)index = 0while True:index += 1ret, frame = cap.read()if not ret:breakframe_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# 计算光流# calcOpticalFlowPyrLK(prevImg, nextImg, prevPts, nextPts[, status[, err[, \\# winSize[, maxLevel[, criteria[, flags[, minEigThreshold]]]]]]]) -> nextPts, status, errp1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)# 返回成功跟踪的特征点的位置# 哪些点成功跟踪(True)或失败(False)# 每个点的错误度量(通常是跟踪的质量或置信度)# 选择比较好的点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 = cv2.line(mask, (int(a), int(b)), (int(c), int(d)), color[i].tolist(), 2)frame = cv2.circle(frame, (int(a), int(b)), 5, color[i].tolist(), -1)img = cv2.add(frame, mask)cv2.imshow("frame", img)cv2.imwrite(f"duck_{str(index)}.jpg", img)k = cv2.waitKey(25) & 0xFFif k == 27:breakif k == ord("c"):mask = np.zeros_like(old_frame)# 现在更新之前的帧和之前的点old_gray = frame_gray.copy()p0 = good_new.reshape(-1, 1, 2)if __name__ == "__main__":video_path = "duck.mp4"lucas_kanade_method(video_path)# python lucas_kanade.py

原理是检测前帧的角点,然后计算光流,绘制

结果展示,分割成多个片段,前后片段是连续的

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

可以观测到还是有些异常值的(比较直的线段)

4、密集光流

# dense_optical_flow.py
import cv2
import numpy as np
import argparsedef dense_optical_flow(method, video_path, params=[], to_gray=False):# 读取视频cap = cv2.VideoCapture(video_path)# 读取第一帧ret, old_frame = cap.read()# 创建HSV并使Value为常量hsv = np.zeros_like(old_frame)hsv[..., 1] = 255# 精确方法的预处理if to_gray:old_frame = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)index = 0while True:index += 1# 读取下一帧ret, new_frame = cap.read()frame_copy = new_frameif not ret:break# 精确方法的预处理if to_gray:new_frame = cv2.cvtColor(new_frame, cv2.COLOR_BGR2GRAY)# 计算光流flow = method(old_frame, new_frame, None, *params)# 编码:将算法的输出转换为极坐标mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])# 使用色相和饱和度来编码光流hsv[..., 0] = ang * 180 / np.pi / 2hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)# 转换HSV图像为BGRbgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)cv2.imshow("frame", frame_copy)cv2.imshow("optical flow", bgr)cv2.imwrite(f"duck_{str(index)}.jpg", bgr)k = cv2.waitKey(25) & 0xFFif k == 27:breakold_frame = new_framedef main():parser = argparse.ArgumentParser()parser.add_argument("--algorithm",choices=["farneback", "lucaskanade_dense", "rlof"],required=True,help="Optical flow algorithm to use",)parser.add_argument("--video_path", default="duck.mp4", help="Path to the video",)args = parser.parse_args()video_path = args.video_pathif args.algorithm == "lucaskanade_dense":method = cv2.optflow.calcOpticalFlowSparseToDensedense_optical_flow(method, video_path, to_gray=True)elif args.algorithm == "farneback":# OpenCV Farneback算法需要一个单通道的输入图像,因此我们将BRG图像转换为灰度。method = cv2.calcOpticalFlowFarnebackparams = [0.5, 3, 15, 3, 5, 1.2, 0]  # Farneback的算法参数dense_optical_flow(method, video_path, params, to_gray=True)elif args.algorithm == "rlof":# 与Farneback算法相比,RLOF算法需要3通道图像,所以这里没有预处理。method = cv2.optflow.calcOpticalFlowDenseRLOFdense_optical_flow(method, video_path)if __name__ == "__main__":main()
# python dense_optical_flow.py

4.1、farneback

输出结果

请添加图片描述

请添加图片描述

请添加图片描述

请添加图片描述

请添加图片描述

效果还行,显示出来的部分仅为手拿着物体在移动

4.2、lucaskanade_dense

输出结果

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

这个感觉更稠密

4.3、rlof

输出结果

在这里插入图片描述

在这里插入图片描述

这个光流不太稳定的样子,噪点比较大

5、涉及到的库

5.1、cv2.goodFeaturesToTrack

cv2.goodFeaturesToTrack 用于检测图像中的角点,这些角点通常用于后续的图像跟踪或特征匹配任务

函数原型

corners = cv2.goodFeaturesToTrack(image, maxCorners, qualityLevel, minDistance, [, corners[, mask[, blockSize[, useHarrisDetector[, k]]]]])

参数说明

  • image:输入图像,应为8位或32位浮点型,单通道图像(灰度图)。
  • maxCorners:返回角点的最大数量。如果实际检测到的角点数超过此值,则只返回最强的前maxCorners个角点。如果设置为0,则返回所有检测到的角点。
  • qualityLevel:角点的最小可接受质量水平,是角点检测算法中用于筛选角点的阈值参数。
  • minDistance:检测到的角点之间的最小欧氏距离。在此距离内的多个角点将被视为同一角点并只保留一个。
  • corners(可选):输出参数,用于存储检测到的角点坐标。如果提供了此参数,则检测到的角点将存储在此数组中。
  • mask(可选):一个与输入图像同样大小的8位单通道图像,用于指定感兴趣区域(ROI)。非零(通常是255)像素位置表示该位置是角点检测的候选区域。
  • blockSize(可选):计算角点时使用的邻域大小,默认为3。该值越大,检测到的角点越稳定,但计算量也越大。
  • useHarrisDetector(可选):一个布尔值,指定是否使用Harris角点检测器。如果为True,则使用Harris角点检测;如果为False(默认值),则使用Shi-Tomasi角点检测。
  • k(可选):Harris角点检测器中的自由参数,仅当useHarrisDetector为True时有效。

返回值

  • corners:如果函数调用时未提供corners参数,则该函数将返回检测到的角点坐标,格式为numpy.ndarray,每个角点由(x, y)坐标表示。

使用示例

import cv2  
import numpy as np  # 读取图像  
image = cv2.imread('path_to_image.jpg', 0)  # 0 表示以灰度模式读取图像  # 设置角点检测参数  
maxCorners = 100  
qualityLevel = 0.3  
minDistance = 7  # 检测角点  
corners = cv2.goodFeaturesToTrack(image, maxCorners, qualityLevel, minDistance)  # 如果检测到了角点,则绘制并显示它们  
if corners is not None:  for i in corners:  x, y = i.ravel()  cv2.circle(image, (x, y), 3, 255, -1)  cv2.imshow('Corners', image)  cv2.waitKey(0)  cv2.destroyAllWindows()

注意事项

  • 输入图像应为灰度图,因为角点检测通常在灰度空间中进行。
  • qualityLevel 和 minDistance 参数对检测到的角点数量和分布有显著影响,需要根据具体应用场景进行调整。
  • 使用 mask 参数可以指定只在图像的特定区域中检测角点,有助于减少计算量和提高检测精度。
  • blockSize 参数和 useHarrisDetector 参数提供了检测算法的灵活性,可以根据需要选择合适的设置。

5.2、cv2.calcOpticalFlowPyrLK

cv2.calcOpticalFlowPyrLK 是 OpenCV 库中用于计算两幅图像之间稀疏光流(Sparse Optical Flow)的一个函数,特别是通过 Lucas-Kanade 方法结合金字塔(PyrLK)来跟踪图像中的特征点。

函数原型

p1, st, err = cv2.calcOpticalFlowPyrLK(prevImg, nextImg, prevPts, nextPts[, status[, err[, winSize[, maxLevel[, criteria[, flags[, minEigThreshold]]]]]]])

参数说明

  • prevImg:前一帧的图像(8位单通道图像)。
  • nextImg:当前帧的图像(与前一帧同样大小和类型)。
  • prevPts:前一帧图像中的特征点(关键点)数组,数据类型为 numpy 数组,形状为 (N, 1, 2),其中 N 是特征点的数量。
  • nextPts:输出参数,表示在当前帧图像中计算出的特征点位置,与 prevPts 大小相同。如果传递 None,则函数会创建一个新的数组来存储结果。
  • status(可选):输出参数,表示每个特征点的跟踪状态。如果某个特征点被成功跟踪,其对应的 status 值为 1,否则为 0。如果传递 None,则函数会创建一个新的数组来存储状态。
  • err(可选):输出参数,表示每个特征点的错误向量(误差)。在某些情况下,这个参数可能被忽略。如果传递 None,则函数会创建一个新的数组来存储错误向量。
  • winSize(可选):搜索窗口的大小,默认值为 (21, 21)。
  • maxLevel(可选):金字塔的最大层数,0 表示不使用图像金字塔。默认值为 3。
  • criteria(可选):迭代搜索算法的终止条件。通常为 cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT,并设置最大迭代次数和 epsilon 值。
  • flags(可选):操作标志,默认为 0。可以使用的标志包括 cv2.OPTFLOW_USE_INITIAL_FLOW,表示使用初始估计的点位置。
  • minEigThreshold(可选):测量是否被视为良好特征点的最小特征值。默认值为 1e-4。

返回值

  • p1:二维点数组,表示在 nextImg 图像中成功跟踪的特征点的位置。
  • st:与 prevPts 大小相同的布尔数组,表示哪些点成功跟踪(True)或失败(False)。
  • err:与 prevPts 大小相同的数组,表示每个点的错误度量(通常是跟踪的质量或置信度)。

工作原理

  • cv2.calcOpticalFlowPyrLK 函数通过 Lucas-Kanade 方法结合金字塔(PyrLK)来跟踪特征点。它首先将输入的两帧图像构建成金字塔,然后从金字塔的顶层开始逐层向下计算光流。这种金字塔方法可以提高计算效率并提供更好的光流估计结果。

使用示例

import cv2  
import numpy as np  # 读取前一帧和当前帧图像  
prevImg = cv2.imread('frame1.png', cv2.IMREAD_GRAYSCALE)  
nextImg = cv2.imread('frame2.png', cv2.IMREAD_GRAYSCALE)  # 使用 Shi-Tomasi 角点检测器找到前一帧图像中的关键点  
prevPts = cv2.goodFeaturesToTrack(prevImg, maxCorners=100, qualityLevel=0.3, minDistance=7, blockSize=7)  # 设置 LK 光流算法的参数  
lk_params = dict(winSize=(15, 15), maxLevel=2,  criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))  # 计算光流  
nextPts, st, err = cv2.calcOpticalFlowPyrLK(prevImg, nextImg, prevPts, None, **lk_params)  # 筛选出被成功跟踪的点  
good_new = nextPts[st == 1]  
good_old = prevPts[st == 1]  # 绘制跟踪结果(省略具体绘制代码)

注意事项

  • 输入图像应为灰度图,因为光流计算通常在灰度空间中进行。
  • prevPts 中的特征点应使用适当的特征检测算法(如 Shi-Tomasi 角点检测器)获得。

5.3、cv2.optflow.calcOpticalFlowSparseToDense

在OpenCV中,cv2.optflow.calcOpticalFlowSparseToDense 是一个用于计算从稀疏特征点到密集光流场的函数。这个函数结合了稀疏特征匹配和光流算法的优点,通过先找到一组稀疏的关键点(如使用Shi-Tomasi角点检测器),然后利用这些稀疏点来估计整个图像的光流场。

函数原型

flow = cv2.optflow.calcOpticalFlowSparseToDense(prevImg, nextImg, prevPts, nextPts, density=1, sigma_dist=0.05, sigma_color=0.1, patchSize=21, maxLevel=2)

参数说明

  • prevImg: 上一帧图像,类型为np.uint8或np.float32。
  • nextImg: 当前帧图像,与prevImg具有相同的类型和尺寸。
  • prevPts: 上一帧图像中检测到的稀疏点集,类型为np.float32,形状为(N, 1, 2),其中N是点的数量,每个点是一个(x, y)坐标。
  • nextPts: 当前帧图像中对应prevPts的稀疏点集,同样为np.float32类型,形状为(N, 1, 2)。
  • density: 光流场的密度,控制输出光流场的平滑程度。较高的值意味着更密集的光流场,但也可能包含更多的噪声。默认值为1.0。
  • sigma_dist: 在计算光流时,空间邻近性的高斯核标准差。较小的值意味着更关注局部邻域。
  • sigma_color: 在计算光流时,颜色相似性的高斯核标准差。较小的值意味着颜色变化对光流的影响更大。
  • patchSize: 用于计算光流时考虑的邻域大小。较大的值可以提高算法的鲁棒性,但也会增加计算量。
  • maxLevel: 金字塔的最大层数。算法会在多个尺度上计算光流,以提高对大尺度运动的处理能力。
    返回值
  • flow: 密集光流场,类型为np.float32,形状为(height, width, 2),其中每个像素点(x, y)的光流是一个(u, v)向量,分别表示在水平和垂直方向上的运动分量。

示例代码

import cv2  
import numpy as np  # 假设 prevImg, nextImg, prevPts, nextPts 已经准备好  
# ...  # 计算密集光流场  
flow = cv2.optflow.calcOpticalFlowSparseToDense(prevImg, nextImg, prevPts, nextPts, density=1.0, sigma_dist=0.05, sigma_color=0.1, patchSize=21, maxLevel=2)  # 可视化光流场  
hsv = np.zeros_like(nextImg)  
hsv[...,1] = 255  
hsv[...,0] = 0.5 * flow[...,0] + 0.5  
hsv[...,2] = 0.5 * flow[...,1] + 0.5  
hsv = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)  
img = cv2.add(nextImg, hsv)  # 显示结果  
cv2.imshow('Optical Flow', img)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

5.4、cv2.calcOpticalFlowFarneback

cv2.calcOpticalFlowFarneback 是 OpenCV 库中用于计算两个连续帧之间稠密光流的函数。该函数基于 Gunnar Farneback 的算法,该算法在计算速度和准确性之间取得了良好的平衡。

函数原型

cv2.calcOpticalFlowFarneback(prevImg, nextImg, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, flags[, flow])

参数说明

  • prevImg: 前一帧的图像(灰度图像)。类型为 np.uint8。
  • nextImg: 下一帧的图像(灰度图像),与前一帧保持同样的格式和尺寸。类型为 np.uint8。
  • pyr_scale: 指定图像金字塔上下两层之间的尺度关系(<1)。通常设置为 0.5,表示图像金字塔上一层是下一层的两倍降采样。
  • levels: 金字塔的层数,包括初始图像在内。levels=1 表示不创建额外的图层,仅使用原始图像。
  • winsize: 均值窗口大小。较大的值会增加算法对图像噪声的鲁棒性,并可以检测更快速的运动,但会产生更模糊的运动场。
  • iterations: 算法迭代次数。每个金字塔层级的迭代次数。
  • poly_n: 用于在每个像素点处计算多项式展开的相邻像素点的个数。较大的值意味着图像的近似逼近越光滑,算法鲁棒性更好,但也会带来更多的运动区域模糊。通常设置为 5 或 7。
  • poly_sigma: 高斯标准差,用于平滑用作多项式展开基础的导数。poly_n=5 时,poly_sigma 可设置为 1.1;poly_n=7 时,可设置为 1.5。
  • flags: 操作标志,可以是以下选项的组合:
  • OPTFLOW_USE_INITIAL_FLOW: 使用输入流作为初始流近似。
  • OPTFLOW_FARNEBACK_GAUSSIAN: 使用高斯滤波器代替盒式滤波器进行光流估计。这通常可以提供更精确的光流估计,但会降低速度。
  • flow: 输出参数,与 prevImg 大小相同,类型为 CV_32FC2 的计算流图像。如果不提供,则函数将分配并返回一个新的流图像。

返回值

  • flow: 类型为 np.float32 的二维数组,表示每个像素点的运动向量。其形状为 (height, width, 2),其中每个像素点 (x, y) 的光流是一个 (u, v) 向量,分别表示在水平和垂直方向上的运动分量。

使用示例

import cv2  
import numpy as np  # 读取前后两帧图像  
prev_frame = cv2.imread('frame1.jpg')  
next_frame = cv2.imread('frame2.jpg')  # 将图像转换为灰度图  
gray_prev = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)  
gray_next = cv2.cvtColor(next_frame, cv2.COLOR_BGR2GRAY)  # 计算光流  
flow = cv2.calcOpticalFlowFarneback(gray_prev, gray_next, None, 0.5, 3, 15, 3, 5, 1.2, 0)  # 可视化光流(这里省略了可视化代码,通常使用箭头或其他方式表示光流)

注意事项

  • 确保输入的两帧图像是灰度图像,因为 cv2.calcOpticalFlowFarneback 函数仅处理灰度图像。
  • 参数的选择对光流计算的准确性和计算速度有很大影响,需要根据实际情况进行调整。
  • 光流计算的结果是一个二维数组,表示每个像素点的运动向量,可以通过可视化工具进行展示和分析。

5.5、cv2.optflow.calcOpticalFlowDenseRLOF

cv2.optflow.calcOpticalFlowDenseRLOF 是 OpenCV 中用于计算两帧之间光流的一个函数,它属于密集光流算法的一种。RLOF 代表 Robust Local Optical Flow,即鲁棒的局部光流算法。这种算法试图通过考虑图像中的局部特征和区域来更准确地估计光流,即使在图像中存在噪声、遮挡或运动不连续的情况下也能表现出较好的性能。

函数原型

cv2.optflow.calcOpticalFlowDenseRLOF(prevImg, nextImg, win_size, max_iter, eps, criteria_type[, dst[, flow[, layers[, scale_layers]]]])

参数解释

  • prevImg: 前一帧图像,必须是单通道、8位或浮点型图像。
  • nextImg: 当前帧图像,与前一帧图像具有相同的类型和大小。
  • win_size: 用于局部邻域的窗口大小,通常为奇数。
  • max_iter: 迭代算法的最大迭代次数。
  • eps: 算法停止的阈值。
  • criteria_type: 迭代停止的条件,可以是 cv2.TERM_CRITERIA_EPS 或 cv2.TERM_CRITERIA_COUNT 或它们的组合,表示根据迭代次数或阈值来停止。
  • dst: 输出光流图,如果提供,则必须是与前两帧相同大小的浮点型双通道图像(每个像素的光流向量)。
  • flow: 初始化光流场(可选),用于在连续帧之间传递光流信息。
  • layers: 金字塔层数(可选),用于多尺度处理。
  • scale_layers: 金字塔各层之间的缩放因子(可选)。

返回值

  • dst: 如果未提供 dst 参数,则函数返回计算得到的光流图,它是一个与输入图像大小相同的浮点型双通道图像,其中每个像素的值表示该像素的光流向量(水平和垂直分量)。

使用示例

import cv2  
import numpy as np  # 加载视频或图像序列  
cap = cv2.VideoCapture('video.mp4')  ret, prev = cap.read()  
if not ret:  exit()  prev_gray = cv2.cvtColor(prev, cv2.COLOR_BGR2GRAY)  while cap.isOpened():  ret, next = cap.read()  if not ret:  break  next_gray = cv2.cvtColor(next, cv2.COLOR_BGR2GRAY)  # 计算光流  flow = cv2.optflow.calcOpticalFlowDenseRLOF(prev_gray, next_gray, win_size=15, max_iter=3, eps=0.01, criteria_type=cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_COUNT, dst=None)  # 可视化光流  hsv = np.zeros_like(next)  hsv[..., 1] = 255  hsv[..., 0] = 0.5 * flow[..., 0] + 0.5  hsv[..., 2] = 0.5 * flow[..., 1] + 0.5  bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)  # 显示结果  cv2.imshow('Optical Flow', bgr)  if cv2.waitKey(30) & 0xFF == ord('q'):  break  # 更新前一帧  prev_gray = next_gray.copy()  cap.release()  
cv2.destroyAllWindows()

参考

  • OpenCV进阶(2)OpenCV中的光流

  • Optical Flow in OpenCV (C++/Python)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/400787.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CentOS7.9上通过KVM安装Centos虚拟机

目录 1 开发前准备&#xff08;先确保服务器可以虚拟化&#xff09;&#xff1a; 2、安装KWM环境 3、创建镜像文件存放目录 4、创建镜像文件存放目录 5、安装桥连接虚拟网络 6、安装虚拟机 7、配置操作系统 8、虚拟机配置网卡地址 9、克隆虚拟机执行 1开发前准备&am…

Unity教程(十)Tile Palette搭建平台关卡

Unity开发2D类银河恶魔城游戏学习笔记 Unity教程&#xff08;零&#xff09;Unity和VS的使用相关内容 Unity教程&#xff08;一&#xff09;开始学习状态机 Unity教程&#xff08;二&#xff09;角色移动的实现 Unity教程&#xff08;三&#xff09;角色跳跃的实现 Unity教程&…

IDEA 创建类时自动生成注释

一、背景 在开发的过程中&#xff0c;公司都会要求开发针对自己创建的类进行一些描述说明&#xff0c;为了便于程序员在创建类时快速生成注释。 二、如何配置? 打开File -> Settings -> Editor -> File and Code Templates -> Includes&#xff0c;在File Header…

Unity新输入系统结构概览

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途 本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正 在学习新输入系统之前&#xff0c;我们需要对其构成有个印象 1.输入动作&#xff08;Inputaction&#xff09; 是定义输…

一次caffeine引起的CPU飙升问题

背景 背景是上游服务接入了博主团队提供的sdk&#xff0c;已经长达3年&#xff0c;运行稳定无异常&#xff0c;随着最近冲业绩&#xff0c;流量越来越大&#xff0c;直至某一天&#xff0c;其中一个接入方&#xff08;流量很大&#xff09;告知CPU在慢慢上升且没有回落的迹象&…

2分钟搭建一个简单的WebSocket服务器

你好同学&#xff0c;我是沐爸&#xff0c;欢迎点赞、收藏和关注。个人知乎 如何用2分钟在本地搭建一个简单的 WebSocket 服务器&#xff1f;其实使用 Node.js&#xff0c;加上一些流行的库&#xff0c;是很容易实现的。前端同学通过自己搭建 WebSocket 服务器&#xff0c;对于…

百问网全志系列开发板音频ALSA配置步骤详解

8 ALSA 8.1 音频相关概念 ​ 音频信号是一种连续变化的模拟信号&#xff0c;但计算机只能处理和记录二进制的数字信号&#xff0c;由自然音源得到的音频信号必须经过一定的变换&#xff0c;成为数字音频信号之后&#xff0c;才能送到计算机中作进一步的处理。 ​ 数字音频系…

系统重装简记

写在文章开头 因为固态损毁而更换固态&#xff0c;所以需要进行系统重装&#xff0c;由于系统重装都是固定的繁琐的步骤&#xff0c;所以就以这篇文章来记录一下系统重装的一些日常步骤&#xff0c;希望对你有帮助。 Hi&#xff0c;我是 sharkChili &#xff0c;是个不断在硬核…

《Linux运维总结:基于x86_64架构CPU使用docker-compose一键离线部署etcd 3.5.15容器版分布式集群》

总结&#xff1a;整理不易&#xff0c;如果对你有帮助&#xff0c;可否点赞关注一下&#xff1f; 更多详细内容请参考&#xff1a;《Linux运维篇&#xff1a;Linux系统运维指南》 一、部署背景 由于业务系统的特殊性&#xff0c;我们需要面对不同的客户部署业务系统&#xff0…

【网编】——UDP编程

宏观操作 服务器&#xff1a;socket创套接字—bind绑定连接—recvfrom接收数据/sendto发送数据 客户端&#xff1a;socket创套接字—sendto发送数/recvfrom接收数据—close关闭套接字 函数 recv ssize_t recvfrom ( int sockfd , void * buf , size_t len , int flags , str…

链接Mysql 报错connection errors; unblock with ‘mysqladmin flush-hosts‘错误的解决方法!亲测有效!

文章目录 前言一、使用 mysqladmin flush-hosts 命令解锁 IP 地址二、增加 max_connect_errors 参数三、检查连接错误的原因 前言 今天正常的对各大的测试服进行重启的时候发现每台服务器都启动失败&#xff01;查看日志发现每台服务器都报一下的错误 java.sql.SQLException:…

【学习笔记】Day 13

一、进度概述 1、《地震勘探原理》第六章 二、详情 个人感觉第五&#xff0c;六&#xff0c;八章的解释更倾向于地质学那边负责的&#xff0c;但是多了解相关原理&#xff0c;肯定是有利于 DL-FWI 的相关研究的&#xff0c;所以这里只是做一个粗略的归纳&#xff0c;相关内容详…

android车载手机互联投屏新专题-实战作业布置

背景&#xff1a; 学习了马哥的投屏实战开发课程后&#xff0c;大家都可以实现如下图一样的手机车机多端互联的投屏场景。 即已经实现了手机和车机投屏互动&#xff0c;车机上手机画面屏幕可以与手机实体屏幕一样就是常见的Mirror模式&#xff0c;如果不一样就是课程里面讲的扩…

【策略模式】设计模式系列:在Java中实现灵活的行为选择(实战指南)

文章目录 策略模式&#xff1a;在Java中实现灵活的行为选择引言1. 策略模式的组成1.1 抽象策略 (Strategy)1.2 具体策略 (Concrete Strategy)1.3 上下文 (Context)1.4 UML类图和时序图 2. 策略模式在Java中的实现步骤一&#xff1a;定义抽象策略接口步骤二&#xff1a;创建具体…

波涛汹涌的海面:适用于恶劣环境的水冷电阻器

电阻器液体冷却可提升 3.3kV 中压负载&#xff0c;并大幅减少工业和船舶应用中的电阻器占用空间。在起重机、升降机、升降机和输送机等电机驱动应用中&#xff0c;风冷电阻器很常见&#xff0c;但在中压、高功率应用中&#xff0c;液体冷却胜出。 使用 3.3kV 电源运行以转动 5…

vue前端可以完整的显示编辑子级部门,用户管理可以为用户分配角色和部门?

用户和角色是一对多的关系用户和部门是多对多得关系<template><div class="s"><!-- 操作按钮 --><div class="shang"><el-input v-model="searchText" placeholder="请输入搜索关键词" style="width:…

MySQL的InnoDB的页里面存了些什么 --InnoDB存储梳理(三)

文章目录 创建新表页的信息新增一条数据根据页号找数据信息脚本代码py_innodb_page_info根据地址计算页号根据页号计算起始地址 主要介绍表空间索引页里面有哪些内容&#xff0c;数据在表空间文件里面是怎么组织的 创建新表页的信息 CREATE TABLE test8 (id bigint(20) NOT N…

跟着iMeta学做图|ggplot2绘制多个饼图展示菌群物种组成

原始教程链接&#xff1a;https://github.com/iMetaScience/iMetaPlot/tree/main/221017multi-pieplot 写在前面 饼图 (Pie Plot) 在微生物组研究中可以用来展示菌群物种组成&#xff0c;可以起到与堆叠柱状图相同的展示效果。本期我们挑选2022年4月5日刊登在iMeta上的The imp…

服务器安装哪吒面板详细教程

本文长期更新地址&#xff1a; 服务器安装哪吒面板详细教程-星零岁的博客https://blog.0xwl.com/13568.html 注&#xff1a;本文中部分内容源自网络&#xff0c;第四步中部分来自本人曾经文章&#xff1a;云服务器安装配置宝塔面板并安装基础运行环境教程-星零岁的博客 今天来讲…

VGMShield:揭秘视频生成模型滥用的检测与追踪技术

人工智能咨询培训老师叶梓 转载标明出处 视频生成模型&#xff0c;如 Stable Video Diffusion 和 Videocrafter&#xff0c;已经能够生成合理且高分辨率的视频。但这些技术进步也带来了被恶意利用的风险&#xff0c;比如用于制造假新闻或进行政治宣传。因此&#xff0c;来自弗…