《深度学习》OpenCV 光流估计 原理、案例解析

目录

一、光流估计

1、什么是光流估计

2、原理

3、光流估计算法

1)基于局部方法

2)和基于全局方法

4、光流估计的前提

1)亮度恒定

2)小运动

3)空间一致

二、案例实现

1、读取视频

2、特征检测

3、处理每一帧画面

运行结果:

4、释放资源

5、完整代码


一、光流估计

1、什么是光流估计

        光流估计是指通过计算相邻帧之间的像素位移,来估计图像中物体的运动信息。

2、原理

        假设相邻帧之间的像素亮度保持不变,并根据此假设计算每个像素的位移向量。

3、光流估计算法

        1)基于局部方法

                基于局部方法的光流估计算法通常基于图像区域内的像素点之间的亮度变化来计算位移向量。这些方法通常依赖于一些边缘、角点等特征点的检测和匹配。

        2)和基于全局方法

                基于全局方法的光流估计算法则通过优化能量函数来计算整个图像的位移向量。这些方法通常能够获得更准确的位移估计结果,但计算复杂度较高。

4、光流估计的前提

        1)亮度恒定

                同一点随着时间的变化,其亮度不会发生改变。

        2)小运动

                随着时间的变化不会引起位置的剧烈变化,只有小运动情况下才能用前后帧之间单位位置变化引起的灰度变化去近似灰度对位置的偏导数。

        3)空间一致

                一个场景上邻近的点投影到图像上也是邻近点,且邻近点速度一致。因为光流法基本方程约束只有一个,而要求x,y方向的速度,有两个未知变量。所以需要连立n多个方程求解。

二、案例实现

1、读取视频

# 打开视频文件
cap = cv2.VideoCapture('test.avi')
color = np.random.randint(0,255,(100,3))  # 生成随机整数数组,值范围为0-255,格式为100*3,以此充当颜色用来绘制轨迹,此处的值为矩阵类型
ret,old_frame = cap.read()   # 读取视频的di一帧画面,返回读取状态布尔值和每一帧的图像
old_gray = cv2.cvtColor(old_frame,cv2.COLOR_BGR2GRAY)  # 将第一帧转换为灰度图

2、特征检测

