【光流法实现目标追踪:Python实战指南】

news2024/11/26 3:57:06

文章目录

    • 概要
    • 一、目标追踪概述
    • 二、光流法进行目标追踪
    • 小结

概要

在当今计算机视觉领域,图像处理被广泛应用于多个关键领域,包括图像分类、目标检测、语义分割、实例分割和目标追踪。其中,图像分类和目标检测作为基础应用为其他高级领域奠定了基础。在这个基础上,衍生出了更为复杂的任务,如语义分割、实例分割和目标追踪。

语义分割和实例分割是图像处理中的两项重要任务,它们致力于将图像中的每个像素点准确分类,从而实现图像前景和背景的清晰分离。与此同时,目标追踪则扩展了这一概念,专注于在图像序列或视频中跟踪目标的运动轨迹,准确定位目标在连续图像帧中的位置,为视频分析和实时监控等应用提供了重要支持。

一、目标追踪概述

在计算机视觉领域,视频是一种非常重要的数据形式,它由一系列有序的图像帧组成。这些图像帧按照一定的逻辑顺序组成视频的不同层次,包括帧(Frame)、镜头(Shot)、场景(Scene)和视频(Video)。

  1. 帧(Frame): 帧是视频的基本单元,实际上就是一幅图像。在视频中,每一帧呈现了一个瞬间的静态画面。其中,关键帧(Key Frame)是具有代表性的帧,通常用来代表整个视频内容。

  2. 镜头(Shot): 镜头由一系列相邻的帧组成,这些帧捕捉了同一个事件或者摄像机的一组连续运动。镜头可以看作是一段连续的视频片段。

  3. 场景(Scene): 场景由一系列相似的镜头组成,这些镜头在内容上有一定的语义关联,通常表达了同一批对象或者环境。场景划分通常依赖于图像内容的相似性和场景的转换。

  4. 视频(Video): 视频是所有层次的顶层结构,由一系列有序的镜头和场景组成,呈现了一个完整的动态场景或者事件。

在实际应用中,我们常常需要将视频转换为图像序列,或者将图像序列合成为视频。这种转换在很多图像处理和计算机视觉任务中是必不可少的。Python中的OpenCV库提供了便捷的接口,使得视频和图像序列之间的转换变得非常容易。

视频转图像序列:
首先,我们使用OpenCV的VideoCapture模块将视频文件读取为一系列的图像帧。每一帧都是一个独立的图像,我们可以将其保存为图像文件。这种转换能够方便地将视频数据处理为单独的图像,以便进行进一步的处理和分析。

import cv2
import os

videoFile = './video/ball.mp4'  # 输入的视频文件
imgPath = "./video/frame/"      # 输出的图像文件路径
cap = cv2.VideoCapture(videoFile)
frame_id = 0
while True:
    ret, frame = cap.read()  # 读取视频的帧
    if not ret:              # 视频结束
        break
    cv2.imwrite("%s/%04d.jpg" % (imgPath, frame_id), frame)
    frame_id = frame_id + 1
print("转换结束:(视频文件:%s,图像序列路径:%s)" % (videoFile, imgPath))

图像序列转视频:
另一方面,如果我们有一系列的图像帧,我们可以使用OpenCV的VideoWriter模块将这些图像帧合成为视频。在这个过程中,我们需要设置视频的帧率、尺寸等参数,以及指定输出视频文件的格式。

import os
import cv2

imgPath = "./video/frame/"  # 输入的图像文件路径
videoFile = './video/video.mp4'  # 输出的视频文件
fps = 25.0  # 速率,每秒25帧

# 找到目录下所有的图像文件,并按照文件名排序
files = [f for f in os.listdir(imgPath) if os.path.isfile(os.path.join(imgPath, f)) and f.endswith('.jpg')]
files.sort()

# 获取图像文件的尺寸
img = cv2.imread(os.path.join(imgPath, files[0]))
height, width, channels = img.shape

# 创建视频对象,使用mpg4格式压缩
fourcc = cv2.VideoWriter_fourcc(*'mp4v')  # 使用mp4v编码
video = cv2.VideoWriter(videoFile, fourcc, fps, (width, height))

# 将图像序列写入视频文件
for file_name in files:
    img = cv2.imread(os.path.join(imgPath, file_name))
    video.write(img)

# 释放视频对象
video.release()

