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

news2024/11/25 16:26:46

目录

一、光流估计

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*15
                maxLevel=2)   # 金字塔层数为2

3、处理每一帧画面

# 主循环,处理视频的每一帧
while (True):  # 定义一个死循环
    ret,frame = cap.read()   # 上述已经读取了第一帧画面,再次读取会接着第二帧进行读取
    if not ret:  # 检查是否成功读取到
        break
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # 转换为灰度图

    # calcOpticalFlowPyrLK在图像序列中跟踪特征点的运动,计算前一帧old_gray特征点p0在当前帧frame_gray中的新位置p1
    p1,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) & 0xff
    if 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*15
                maxLevel=2)   # 金字塔层数为2

# 主循环,处理视频的每一帧
while (True):  # 定义一个死循环
    ret,frame = cap.read()   # 上述已经读取了第一帧画面,再次读取会接着第二帧进行读取
    if not ret:  # 检查是否成功读取到
        break
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # 转换为灰度图

    # calcOpticalFlowPyrLK在图像序列中跟踪特征点的运动,计算前一帧old_gray特征点p0在当前帧frame_gray中的新位置p1
    p1,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) & 0xff
    if 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.coloradmin.cn/o/2207684.html

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

相关文章

Python | Leetcode Python题解之第474题一和零

题目: 题解: class Solution:def findMaxForm(self, strs: List[str], m: int, n: int) -> int:count10 []for s in strs:count10.append([0,0])for c in s:if c 0: count10[-1][0]1else: count10[-1][1]1dp [[0]*(n1) for _ in range(m1)]for i …

十一、数据库的设计规范

文章目录 1. 为什么需要数据库设计2. 范式2.1 范式介绍2.2 范式都包括哪些2.3 键和相关属性的概念2.4 第一范式(1st NF)2.5 第二范式(2nd NF)2.6 第三范式(3rd NF)2.7 小结3. 反范式化3.1 概述3.2 应用举例3.3 反范式的新问题3.4 反范式的使用场景3.4.1 增加冗余字段的建议3.…

windows系统更新升级node指定版本【避坑篇!!!亲测有效】(附带各版本node下载链接)一定看到最后!不用删旧版!

Node.js 是一个开源、跨平台的 JavaScript 运行时环境,广泛应用于服务器端和网络应用的开发。随着 Node.js 版本的不断更新,我们可能需要升级到特定版本以满足项目需求或修复安全漏洞。又或者是学习开发另外一个新项目,新项目对Node版本要求更…

上交大全华班复现o1旅程式学习下的深思考

因篇幅限制不重复原研究内容,建议访问原技术报告链接精读,这里主要向大伙表示我对上交大本此研究所涉三方面的价值认同及更进一步的延展思考。 价值认同: ① 深刻洞察:系统性研究并阐释旅程式学习; ② 行业促进&…

SQL Injection | MySQL 数据库概述

关注这个漏洞的其他相关笔记:SQL 注入漏洞 - 学习手册-CSDN博客 0x01:MySQL 数据库简介 MySQL 是一个流行的关系型数据库管理系统(RDBMS),它基于 SQL (Structured Query Language)进行操作。My…

Django项目的创建及说明(详细图解版)

Django项目的创建及说明 1、安装Django2、创建项目2.1、利用终端创建项目2.2、利用Pycharm企业版创建项目 3、默认文件介绍 1、安装Django 在终端输入下述命令行。 pip install django安装成功后执行如下命令查看Django是否安装好,若正确显示出Django版本号则安装…

[实时计算flink]应用场景

本文将以部门场景和技术领域场景为例,为您介绍实时计算Flink版的大数据是实时化场景。 背景信息 作为流式计算引擎,Flink可以广泛应用于实时数据处理领域,例如ECS在线服务日志,IoT场景下传感器数据等。同时Flink还能订阅云上数据…

进程的那些事--进程间的通信(重点说明管道和共享内存)

目录 前言 一、初始进程间通信 二、管道 1.匿名管道 2.命名管道 三、共享内存 四、消息队列(了解) 五、信号量(了解) 前言 提示:这里可以添加本文要记录的大概内容: 进程是一个能够独立运行&#…

什么情况下数据库和缓存不一致?

首先,在非并发的场景中,出现不一致的问题大家都能比较容易的理解,因为缓存的操作和数据库的操作是存在一定的时间差的。而生两个操作是没办法保证原子些的,也就是说,是有可能一个操作功,一个操作失败的。所…

C语言-数据结构 折半查找

在折半查找中,刚开始学可能会在下标处产生困惑,例如奇数个长度的数组怎么处理,偶数个长度的数组怎么处理,不需要修改代码吗?并且下标我从1开始算和0开始算影响代码吗?其实都可以用一样的代码,产…

【含文档】基于Springboot+Vue的失物招领系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

如何替换OCP节点(一):使用oat | OceanBase应用实践

前言: OceanBase Cloud Platform(简称OCP),是 OceanBase数据库的专属企业级数据库管理平台。 在实际生产环境中,OCP的安装通常是第一步,先搭建OCP平台,进而依赖OCP来创建、管理和监控我们的生…

docker升级mysql

一、首选备份原数据库所有数据 二、在Docker中查看正在运行的MySQL容器名称,可以使用以下命令: docker ps --filter "namemysql" 三、查看当前docker中正在运行mysql的版本 docker exec -it qgz-mysql mysql -V 可以看到当前运行的版本是8.…

数据传输——差错控制

一、检错纠错 1、通信链路不是完全理想的,在传输的过程中可能会产生比特差错。 2、误码率:传输错误的比特占所传输比特总数的比率。 3、检错:能自动发现差错。 4、纠错:不仅能发现差错而且能自动纠正差错。 5、码字(codeword…

Selenium打开外部应用程序的弹窗处理

问题 selenium自动化操作页面跳转到外部应用程序进行下载等操作,各种窗口处理方式无法解决 原因 该窗口属于浏览器窗口,与访问页面无关(已经脱离页面操作层面) 解决 selenium启动浏览器时,对浏览器进行相关窗口设…

Elasticsearch的安装与配置

注意:elasticsearch 禁止安装在/root路径下! 1、创建用户组 groupadd elastic 2、创建用户 useradd es -d /home/es -g elastic echo es | passwd es --stdin 3、给新创建的用户进行授权 chown -R es:elastic /home/es chmod -R 775 /home/es 4…

sklearn机器学习实战——支持向量机四种核函数分类任务全过程(附完整代码和结果图)

sklearn机器学习实战——支持向量机四种核函数分类任务全过程(附完整代码和结果图) 关于作者 作者:小白熊 作者简介:精通python、matlab、c#语言,擅长机器学习,深度学习,机器视觉,目…

Nginx反向代理配置与负载均衡配置

简介:整理自黑马程序员苍穹外卖的第11节 nginx是什么? nginx的好处 nginx反向代理配置方式 nginx负载均衡的配置方式 nginx负责均衡策略

等保2.0测评 — WebSphere 中间件

查看版本信息: 登录websphere管理平台首页就能看到版本信息 可以进入\usr\IBM\WebSphere\AppServer\bin 下执行./versionInfo.sh查看版本 一、身份鉴别 a)应对登录的用户进行身份标识和鉴别,身份标识具有唯一性,身份鉴别信息具有…

如何使用printf实现整齐美观的输出?

在编程中,尤其是在涉及控制台输出的应用场景中,我们需要让输出的信息更加整齐美观。printf 是 C 语言中用于格式化输出的强大工具之一。通过合理的格式化控制符,我们可以轻松地控制输出的宽度、对齐方式、填充字符等,从而达到整齐…