《OpenCV》——光流估计

什么是光流估计?

光流估计的前提?



基本假设

  • 亮度恒定假设:目标像素点的亮度在相邻帧之间保持不变。这是光流计算的基础假设,基于此可以建立数学方程来求解光流。
  • 时间连续或运动平滑假设:相邻帧之间的时间间隔足够小,使得像素点的运动是连续的,不会发生突变;或者说相邻像素点的运动情况是相似的,具有平滑性。

经典算法

  • Lucas-Kanade 光流算法:该算法基于局部平滑假设,通过在一个小的窗口内对多个像素点进行约束,求解光流方程。它是一种基于梯度的方法,计算效率较高,常用于实时性要求较高的应用中。
  • Horn-Schunck 光流算法:是一种全局的光流估计算法,在亮度恒定和光滑性约束的基础上,通过最小化一个能量函数来求解光流。它考虑了整幅图像的信息,能够得到较为平滑的光流场,但计算量相对较大。
  • 基于深度学习的光流估计算法:近年来,随着深度学习的发展,基于卷积神经网络(CNN)的光流估计算法取得了很好的效果。例如 FlowNet、PWC-Net 等,这些算法通过大量的训练数据学习图像之间的运动模式,能够处理复杂的场景和运动情况,并且在精度和速度上都有了很大的提升。

实例

对视频中的人物走动轨迹进行光流追踪处理。

实现了基于 Lucas - Kanade 算法的稀疏光流估计,用于处理视频中的运动跟踪。

  • 导入必要的库
python 复制代码
import numpy as np
import cv2

导入numpy库用于数值计算,cv2是 OpenCV 库,用于计算机视觉任务

  • 打开视频文件并初始化颜色
python 复制代码
cap = cv2.VideoCapture('test.avi')
color = np.random.randint(0, 255, (100, 3))

cv2.VideoCapture('test.avi'):打开名为test.avi的视频文件。

np.random.randint(0, 255, (100, 3)):生成 100 个随机的 RGB 颜色,用于后续绘制光流轨迹。

  • 读取第一帧并转换为灰度图
python 复制代码
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)

cap.read():读取视频的第一帧,ret是一个布尔值,表示是否成功读取帧,old_frame是读取的帧图像。

cv2.cvtColor():将彩色图像转换为灰度图像,因为光流估计通常在灰度图像上进行。

  • 检测特征点
python 复制代码
feature_params = dict(maxCorners=100,
                      qualityLevel=0.3,
                      minDistance=7)
p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)

cv2.goodFeaturesToTrack():使用 Shi - Tomasi 角点检测算法检测图像中的特征点。

feature_params是一个字典,包含了角点检测的参数:

  • maxCorners:最多检测的角点数量。
  • qualityLevel:角点质量的阈值,只有质量高于该阈值的角点才会被保留。
  • minDistance:相邻角点之间的最小距离。
  • 初始化掩码图像
python 复制代码
mask = np.zeros_like(old_frame)

创建一个与第一帧图像大小相同的全零掩码图像,用于绘制光流轨迹。

  • 设置 Lucas - Kanade 光流算法的参数
python 复制代码
lk_params = dict(winSize=(15, 15),
                 maxLevel=2)

winSize:搜索窗口的大小,用于在计算光流时对每个像素点周围的区域进行分析。

maxLevel:金字塔的最大层数,用于处理大位移的光流。

  • 循环处理视频帧
python 复制代码
while True:
    ret, frame = cap.read()
    if not ret:
        break
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
    good_new = p1[st == 1]
    good_old = p0[st == 1]

cap.read():读取视频的下一帧。

cv2.calcOpticalFlowPyrLK():使用金字塔 Lucas - Kanade 算法计算光流。

  • old_gray:前一帧的灰度图像。
  • frame_gray:当前帧的灰度图像。
  • p0:前一帧检测到的特征点。
  • p1:当前帧中对应的特征点位置。
  • st:状态数组,用于表示每个特征点是否被成功跟踪,st == 1表示成功跟踪。
  • err:每个特征点的跟踪误差。
  • 绘制光流轨迹
python 复制代码
    for i, (new, old) in enumerate(zip(good_new, good_old)):
        a, b = new.ravel()
        c, d = old.ravel()
        a, b, c, d = int(a), int(b), int(c), int(d)
        mask = cv2.line(mask, (a, b), (c, d), color[i].tolist(), 2)
    img = cv2.add(frame, mask)

cv2.line():在掩码图像上绘制从旧特征点到新特征点的线段。

cv2.add():将掩码图像与当前帧图像叠加,得到带有光流轨迹的图像。

  • 显示结果并更新帧信息
python 复制代码
 cv2.imshow('mask', mask)
    cv2.imshow('frame', img)
    k = cv2.waitKey(150)
    if k == 27:
        break
    old_gray = frame_gray.copy()
    p0 = good_new.reshape(-1, 1, 2)

cv2.imshow():显示掩码图像和带有光流轨迹的图像。

cv2.waitKey(150):等待 150 毫秒,按下按键则返回按键的 ASCII 码。

k == 27:如果按下 ESC 键(ASCII 码为 27),则退出循环。

更新前一帧的灰度图像和特征点信息,以便下一帧的光流计算。

  • 释放资源
python 复制代码
cv2.destroyAllWindows()
cap.release()

cv2.destroyAllWindows():关闭所有打开的窗口。

cap.release():释放视频捕获对象。
这段代码通过 Lucas - Kanade 算法实现了视频中特征点的光流估计,并将光流轨迹绘制在视频帧上。它可以帮助我们观察视频中物体的运动情况。

  • 结果:
相关推荐
喜-喜4 分钟前
机器学习破局指南:零基础6个月系统训练计划
人工智能·机器学习
青松@FasterAI12 分钟前
【Arxiv 大模型最新进展】北大 Parenting 方法登场:参数魔法解锁检索增强语言模型新高度!
人工智能·语言模型·自然语言处理
admin皮卡14 分钟前
2.4 自动化评测答疑机器人的表现-大模型ACP模拟题-真题
前端·人工智能·机器学习
Donvink25 分钟前
【AIGC系列】3:Stable Diffusion模型介绍
人工智能·深度学习·语言模型·stable diffusion·aigc·transformer
赛逸展张胜1 小时前
AI赋能智能家居,CES Asia 2025论坛深度探讨行业未来
人工智能·科技
起个破名想半天了1 小时前
计算机视觉(opencv-python)入门之常见图像处理基本操作(待补充)
python·opencv·计算机视觉·图像处理基本操作
shelly聊AI2 小时前
GPT-5倒计时:2025年AI海啸来袭,机器与人类对话临近
人工智能·gpt·openai
FE802 小时前
opencv边缘检测
人工智能·opencv·计算机视觉
小小打工人2222 小时前
敏捷开发实践指南:从理论到落地的全面解析
人工智能·信息可视化·emacs
qq_254674412 小时前
罗成华教授论腹膜后肿瘤核磁共振检查意义
人工智能