当前位置: 首页 > news >正文

OpenCv高阶(十)——光流估计

文章目录

  • 前言
  • 一、光流估计
  • 二、使用步骤
      • 1、导库读取视频、随机初始化颜色
      • 2、初始化光流跟踪
      • 3、视频帧处理循环
      • 4、光流计算与可视化
      • 5、循环控制与资源释放
      • 完整代码
  • 总结


前言

在计算机视觉领域,光流估计是捕捉图像序列中像素点运动信息的核心技术。它描述了图像中每个像素点在相邻帧间的运动方向和速度,能从静态图像帧中解析出动态变化。
光流估计基于像素亮度不变和运动平滑两个关键假设,通过数学建模解算出像素运动场,为视频分析、目标跟踪等任务提供基础。OpenCV 集成了稀疏光流、稠密光流等计算方法,广泛应用于无人机避障、电影特效等场景。
接下来,我们将深入解析光流估计原理、OpenCV 函数使用及实战应用,探索这项技术的奥秘。

一、光流估计

光流估计是空间运动物体在观测成像平面上的像素运动的“瞬时速度”,根据各个像素点的速度矢量特征,可以对图像进行动态分析,例如目标跟踪。

光流估计的前提:
(1)亮度恒定:同一点随着时间的变化,其亮度不会发生改变。
(2)小运动:随着时间的变化不会引起位置的剧烈变化,只有小运动情况下才能用前后帧之间单位位置变化引起的灰度变化去近似灰度对位置的偏导数。
(3)空间一致:一个场景上邻近的点投影到图像上也是邻近点,且邻近点速度一致。因为光流法基本方程约束只有一个,而要求x,y方向的速度,有两个未知变量。所以需要连立n多个方程求解。

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

二、使用步骤

1、导库读取视频、随机初始化颜色

# 导入数值计算库和计算机视觉库
import numpy as np
import cv2# 创建视频捕获对象,读取测试视频
cap = cv2.VideoCapture('../data/test.avi')# 生成100种随机颜色,用于不同特征点的轨迹绘制
# 格式为(100,3)的数组,每个元素代表BGR颜色值
color = np.random.randint(0, 255, (100, 3))

2、初始化光流跟踪

# 读取视频第一帧
ret, old_frame = cap.read()# 将第一帧转换为灰度图像(光流算法需要灰度输入)
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)# 设置特征点检测参数字典
feature_params = dict(maxCorners = 100,      # 检测的最大特征点数量qualityLevel = 0.3,    # 特征点质量阈值(0-1,值越大质量越高)minDistance = 7        # 特征点之间的最小像素距离
)# 使用Shi-Tomasi算法检测角点特征
# goodFeaturesToTrack:在灰度图像中寻找适合跟踪的强角点
p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)# 创建与视频帧同尺寸的全黑图像,用于绘制运动轨迹
mask = np.zeros_like(old_frame)# 设置Lucas-Kanade光流算法参数
lk_params = dict(winSize = (15, 15),   # 每个金字塔层的搜索窗口大小maxLevel = 2          # 金字塔层数(0表示不使用金字塔)
)

3、视频帧处理循环

while True:# 读取新帧ret, frame = cap.read()# 视频结束或读取失败时退出循环if not ret:break# 将当前帧转换为灰度图像frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

4、光流计算与可视化

     # 使用Lucas-Kanade金字塔光流法计算特征点运动# p1:新帧中特征点位置# st:状态标记(1表示成功跟踪,0表示丢失)# err:跟踪误差p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)# 筛选成功跟踪的特征点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().astype(int)c, d = old.ravel().astype(int)# 在mask图像上绘制运动轨迹线# 参数:目标图像,起点,终点,颜色,线宽mask = cv2.line(mask, (a, b), (c, d), color[i].tolist(), 2)# 显示纯轨迹图像cv2.imshow("mask", mask)# 将轨迹叠加到原始帧上img = cv2.add(frame, mask)# 显示叠加后的结果帧cv2.imshow('frame', img)

5、循环控制与资源释放

    # 等待150ms并检测ESC按键(ASCII 27)k = cv2.waitKey(150)if k == 27:break# 更新前一帧数据old_gray = frame_gray.copy()  # 更新灰度图像# 更新特征点(只保留成功跟踪的点)# reshape(-1,1,2)保持与原始p0相同的维度结构p0 = good_new.reshape(-1, 1, 2)# 释放视频资源并销毁所有窗口
cv2.destroyAllWindows()
cap.release()

效果:

完整代码

