【python】OpenCV—Optical Flow

news2024/12/26 22:04:43

在这里插入图片描述

文章目录

  • 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 np


def 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 = 0
    while True:
        index += 1
        ret, frame = cap.read()
        if not ret:
            break
        frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        # 计算光流
        # calcOpticalFlowPyrLK(prevImg, nextImg, prevPts, nextPts[, status[, err[, \\
        # winSize[, maxLevel[, criteria[, flags[, minEigThreshold]]]]]]]) -> nextPts, status, err
        p1, 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) & 0xFF
        if k == 27:
            break
        if 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 argparse


def 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 = 0
    while True:
        index += 1
        # 读取下一帧
        ret, new_frame = cap.read()
        frame_copy = new_frame
        if 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 / 2
        hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
        # 转换HSV图像为BGR
        bgr = 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) & 0xFF
        if k == 27:
            break
        old_frame = new_frame


def 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_path
    if args.algorithm == "lucaskanade_dense":
        method = cv2.optflow.calcOpticalFlowSparseToDense
        dense_optical_flow(method, video_path, to_gray=True)

    elif args.algorithm == "farneback":
        # OpenCV Farneback算法需要一个单通道的输入图像,因此我们将BRG图像转换为灰度。
        method = cv2.calcOpticalFlowFarneback
        params = [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.calcOpticalFlowDenseRLOF
        dense_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.coloradmin.cn/o/2039664.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

超赞!墙裂推荐这款开箱即用、永久免费的运维监控平台

文章目录 简介一、初次印象&#xff1a;直观而强大的界面二、深入体验&#xff1a;6个重点功能模块1、告警管理2、综合监控3、业务服务4、网络拓扑5、可视化管理6、知识库7、报表管理 Lerwee AI 在当今这个数字化时代&#xff0c;企业依赖于强大的IT基础设施来支持其日常运营。…

微软Detours Hook库编译与使用

Detours 是微软开发的一个强大的Windows API钩子库&#xff0c;用于监视和拦截函数调用。它广泛应用于微软产品团队和众多独立软件开发中&#xff0c;旨在无需修改原始代码的情况下实现函数拦截和修改。Detours 在调试、监控、日志记录和性能分析等方面表现出色&#xff0c;已成…

java之如何爬取本地数据(利用正则表达式)

public class RegexDemo4 {public static void main(String[] args) {String s"程序员学习java&#xff0c;""电话&#xff1a;181512516758&#xff0c;18512508907" "或者联系邮箱&#xff1a;boniuitcast.cn&#xff0c;""座机电话&…

基于vue框架的RTY个人记账管理系统03jc1(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,收入分类,支出分类,收入信息,支出信息,开支预算,负债信息 开题报告内容 基于Vue框架的RTY个人记账管理系统 开题报告 一、研究背景与意义 随着社会经济的快速发展和人们生活水平的不断提升&#xff0c;个人财务管理成为越来越…

centos7.9 内核升级至5.4

一、修改yum源 查看现有系统内核版本&#xff1a; 备份系统自带的yum源&#xff1a; 一、修改CentOS-Base.repo ## cat CentOS-Base.repo # CentOS-Base.repo # # The mirror system uses the connecting IP address of the client and the # update status of each mirror t…

详细解读keepalived高可用集群

一.高可用集群 1.1 集群类型 LB&#xff1a;Load Balance 负载均衡LVS/HAProxy/nginx&#xff08;http/upstream, stream/upstream&#xff09;HA&#xff1a;High Availability 高可用集群数据库、RedisSPoF: Single Point of Failure&#xff0c;解决单点故障HPC&#xff1…

docker容器挂载USB串口设备

1、在容器所在宿主机确认USB串口设备 有两种方法可以将USB设备挂载到容器中: 使用--privileged参数或者使用--device参数 --prvleged参数可以让容器拥有主机的所有特权&#xff0c;包括所有可以访问USB设备。--device参数可以针对特定的设备挂载到容器中。 [rootdocker40 ~]…

【经验总结】ShardingSphere+Springboot-01模式参数配置

文章目录 详细配置&#xff08;boot&#xff09;一、模式配置&数据源配置1.1 模式配置1.2 数据源配置1.3 默认数据源的配置默认数据源配置结论 二、基础属性配置2.1 在日志中打印 SQL2.2 在程序启动和更新时&#xff0c;是否检查分片元数据的结构一致性 详细配置&#xff0…

JavaScript高阶笔记总结第三天:(JavaScript高阶完结)

Xmind鸟瞰图&#xff1a; 简单文字总结&#xff1a; js高阶笔记总结&#xff1a; 严格模式&#xff1a; 1.开启严格模式&#xff1a;"use strict" 2.不使用var关键字声明会报错 3.严格模式下普通函数的this指向undefined 高阶函数&#xff1a; 满足…

浅谈C/C++指针和引用在Linux和Windows不同环境下的编码风格

目录 0. 前言 1. 代码块、函数体上的 { } 的规范 2. 指针和引用中的 * 和 & 符号的位置 1. Linux 环境下编码风格(gcc) 2. Windows 环境下编码风格(Visual Studio) 3. 简单总结 0. 前言 C/C因为高度的自由性&#xff0c;并没有对一些常见的编码风格进行限制&#…

https://registry.nlark.com/无法访问

先上问题&#xff1a; own up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. npm ERR! code ENOTFOUND npm ERR! syscall getaddrinfo npm ERR! errno ENOTFOU…

电动自行车出海黑马Avento独立站拆解(上)丨出海笔记

这次我们来拆解一个电动自行车的独立站 为什么选电动自行车&#xff1f; 因为全球疫情&#xff0c;带来出行问题——避免聚集&#xff0c;大家都减少了公共交通工具&#xff0c;而改为自行车&#xff0c;电动自行车...... 君不见疫情之后无论是出行自行车&#xff0c;还是健…

NMAP扫描器的使用

NMAP 一 概述 nmap是一个网络探测和安全扫描工具,系统管理者和个人可以使用这个软件扫描大型的网络&#xff0c;获取 哪台主机正在运行以及提供什么服务等信息。 nmap可用于 检测活在网络上的主机(主机发现)。 检测主机上开放的端口(端口发现)。 检测到相应的端口(服务发现…

cisp-pte考试复盘

考试客户端下载-->点击进入考试>输入密码->进去可以看见一个qax的登录框【监考员会告知账户密码】->进入考试页面 里面的操作题,点击开始答题,能看见一个题有一个攻击机,这时我们需要点击鼠标左键,看见一个控制台,点击控制台才能进入答题【双击是没有用的】 …

C/C++开发,opencv内置背景减除算法与运动检测

目录 一、c opencv 背景减除算法内置算法 1.1 MOG2算法 1.2 KNN算法 二、完整案例实现 2.1 程序代码 2.2 程序编译及输出 一、c opencv 背景减除算法内置算法 背景减除算法的目标是将视频帧中的背景与前景&#xff08;通常是移动的对象&#xff09;分离。OpenCV提供MOG2&…

数据结构-排序的概念、应用及其算法实现1(直接插入排序、希尔排序、选择排序、堆排序、冒泡排序)

本篇文章主要讲解直接插入排序、希尔排序、选择排序、堆排序、冒泡排序算法实现以及时间复杂度&#xff0c;稳定性分析。将在接下来的文章讲解快速排序、归并排序和计数排序。 本文全部代码在文章最后 目录 一、常见的排序算法 a.排序实现的接口 1.1插入排序 1.1.1基本思想…

【C++】BFS解决边权唯一的最短路径问题

目录 介绍 迷宫中离入口最近的出口 算法思路 代码实现 最小基因变化 算法思路 代码实现 单词接龙 算法思路 代码实现 为高尔夫比赛砍树 算法思路 代码实现 介绍 最短路问题是图论中非常经典的一种问题,其实就是通过代码找到两点之间的最优路径(往往是距离最短),最…

用MobaXterm,TightVNC和secure SSH实现两台windows电脑之间的连接和通信

今天给大家分享一个非常有趣的技术&#xff0c;那便是如何使用MobaXterm来实现两台电脑之间的通信。实验成功&#xff0c;保证能跑。 首先&#xff0c;给大家介绍我们今天最重要的工具&#xff1a;那便是MobaXterm&#xff08;以下由ChatGPT生成&#xff09;&#xff1a; Moba…

C++初阶_2: inline内联函数 宏函数

C推出了inline关键字&#xff0c;其目的是为了替代C语言中的宏函数。 我们先来回顾宏函数&#xff1a; 宏函数 现有个需求&#xff1a;要求你写一个Add(x,y)的宏函数。 正确的写法有一种&#xff0c;错误的写法倒是五花八门&#xff0c;我们先来“见不贤而自省也。” // …

我怎么会这么依赖 GUI?

AWS CLI、.NET 和 Lambda 函数 欢迎来到雲闪世界。在 Windows 上使用 Visual Studio 和 AWS Explorer 绝对会让你变得懒惰。我的意思是&#xff0c;能够通过右键单击项目来构建和部署 Lambda 函数之类的东西真是太棒了&#xff0c;但有时最好了解幕后发生了什么。 尽管如此&am…