# 定义特征点检测参数
feature_params = dict(maxCorners=100,  # 最大角点数量,特征点qualityLevel = 0.3,   # 角点质量的阚值minDistance = 7)    # 两个特征点最小欧式距离,用于分散角点# 对第一帧画面进行特征检测
p0 = cv2.goodFeaturesToTrack(old_gray,mask=None,**feature_params)   # **:关键字参数解包,用于将字典解包为关键字参数,# 创建一个与给定数组大小和数据类型都相同的全0的新的数组,将其当做掩膜
mask = np.zeros_like(old_frame)#定义Lucas-Kanade光流参数
lk_params = dict(winSize=(15,15),  # 窗口大小为15*15maxLevel=2)   # 金字塔层数为2

3、处理每一帧画面

# 主循环,处理视频的每一帧
while (True):  # 定义一个死循环ret,frame = cap.read()   # 上述已经读取了第一帧画面,再次读取会接着第二帧进行读取if not ret:  # 检查是否成功读取到breakframe_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # 转换为灰度图# calcOpticalFlowPyrLK在图像序列中跟踪特征点的运动,计算前一帧old_gray特征点p0在当前帧frame_gray中的新位置p1p1,st,err = cv2.calcOpticalFlowPyrLK(old_gray,frame_gray,p0,None,**lk_params)# p1 特征点新坐标# st 状态数组,表示每个特征点是否被成功跟踪,1表示成功,0表示失败# err 错误数组,包含每个特征点的跟踪误差,误差与匹配质量有关# 选择好的点(状态为1的点)good_new = p1[st == 1]good_old = p0[st == 1]# 绘制轨迹for i,(new,old) in enumerate(zip(good_new,good_old)):  # 将新的特征点和旧的特征点进行打包,因为有很多特针点,所以使用enumerate将其转变成可迭代对象,返回索引和值a,b = new.ravel()   # 获取新点的坐标(a,b), 或者使用[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)  # 绘制线,在mask图像上绘制从点(a,b)到(c,d)的线,颜色为上述定义的,每个特征点的颜色不同cv2.imshow( 'mask', mask)img = cv2.add(frame, mask)  # 使用add叠加图像,将mask图像叠加到当前帧frame上cv2.imshow('frame', img)  # 显示结果图像# 等待150ms,检测是否按下了Esc键(键码为27)k = cv2.waitKey(150) & 0xffif k == 27:  # 按下ESC键,退出循环break# 更新旧灰度图和旧特征点old_gray = frame_gray.copy()  # 每当绘制完当前帧与上一帧的图像后将当前帧的副本赋值给上一帧使其进入下一个循环# 将当前帧的特征点的新位置赋值给p0,重新整理特征点为适合下次计算的形状p0 = good_new.reshape(-1,1,2)  # 将当前帧关键点的坐标形状更改为3维,-1表示自动判断维度大小,1,2表示一行两列
        运行结果:

4、释放资源

# 无制表符
cv2.destroyAllWindows()   # 关闭所有页面
cap.release()  # 释放摄像头资源

5、完整代码

import cv2
import numpy as np# 打开视频文件
cap = cv2.VideoCapture('test.avi')
color = np.random.randint(0,255,(100,3))  # 生成随机整数数组,值范围为0-255,格式为100*3,以此充当颜色用来绘制轨迹,此处的值为矩阵类型
ret,old_frame = cap.read()   # 读取视频的di一帧画面,返回读取状态布尔值和每一帧的图像
old_gray = cv2.cvtColor(old_frame,cv2.COLOR_BGR2GRAY)  # 将第一帧转换为灰度图# 定义特征点检测参数
feature_params = dict(maxCorners=100,  # 最大角点数量,特征点qualityLevel = 0.3,   # 角点质量的阚值minDistance = 7)    # 两个特征点最小欧式距离,用于分散角点# 对第一帧画面进行特征检测
p0 = cv2.goodFeaturesToTrack(old_gray,mask=None,**feature_params)   # **:关键字参数解包,用于将字典解包为关键字参数,# 创建一个与给定数组大小和数据类型都相同的全0的新的数组,将其当做掩膜
mask = np.zeros_like(old_frame)#定义Lucas-Kanade光流参数
lk_params = dict(winSize=(15,15),  # 窗口大小为15*15maxLevel=2)   # 金字塔层数为2# 主循环,处理视频的每一帧
while (True):  # 定义一个死循环ret,frame = cap.read()   # 上述已经读取了第一帧画面,再次读取会接着第二帧进行读取if not ret:  # 检查是否成功读取到breakframe_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # 转换为灰度图# calcOpticalFlowPyrLK在图像序列中跟踪特征点的运动,计算前一帧old_gray特征点p0在当前帧frame_gray中的新位置p1p1,st,err = cv2.calcOpticalFlowPyrLK(old_gray,frame_gray,p0,None,**lk_params)# p1 特征点新坐标# st 状态数组,表示每个特征点是否被成功跟踪,1表示成功,0表示失败# err 错误数组,包含每个特征点的跟踪误差,误差与匹配质量有关# 选择好的点(状态为1的点)good_new = p1[st == 1]good_old = p0[st == 1]# 绘制轨迹for i,(new,old) in enumerate(zip(good_new,good_old)):  # 将新的特征点和旧的特征点进行打包,因为有很多特针点,所以使用enumerate将其转变成可迭代对象,返回索引和值a,b = new.ravel()   # 获取新点的坐标(a,b), 或者使用[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)  # 绘制线,在mask图像上绘制从点(a,b)到(c,d)的线,颜色为上述定义的,每个特征点的颜色不同cv2.imshow( 'mask', mask)img = cv2.add(frame, mask)  # 使用add叠加图像,将mask图像叠加到当前帧frame上cv2.imshow('frame', img)  # 显示结果图像# 等待150ms,检测是否按下了Esc键(键码为27)k = cv2.waitKey(150) & 0xffif k == 27:  # 按下ESC键,退出循环break# 更新旧灰度图和旧特征点old_gray = frame_gray.copy()  # 每当绘制完当前帧与上一帧的图像后将当前帧的副本赋值给上一帧使其进入下一个循环# 将当前帧的特征点的新位置赋值给p0,重新整理特征点为适合下次计算的形状p0 = good_new.reshape(-1,1,2)  # 将当前帧关键点的坐标形状更改为3维,-1表示自动判断维度大小,1,2表示一行两列# 释放资源
cv2.destroyAllWindows()   # 关闭所有页面
cap.release()  # 释放摄像头资源

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

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

相关文章

案例实践 | 以长安链为坚实底层,江海链助力南通民政打造慈善应用标杆

案例名称-江海链 ■ 实施单位 中国移动通信集团江苏有限公司南通分公司、中国移动通信集团江苏有限公司 ■ 业主单位 江苏省南通市民政局 ■ 上线时间 2023年12月 ■ 用户群体 南通市民政局、南通慈善总会等慈善组织及全市民众 ■ 用户规模 全市近30家慈善组织&#…

【RoadRunner】自动驾驶模拟3D场景构建 | 软件简介与视角控制

💯 欢迎光临清流君的博客小天地,这里是我分享技术与心得的温馨角落 💯 🔥 个人主页:【清流君】🔥 📚 系列专栏: 运动控制 | 决策规划 | 机器人数值优化 📚 🌟始终保持好奇心&…

秋招突击——8/6——万得数据面试总结

文章目录 引言正文面经整理一1、讲一下java的多态,重载,重写的概念,区别2、说一下Java的数组,链表的结构,优缺点3、创建java线程的方式有哪些,具体说说4、创建线程池呢、每个参数的意义5、通过那几种方式保…

普通索引和唯一索引,应该怎么选择?

普通索引和唯一索引,应该怎么选择? 普通索引,不能保证字段的唯一性,所以普通索引会比唯一索引要多N次判断,比如判断下一条记录是否和目标相同。 InnoDB的数据其实是按页来取的,也就是说要拿到某一个数据&a…

AndroidStudio配置MQTT连接云平台EMQX

引言 本篇博客主要介绍mqtt和emqx配置连接实现数据收发,我会从基础的本机连接到手机和本机连接再到手机实现mqtt连接云平台,大家可以根据需要自行选择观看(后面两个教程都建立在mqtt和emqx下载完成的基础上,若没有下载完成&#x…

黎巴嫩爆炸事件分析:硬件国产自主可控的意义

黎巴嫩近期发生的寻呼机爆炸事件,不仅对当地社会造成了冲击,也在全球范围内引发了对通信设备安全性的深刻反思。这一事件凸显了在全球化背景下,电子产品安全性的重要性,以及自主可控技术在保障国家安全和公共安全中的关键作用。 …

DataWhale10月动手实践——Bot应用开发task02学习笔记

一、Prompt工程 之前有接触过一些Prompt工程的内容,也做过一些简单的应用,比如使用langchain和Openai库自己搭建了一个助手项目,但是还从未关注过在智能体方面的Prompt。在这篇博客中,我会将我之前掌握的和在本次任务学习中掌握的…

【C++】在Windows中使用Boost库——实现TCP、UDP通信

目录 一、编译Boost库 二、TCP服务端 三、TCP客户端 四、UDP连接 一、编译Boost库 1. 先去官网下载Boost库源码 2. 点击下载最新的版本 下载Windows环境的压缩包,然后解压 3. 在解压后的目录路径下找到“bootstrap.bat” 打开控制台,在“bootstrap.…

ROS2 常用工具之Launch -- 启动管理工具

基于上一篇的action代码上继续,链接如上: ROS2 通信三大件之动作 -- Action-CSDN博客 参考链接:ROS2——教你写新版Launch文件 | 范子琦的博客 1、创建文件 src/action_moudle/launch/action_launch.launch.py 路径下创建文件action_lau…

腾讯六宫格本地识别,本地模型识别,腾讯六图识别

基于K哥爬虫昨天发的文章,特此训练了一版腾讯模型,效果不错,特此感谢K哥的指导,效果如下图: 有需求,有疑问的欢迎评论区点出

尚硅谷大数据Flink1.17实战教程-笔记04【Flink DataStream API】

尚硅谷大数据技术-教程-学习路线-笔记汇总表【课程资料下载】视频地址:尚硅谷大数据Flink1.17实战教程从入门到精通_哔哩哔哩_bilibili 尚硅谷大数据Flink1.17实战教程-笔记01【Flink 概述、Flink 快速上手】尚硅谷大数据Flink1.17实战教程-笔记02【Flink 部署】尚硅…

【Spring篇】初识之Spring的入门程序及控制反转与依赖注入

🧸安清h:个人主页 🎥个人专栏:【计算机网络】,【Mybatis篇】 🚦作者简介:一个有趣爱睡觉的intp,期待和更多人分享自己所学知识的真诚大学生。 文章目录 🎯初始Spring …

【K8S系列】Kubernetes pod节点NotReady问题及解决方案详解【已解决】

Kubernetes 集群中的每个节点都是运行容器化应用的基础。当节点状态显示为 NotReady 时,意味着该节点无法正常工作,这可能会导致 Pod 无法调度,从而影响整个应用的可用性。本文将深入分析节点不健康的各种原因、详细的排查步骤以及有效的解决…

查看SQL执行计划 explain

查看SQL执行计划 explain explain使用方式 alter session set current_schematest; explain plan for sql语句; --并不会实际执行,因此生成的执行计划也是预估的 select * from table(dbms_xplan.display); explain使用场景 1.内存中没有谓词信息了&#xff0…

MySQL从入门到跑路

SQL语言 SQL(Structured Query Language,结构化查询语言)是用于管理和操作关系数据库的一种标准编程语言。 SQL分类: DDL(Data Definition Language):数据定义语言,用于操作数据库、表、字段&#xff0c…

前端文件流导出

1、前端代码 ​ /** 导出 */ const handleExport async () > {let config {responseType: blob,headers: {Content-Type: application/json,},};const res await getTargetExport(config);const blob new Blob([res]);const fileName PK目标跟进导出列表.xls;const li…

SpringBoot整合Freemarker(一)

Freemarker和jsp一样是一个视图的引擎模板,其实所有的模板引擎的工作原理都是类似的,如下图: 接下来就具体讲解一下Freemarker的用法,参考手册:模板 数据模型 输出 - FreeMarker 中文官方参考手册 SpringBoot默认就…

【浏览器】如何正确使用Microsoft Edge

1、清理主页广告 如今的Microsoft Edge 浏览器 主页太乱了,各种广告推送,点右上角⚙️设置,把快速链接、网站导航、信息提要、背景等全部关闭。这样你就能得到一个超级清爽的主页。 网站导航       关闭 …

HarmonyOS NEXT和认证(在校生的大福利)

今天重点关注了一下HarmonyOS NEXT,也就是我们所说的纯血鸿蒙! 根据官方的说法: 欢迎开发者进入HarmonyOS NEXT。暌违一年,HarmonyOS NEXT终于在万千开发者的期待下从幕后走向台前。 HarmonyOS NEXT采用全新升级的系统架构&#…

【Python】NumPy(一):数据类型、创建数组及基本操作

目录 ​NumPy初识 1.什么是NumPy? NumPy的应用 NumPy数据类型 Python基本数据类型 NumPy数据类型 NumPy数组 创建数组 1.使用numpy.array() 2.使用arange()方法创建 3.使用linspace()创建等差数列 4使用zeros()创建数组 5.使用ones()创建数组 6.利用…