# 导入必要的库
import numpy as np
import cv2# 创建视频捕获对象,读取视频文件
cap = cv2.VideoCapture('../data/test.avi')# 生成随机颜色数组,用于绘制不同特征点的轨迹(100种颜色)
color = np.random.randint(0, 255, (100, 3))# 读取视频的第一帧
ret, old_frame = cap.read()# 将第一帧转换为灰度图像
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)# 设置特征点检测参数
feature_params = dict(maxCorners=100,   # 最大特征点数量qualityLevel=0.3, # 特征点质量等级(0-1之间,越大质量越高)minDistance=7     # 特征点之间的最小欧氏距离
)# 使用Shi-Tomasi方法检测初始特征点(角点检测)
p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)# 创建一个与视频帧大小相同的全黑图像,用于绘制轨迹
mask = np.zeros_like(old_frame)# Lucas-Kanade光流算法参数设置
lk_params = dict(winSize=(15, 15),  # 每个金字塔层的搜索窗口大小maxLevel=2         # 金字塔层数(0表示仅当前层)
)# 主循环处理视频帧
while True:# 读取新的一帧ret, frame = cap.read()if not ret:  # 如果读取失败(如视频结束)则退出循环break# 将当前帧转换为灰度图像frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# 计算光流(Lucas-Kanade方法)p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray,  # 前一帧的灰度图像frame_gray, # 当前帧的灰度图像p0,         # 需要跟踪的特征点None,       # 不使用前一帧的特征点位置**lk_params)# 筛选成功跟踪的特征点(st=1表示成功跟踪)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().astype(int)c, d = old.ravel().astype(int)# 在mask上绘制运动轨迹线(使用随机颜色)mask = cv2.line(mask, (a, b), (c, d), color[i].tolist(), 2)# 将轨迹mask与当前帧叠加显示img = cv2.add(frame, mask)cv2.imshow('frame', img)cv2.imshow('mask', mask)  # 单独显示轨迹mask# 等待按键(150ms延迟),ESC键退出k = cv2.waitKey(150)if k == 27:break# 更新前一帧的灰度图像和特征点old_gray = frame_gray.copy()p0 = good_new.reshape(-1, 1, 2)  # 更新为当前帧的有效特征点# 释放资源并关闭所有窗口
cv2.destroyAllWindows()
cap.release()

总结

光流估计的应用:
视频增强与创作:光流不仅用于运动补偿压缩(如MPEG标准),还被应用于视频插帧(生成中间帧提升流畅度)和特效合成(如电影中动态背景替换),英伟达SDK已展示其商业化潜力。

医疗精准化:在超声影像中,光流估计校正探头移动导致的图像偏移,辅助心脏手术的实时导航;还可量化器官运动参数(如心肌应变率),为疾病诊断提供动态指标。

工业智能化升级:生产线中,光流实时监测机械臂运动轨迹,结合异常检测算法预防故障;在精密装配场景,通过微位移分析提升质检精度。

http://www.xdnf.cn/news/137899.html

相关文章:

  • Oracle_开启归档日志和重做日志
  • AXOP34062: 40V双通道运算放大器
  • C 语言内存分配方法及优缺点
  • 国内多层PCB供应商优选指南
  • 【每天一个知识点】IPv4(互联网协议版本4)和IPv6(互联网协议版本6)
  • vite+vue构建的网站项目localhost:5173打不开
  • ASP.NET MVC​ 入门指南二
  • [基础] Windows PCIe设备驱动框架与开发实践深度解析
  • 面向高性能运动控制的MCU:架构创新、算法优化与应用分析
  • DeepSeek大模型应用学习通知
  • 嵌入式:ARM系列分类及主要应用场景
  • SpringCloud搭建Eureka注册中心
  • Python解析地址中省市区街道
  • 3D Web轻量化引擎HOOPS Communicator 发布3.0版本:平台支持扩展至Linux on ARM64!
  • 【Leetcode 每日一题】2845. 统计趣味子数组的数目
  • 技术面试一面标准流程
  • MiniMind模型的web交互功能初试
  • 28、.NET 中元数据是什么?
  • LeNet5 神经网络的参数解析和图片尺寸解析
  • 《R语言SCI期刊论文绘图专题计划》大纲
  • ​​激光雷达(LiDAR)数据​​ 的标准存储格式.las文件介绍
  • C++ (STL,顺序容器,关联容器,容器适配器)
  • 如何使用SeedProd创建无缝的WordPress维护页面
  • 【刷题Day26】Linux命令、分段分页和中断(浅)
  • AD相同网络的铜皮和导线连接不上
  • 5.2 AutoGen:支持多Agent对话的开源框架,适合自动化任务
  • 深入解析 Linux 中动静态库的加载机制:从原理到实践
  • 文件的读取操作
  • Unity3D IK解算器技术分析
  • 安卓手机下载谷歌浏览器遇到兼容问题怎么办【三步解决】