print("转换结束:(图像序列路径:%s, 视频文件:%s)" % (imgPath, videoFile))

  1. 目标追踪的分类

目标追踪根据实时性要求和应用场景可以分为不同类型:
(1)在线追踪 vs. 离线追踪

在线追踪:通过过去和现在的视频帧确定目标的位置,适用于对实时性要求较高的场景。
离线追踪:通过过去、现在和未来的视频帧确定目标的位置,准确性通常高于在线追踪,但对实时性要求较低。

(2)单目标追踪 vs. 多目标追踪 vs. 多目标多摄像头追踪 vs. 姿态追踪

单目标追踪:追踪单个固定目标在视频帧中的位置。
多目标追踪:同时追踪多个目标在视频帧中的位置。
多目标多摄像头追踪:追踪多个摄像头拍摄到的多个目标,在不同的视频帧中的位置。
姿态追踪:追踪目标在视频帧中的姿态变化,例如人体的不同姿势。
  1. 生成式模型 vs. 鉴别式模型
    生成式模型

生成式模型首先定义目标的特征,然后在后续视频帧中寻找具有相似特征的位置,从而定位目标。早期的目标追踪方法如光流法属于生成式模型,但由于特征定义简单,面对光照变化、遮挡、分辨率低、角度变化等情况时效果不佳。
鉴别式模型

鉴别式模型通过比较视频帧中目标和背景的差异,将目标从视频帧中提取出来,实现目标定位。这类模型综合考虑了目标和背景信息,在准确性和实时性方面通常优于生成式模型。传统的机器学习模型(如SVM、随机森林、GBDT)逐渐被引入,同时基于深度学习的目标追踪方法也逐渐兴起。
4. 目标追踪的方法

目标追踪方法可以根据时间顺序分为“经典方法”、“基于滤波方法”和“基于深度学习方法”。

(1)经典方法
经典的目标追踪方法首先对目标的外观进行建模,例如特征点、轮廓、SIFT等特征,然后在视频帧中查找目标出现的位置。通常使用预测算法,对可能出现的区域进行预测,仅在这些区域内查找目标,以提高效率。

(2)基于滤波方法
这种方法通过度量视频帧中目标的相似程度,将不同视频帧中的目标进行关联,实现追踪。例如,MOSSE算法使用相关滤波器(Correlation Filter),计算目标之间的相关值,根据相关值找到不同视频帧中相同的目标并建立关联,实现目标追踪。

(3)基于深度学习方法
基于深度学习的目标追踪方法将深度学习模型引入目标追踪中。例如,基于目标检测的追踪方法(Tracking By Detecting,简称TBD)使用深度学习模型在每个视频帧上执行目标检测,并在检测到的目标之间建立关联,实现目标追踪。

二、光流法进行目标追踪

光流(Optical Flow)是一种用来描述运动物体在图像中像素级别运动的方法。当一个物体在三维空间中移动时,它在图像上的投影位置也会随之变化。光流就是描述这种投影位置变化的二维矢量。

具体地说,当我们观察两个相邻的图像帧时,每个像素点在这两帧之间会发生位移。这个位移可以被表示为一个二维向量,其中的两个分量(x 和 y)分别表示了像素在图像平面上的水平和垂直位移。这个二维向量即为光流矢量。

光流矢量的计算基于一个假设:在相邻的图像帧之间,相邻像素的灰度不会发生剧烈变化。基于这个假设,光流算法通过分析像素点在两帧之间的灰度变化,估计出每个像素点的运动矢量。这种方法可以用来追踪图像中的目标,分析视频中的运动模式,或者用于图像稠密匹配等应用。

总结而言,光流是通过比较相邻图像帧之间像素灰度的变化来估计像素点运动的方法,用二维矢量表示像素点在图像平面上的瞬时速度。

在这里插入图片描述
光流法的原理基于两个关键假设条件:

  1. 亮度不变性假设:

这个假设表明,同一个目标在不同的视频帧之间运动时,其亮度(像素值)不会发生显著的变化。换句话说,目标在相邻帧之间的灰度值保持不变。
2. 时间连续性假设:

这个假设指的是,时间的变化不会引起目标位置的剧烈变化。也就是说,相邻帧之间的目标位移是连续的,而不是突然发生的大幅度变化。

在这两个假设的基础上,光流法通过计算相邻帧之间像素点的位移,得到光流场,其中包含了目标的运动信息。这个位移信息可以用来分析和追踪目标的运动轨迹。

具体来说,对于某个像素点在时刻 tt 的坐标为 (xt,yt)(xt​,yt​),像素值为 ItIt​,在时刻 t+1t+1 的坐标为 (xt+1,yt+1)(xt+1​,yt+1​),像素值为 It+1It+1​。光流法计算出的位移向量 (u,v)(u,v) 表示了该像素点在水平方向(uu)和垂直方向(vv)上的位移。

光流法的目标是找到适当的位移向量 (u,v)(u,v) 使得下面的方程成立:

It(xt,yt)=It+1(xt+1,yt+1)It​(xt​,yt​)=It+1​(xt+1​,yt+1​)

这个方程表示了亮度不变性假设。通过求解这个方程,光流法能够估计目标在相邻帧之间的位移,从而实现目标的追踪。光流法的结果通常是一个矢量场,其中包含了图像中各个像素点的运动信息。

Lucas-Kanade(LK)光流算法是一种用于估计图像中物体运动的经典方法。在LK算法中,我们希望找到一个光流矢量 (u,v)(u,v),表示图像中每个像素点在水平和垂直方向上的位移。光流矢量的计算是基于以下假设的:

  1. 亮度不变性假设:

这个假设表明,在相邻的图像帧之间,同一个像素点的灰度值保持不变。也就是说,如果在第一帧图像中某个像素的灰度值为 I(x,y)I(x,y),在下一帧图像中相同位置的像素的灰度值仍然是 I(x+u,y+v)I(x+u,y+v)。其中 (u,v)(u,v) 是我们要估计的光流矢量。
2. 时间连续性假设:

这个假设指的是,在一个短时间内,目标的运动是连续的,相邻帧之间的位移是平滑的。即,目标在相邻帧之间的位移是有限的,不会突然发生剧烈变化。
3. 空间一致性假设:

LK算法引入了“空间一致性”假设,这意味着在目标像素周围的一个小窗口内,所有像素点都有相同的光流矢量。该窗口的大小通常选择为3x3,这样就有9个像素点。

对于这9个像素点,可以建立如下的9个方程:

Ix⋅ui+Iy⋅vi=−ItIx​⋅ui​+Iy​⋅vi​=−It​

其中 IxIx​ 和 IyIy​ 分别表示在 xx 和 yy 方向上的梯度,uiui​ 和 vivi​ 表示第 ii 个像素点的光流矢量分量,ItIt​ 是两帧图像之间的灰度差。

LK算法的目标是通过最小二乘法,找到一个最优的光流矢量 (u,v)(u,v),使得上述9个方程的误差最小化。通过解这个最小二乘问题,可以得到光流矢量 (u,v)(u,v),从而实现目标的运动估计。这种方法对于小的位移和较好的纹理区域通常具有良好的效果。
在这里插入图片描述

这段代码演示了如何使用OpenCV中的calcOpticalFlowPyrLK()函数实现稀疏光流的计算,以及如何将两帧图像的特征点进行关联,从而显示图像中的运动信息。
步骤解释:

  1. 导入库:
import cv2
import numpy as np
from matplotlib import pyplot as plt
  1. 读取图像并转换为灰度图:
img_0 = cv2.imread("./images/da_feng_che_0.jpg")
img_1 = cv2.imread("./images/da_feng_che_1.jpg")
img_0 = cv2.cvtColor(img_0, cv2.COLOR_BGR2RGB)
img_1 = cv2.cvtColor(img_1, cv2.COLOR_BGR2RGB)
gray_0 = cv2.cvtColor(img_0.copy(), cv2.COLOR_RGB2GRAY)
gray_1 = cv2.cvtColor(img_1.copy(), cv2.COLOR_RGB2GRAY)
mask = img_0 + img_1  # mask用来显示最后的结果
  1. 生成特征点:
params = {"maxCorners": 10, "qualityLevel": 0.01, "minDistance": 50, "blockSize": 1}
key_points_0 = cv2.goodFeaturesToTrack(gray_0, mask=None, **params)
  1. 计算稀疏光流并关联特征点:
key_points_1, match, _ = cv2.calcOpticalFlowPyrLK(gray_0, gray_1, key_points_0, None)
matched_0 = key_points_0[match == 1]  # 第一帧图像上的特征点
matched_1 = key_points_1[match == 1]  # 第二帧图像上的特征点
  1. 显示运动信息:
for i, (frame_0, frame_1) in enumerate(zip(matched_0, matched_1)):
    a, b = frame_0.ravel()
    c, d = frame_1.ravel()
    mask = cv2.circle(mask, (a, b), 3, (255, 0, 0), -1)  # 用红色标记,第一帧图上的特征点
    mask = cv2.circle(mask, (c, d), 3, (0, 0, 255), -1)  # 用蓝色标记,第二帧图上的特征点
    mask = cv2.line(mask, (a, b), (c, d), (255, 255, 255), 2)  # 用白色标记,两帧图像上特征点的对应关系

f, ax = plt.subplots(1, 3, figsize=(12, 12))
ax[0].imshow(img_0)
ax[1].imshow(img_1)
ax[2].imshow(mask)

在这段代码中,我们首先导入所需的库。然后,我们读取两帧图像,并将它们转换为灰度图像。接着,使用cv2.goodFeaturesToTrack()函数生成第一帧图像的特征点。随后,我们使用cv2.calcOpticalFlowPyrLK()函数计算稀疏光流,并将第一帧和第二帧图像的特征点进行关联。最后,我们将特征点和它们的对应关系可视化在两帧图像上,用红色和蓝色标记特征点,并用白色线条连接两帧图像上对应的特征点。

小结

步骤展示了如何使用OpenCV实现稀疏光流的计算,并可视化特征点的运动信息。这种方法通常适用于追踪图像中的关键特征点,例如角点,以分析物体的运动轨迹。

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

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

相关文章

MPLS基础

1. MPLS原理与配置 MPLS基础 (1)MPLS概念 MPLS位于TCP/IP协议栈中的数据链路层和网络层之间,可以向所有网络层提供服务。 通过在数据链路层和网络层之间增加额外的MPLS头部,基于MPLS头部实现数据快速转发。 本课程仅介绍MPLS在…

天软特色因子看板 (2023.10 第05期)

该因子看板跟踪天软特色因子A05005(近一月单笔流涌金额占比(%),该因子为近一个月单笔流通金额占比因,用以刻画股票在收盘时,力资金在总交易金额中所占的比重。。 今日为该因子跟踪第05期,跟踪其在SW801030 (申万化工) 中的表现&am…

危险化工品出口注意事项及法规要求_箱讯科技

随着全球化工品市场的不断发展,危险化工品出口业务逐渐成为国际贸易的重要组成部分。然而,由于危险化工品具有潜在的危险性,出口过程中需严格遵守相关法规和注意事项,以确保运输安全和顺畅。本文将详细介绍危险化工品出口注意事项…

面试算法26:重排链表

问题 给定一个链表,链表中节点的顺序是L0→L1→L2→…→Ln-1→Ln,请问如何重排链表使节点的顺序变成L0→Ln→L1→Ln-1→L2→Ln-2→…? 分析 首先把链表分成前后两半。在示例链表中,前半段链表包含1、2、3这3个节点&#xff0c…

路径规划-learning

参考视频:【全】无人驾驶系列知识入门到提高 本文旨在对视频内容规划控制方面做一些学习记录,希望帮助有需要的人学习提高。不对处,望指正。 文章概要: 1 什么是规划 规划的本质、如何解决规划问题 2 传统的规划方法 机器人学基础…

基于Java的列车票务信息管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding) 代码参考数据库参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

C++入门之引用与内联函数

一、引用 1、初步理解 引用在语法上的理解就是起别名,用法就是在类型后面加&,例子:int a 1; int& b a; 上例所示,执行后,b就是a的别名,它们代表同一块空间,a的改变会影响b&#xff0…

MySQL 迁移完不能快速导数据了?

关于 5.6 升级到 5.7 之后,GTID 的相关功能的注意事项。 作者:秦福朗,爱可生 DBA 团队成员,负责项目日常问题处理及公司平台问题排查。热爱互联网,会摄影、懂厨艺,不会厨艺的 DBA 不是好司机,di…

一文学会使用WebRTC API

WebRTC(Web Real-Time Communication)是一项开放标准和技术集合,由 W3C 和 IETF 等组织共同推动和维护,旨在通过Web浏览器实现实时通信和媒体流传输。WebRTC于2011年6月1日开源并在Google、Mozilla、Opera支持下被纳入万维网联盟的…

【分享】教你加速访问GitHub,进来学!

哈喽,大家好,木易巷来啦! 众所周知,Github是一款程序猿必备的代码托管平台,上面已经存在了无数前辈的心血!经常需要在上面查看大佬写的一些好用的开源项目,无赖国外网站的速度实在让人难以接受。…

【linux】重定向+缓冲区

重定向缓冲区 1.重定向1.1重定向本质1.2重定向接口1.3重定向分类1.3.1>输出重定向1.3.2>>追加重定向1.3.3<输入重定向 2.理解 >&#xff0c; >>&#xff0c; <3.如何理解linux下一切皆文件4.缓冲区4.1理解缓冲区问题4.1.1为什么要有缓冲区4.1.2缓冲区刷…

php获取10年内的年份并加入下拉列表

要实现的效果 在html中内嵌php循环将数组中的年份加入下拉列表 <div class="form-group"><label>年份:</label><div class="input-group"><div class="input-group-prepend"><span class="input-group-te…

7天狂揽 1.3w star 的 MetaGPT,他们的目标让软件公司为之一惊

在 AI 产品爆炸的今天&#xff0c;拥有各种本领的 AI 产品层出不穷&#xff0c;但 MetaGPT 的出现仍然显的格外耀眼&#xff0c;其可以实现只输入单一 prompt&#xff0c;就可以输出需求分析、需求文档、技术架构、最终代码等等产物&#xff0c;这相当于一个开发团队的输出成果…

012 Spring Boot + Vue 电影购票系统

部分代码地址&#xff1a; https://github.com/XinChennn/xc012-movie Spring Boot Vue 电影购票系统 一、项目结构 网上购票后台管理客服模块 二、环境介绍 后端&#xff1a;SpringBoot SpringSecurity MyBatis-Plus前端&#xff1a;Vue ElementUi数据库&#xff1a;…

mongodb如何多表查询,如同时查询店铺以及里面对应的商品

多表查询场景介绍 一种很常见的场景&#xff0c;比如电商首页中&#xff0c;需要同时展示最近比较火热的店铺&#xff0c;以及直接展示店铺里对应的商品。或者用户下单之后购物车里可以看到所选的商品以及对应的店铺。如果不知道如何用mongodb自带的查询语句快速查询的话&#…

有限差分法

目录 1.原理介绍 1.1 有限差分法介绍 1.2 有限差分法步骤 2.案例分析 2.1 问题重述 2.2 问题求解 1.原理介绍 1.1 有限差分法介绍 有限差分法是一种常用的数值计算方法&#xff0c;用于求解偏微分方程或常微分方程的数值解。它的基本思想是将连续的空间区域离散化为有限…

mac电脑安装雷蛇管理软件,实现调整鼠标dpi,移动速度,灯光等

雷蛇官网只给了win版本驱动 mac版本驱动到这里下载: GitHub - 1kc/razer-macos: Color effects manager for Razer devices for macOS. Supports High Sierra (10.13) to Monterey (12.0). Made by the community, based on openrazer. 安装后会显示开发者不明,请丢弃到垃圾桶.…

Java:SpringBoot整合Spring Batch示例

目录 文档基础概念Tasklet方式示例Chunk方式示例参考文章 文档 https://docs.spring.io/spring-batch/docs/4.3.9/reference/html/index.html 基础概念 JobLauncher&#xff1a;作业启动器&#xff0c;启动作业的入口。对应的实现类为SimpleJobLauncher。Job&#xff1a;作业…

PLC通过Modbus转Profinet网关连接变频器控制电机配置案例

在本案例中&#xff0c;通过使用Modbus转Profinet网关&#xff08;XD-MDPN100&#xff09;&#xff0c;PLC可以通过Profinet协议与变频器进行通信和控制。这样&#xff0c;PLC可以实现对电机的转速调节、启停控制等功能。 同时&#xff0c;通过Modbus转Profinet&#xff08;XD-…

你还在为协同办公烦恼吗?试试视频协同办公吧!

在这个信息化、数字化的时代&#xff0c;协同办公已经成为了企业、团队的必备工具。然而&#xff0c;尽管传统的协同办公工具有诸多优点&#xff0c;但在实际使用中&#xff0c;仍会遇到各种各样的问题。你是否还在为这些问题而烦恼&#xff1f;别担心&#xff0c;让我们一起探…