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

【OpenCV】 中使用 Lucas-Kanade 光流进行对象跟踪和路径映射

文章目录

  • 一、说明
  • 二、什么是Lucas-Kanade 方法
  • 三、Lucas-Kanade 原理
  • 四、代码实现
    • 4.1 第 1 步:用户在第一帧绘制一个矩形
    • 4.2 第 2 步:从图像中提取关键点
    • 4.3 第 3 步:跟踪每一帧的关键点

一、说明

本文针对基于光流法的目标追踪进行叙述,首先介绍Lucas-Kanade 方法的引进,以及基本推导,然后演示如何实现光流法的运动跟踪。并以OpenCV实现一个基本项目。

二、什么是Lucas-Kanade 方法

在计算机视觉领域,Lucas-Kanade 方法是 Bruce D. Lucas 和Takeo Kanade开发的一种广泛使用的光流估计差分方法。该方法假设所考虑像素局部邻域中的光流基本恒定,并根据最小二乘准则求解该邻域中所有像素的基本光流方程。

通过结合来自多个邻近像素的信息,Lucas-Kanade 方法通常可以解决光流方程固有的模糊性。与逐点方法相比,该方法对图像噪声的敏感度也较低。另一方面,由于它是一种纯局部方法,因此无法提供图像均匀区域内部的流信息。

三、Lucas-Kanade 原理

在理论上,初始时间为 t 0 t_0 t0 时刻,经历过 Δ t \Delta t Δt时段后,点p会移动到另一个位置 p ′ p′ p ,并且 p ′ p′ p 本身和周围都有着与p相似的亮度值。朴素的LK光流法是直接用灰度值代替RGB作为亮度。根据上面的描述,对于点p而言,假设p 的坐标值是( x , y ),有
I ( x , y , t ) = I ( x + Δ x , y + Δ y , t + Δ t ) I(x, y, t) = I(x+\Delta x,y+\Delta y, t+\Delta t) I(x,y,t)=I(x+Δx,y+Δy,t+Δt)

根据泰勒公式:在这里把x 、y 看做是t 的函数,把公式(1)看做单变量t 的等式,只需对t进行展开)
I ( x , y , t ) = I ( x , y , t ) + ∂ I ∂ x ∂ x ∂ t + ∂ I ∂ y ∂ y ∂ t + ∂ I ∂ t + o ( Δ t ) I(x,y,t)=I(x,y,t)+\frac{∂I} {∂x}\frac{∂x}{∂t}+\frac{∂I} {∂y}\frac{∂y}{∂t}+\frac{∂I} {∂t}+o(Δt) I(x,y,t)=I(x,y,t)+xItx+yIty+tI+o(Δt)
对于一个像素区域:
I x ( q 1 ) V x + I y ( q 1 ) V x = − I t ( q 1 ) I x ( q 2 ) V x + I y ( q 2 ) V x = − I t ( q 2 ) . . . I x ( q n ) V x + I y ( q n ) V x = − I t ( q n ) I_x(q_1)V_x+I_y(q_1)V_x=-I_t(q_1)\\I_x(q_2)V_x+I_y(q_2)V_x=-I_t(q_2)\\...\\I_x(q_n)V_x+I_y(q_n)V_x=-I_t(q_n) Ix(q1)Vx+Iy(q1)Vx=It(q1)Ix(q2)Vx+Iy(q2)Vx=It(q2)...Ix(qn)Vx+Iy(qn)Vx=It(qn)

在这里: q 1 , q 2 , . . . q n q_1,q_2,...q_n q1,q2,...qn是窗口内点的标号, I x ( q i ) I_x(q_i) Ix(qi), I y ( q i ) I_y(q_i) Iy(qi), I t ( q i ) I_t(q_i) It(qi)是图像的灰度偏导数,
这些方程可以写成矩阵形式:
A v = b Av=b Av=b
在这里插入图片描述
这个系统的方程多于未知数,因此它通常是过度确定的。Lucas-Kanade方法通过最小二乘原理得到折衷解。也就是说,它解决了2×2系统:
在这里插入图片描述

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

四、代码实现

4.1 第 1 步:用户在第一帧绘制一个矩形

# Path to video  
video_path="videos/bicycle1.mp4" 
video = cv2.VideoCapture(video_path)# read only the first frame for drawing a rectangle for the desired object
ret,frame = video.read()# I am giving  big random numbers for x_min and y_min because if you initialize them as zeros whatever coordinate you go minimum will be zero 
x_min,y_min,x_max,y_max=36000,36000,0,0def coordinat_chooser(event,x,y,flags,param):global go , x_min , y_min, x_max , y_max# when you click the right button, it will provide coordinates for variablesif event==cv2.EVENT_RBUTTONDOWN:# if current coordinate of x lower than the x_min it will be new x_min , same rules apply for y_min x_min=min(x,x_min) y_min=min(y,y_min)# if current coordinate of x higher than the x_max it will be new x_max , same rules apply for y_maxx_max=max(x,x_max)y_max=max(y,y_max)# draw rectanglecv2.rectangle(frame,(x_min,y_min),(x_max,y_max),(0,255,0),1)"""if you didn't like your rectangle (maybe if you made some misclicks),  reset the coordinates with the middle button of your mouseif you press the middle button of your mouse coordinates will reset and you can give a new 2-point pair for your rectangle"""if event==cv2.EVENT_MBUTTONDOWN:print("reset coordinate  data")x_min,y_min,x_max,y_max=36000,36000,0,0cv2.namedWindow('coordinate_screen')
# Set mouse handler for the specified window, in this case, "coordinate_screen" window
cv2.setMouseCallback('coordinate_screen',coordinat_chooser)while True:cv2.imshow("coordinate_screen",frame) # show only first frame k = cv2.waitKey(5) & 0xFF # after drawing rectangle press ESC   if k == 27:cv2.destroyAllWindows()breakcv2.destroyAllWindows()

4.2 第 2 步:从图像中提取关键点

# take region of interest ( take inside of rectangle )
roi_image=frame[y_min:y_max,x_min:x_max]# convert roi to grayscale
roi_gray=cv2.cvtColor(roi_image,cv2.COLOR_BGR2GRAY) # Params for corner detection
feature_params = dict(maxCorners=20,  # We want only one featurequalityLevel=0.2,  # Quality threshold minDistance=7,  # Max distance between corners, not important in this case because we only use 1 cornerblockSize=7)first_gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)# Harris Corner detection
points = cv2.goodFeaturesToTrack(first_gray, mask=None, **feature_params)# Filter the detected points to find one within the bounding box
for point in points:x, y = point.ravel()if y_min <= y <= y_max and x_min <= x <= x_max:selected_point = pointbreak# If a point is found, convert it to the correct shape
if selected_point is not None:p0 = np.array([selected_point], dtype=np.float32)plt.imshow(roi_gray,cmap="gray")

将从此图像中提取关键点

4.3 第 3 步:跟踪每一帧的关键点

############################ Parameters ####################################""" 
winSize --> size of the search window at each pyramid level
Smaller windows can more precisely track small, detailed features -->   slow or subtle movements and where fine detail tracking is crucial.
Larger windows is better for larger displacements between frames ,  more robust to noise and small variations in pixel intensity --> require more computations
"""# Parameters for Lucas-Kanade optical flow
lk_params = dict(winSize=(7, 7),  # Window sizemaxLevel=2,  # Number of pyramid levelscriteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))############################ Algorithm ##################################### Read video
cap = cv2.VideoCapture(video_path)# Take first frame and find corners in it
ret, old_frame = cap.read()width = old_frame.shape[1]
height = old_frame.shape[0]# Create a mask image for drawing purposes
mask = np.zeros_like(old_frame)frame_count = 0
start_time = time.time()old_gray = first_graywhile True:ret, frame = cap.read()if not ret:breakframe_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)if p0 is not None:# Calculate optical flowp1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)  good_new = p1[st == 1]  # st==1 means found pointgood_old = p0[st == 1]if len(good_new) > 0:# Calculate movementa, b = good_new[0].ravel()c, d = good_old[0].ravel()# Draw the tracksmask = cv2.line(mask, (int(a), int(b)), (int(c), int(d)), (0, 255, 0), 2)frame = cv2.circle(frame, (int(a), int(b)), 5, (0, 255, 0), -1)img = cv2.add(frame, mask)# Calculate and display FPSelapsed_time = time.time() - start_timefps = frame_count / elapsed_time if elapsed_time > 0 else 0cv2.putText(img, f"FPS: {fps:.2f}", (width - 200, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2, cv2.LINE_AA)cv2.imshow('frame', img)# Update previous frame and pointsold_gray = frame_gray.copy()p0 = good_new.reshape(-1, 1, 2)else:p0 = None# Check if the tracked point is out of frameif not (25 <= a < width):p0 = None  # Reset p0 to None to detect new feature in the next iterationselected_point_distance = 0  # Reset selected point distance when new point is detected# Redetect features if necessaryif p0 is None:p0 = cv2.goodFeaturesToTrack(frame_gray, mask=None, **feature_params)mask = np.zeros_like(frame)selected_point_distance=0frame_count += 1k = cv2.waitKey(25)if k == 27:breakcv2.destroyAllWindows()
cap.release()

结果

相关文章:

【OpenCV】 中使用 Lucas-Kanade 光流进行对象跟踪和路径映射

文章目录 一、说明二、什么是Lucas-Kanade 方法三、Lucas-Kanade 原理四、代码实现4.1 第 1 步&#xff1a;用户在第一帧绘制一个矩形4.2 第 2 步&#xff1a;从图像中提取关键点4.3 第 3 步&#xff1a;跟踪每一帧的关键点 一、说明 本文针对基于光流法的目标追踪进行叙述&am…...

ES 支持乐观锁吗?如何实现的?

本篇主要介绍一下Elasticsearch的并发控制和乐观锁的实现原理&#xff0c;列举常见的电商场景&#xff0c;关系型数据库的并发控制、ES的并发控制实践。 并发场景 不论是关系型数据库的应用&#xff0c;还是使用Elasticsearch做搜索加速的场景&#xff0c;只要有数据更新&…...

前端宝典十一:前端工程化稳定性方案

一、工程化体系介绍 1、什么是前端工程化 前端工程化 前端 软件工程&#xff1b;前端工程化 将工程方法系统化地应用到前端开发中&#xff1b;前端工程化 系统、严谨、可量化的方法开发、运营和维护前端应用程序&#xff1b;前端工程化 基于业务诉求&#xff0c;梳理出最…...

yum 数据源的切换

本来准备安装一个ntp 服务器时间进行同步&#xff0c;但是使用yum install ntp -y 但是却失败了 原因是yum自带的镜像源不能用了&#xff0c;所以要想使用yum 多功能只能切换yum 对应的镜像源了 如果你的服务商是可以使用wget命令的&#xff1a; wget -O /etc/yum.repos.d/Ce…...

MySQL入门学习-命令行工具.mysqlbinlog

MySQL 命令行工具mysqlbinlog用于处理二进制日志文件。 一、关于mysqlbinlog工具的详细介绍&#xff1a; 1、命令行工具mysqlbinlog的特点和使用方法&#xff1a; - 特点&#xff1a; - 可以解析和查看二进制日志文件的内容。 - 支持多种输出格式&#xff0c;如文本、SQ…...

WARNING XXX is not overriding the create method in batch

WARNING XXX is not overriding the create method in batch api.modeldef create(self, vals):quvals[name]youqu self.env[crm.qu].sudo().search([(name, , qu),(shi_id,,vals[shi_id])])if len(youqu)>0:raise UserError(_("该区名已存在&#xff0c;无需再填加…...

使用预训练的 ONNX 格式的目标检测模型(基于 YOLOv8n-pose)姿态监测

具体步骤如下&#xff1a; 加载图像&#xff1a; 从指定路径读取一张图像&#xff08;这里假设图像名为bus.jpg&#xff09;。将图像从 BGR 颜色空间转换为 RGB 颜色空间。 图像预处理&#xff1a; 计算图像的高度、宽度&#xff0c;并确定其中的最大值作为新图像的边长。创建一…...

matlab实现模拟退火算法

模拟退火算法&#xff08;Simulated Annealing, SA&#xff09;是一种通用概率优化算法&#xff0c;用于在给定的大搜索空间内寻找问题的近似全局最优解。该算法灵感来源于物理学中固体物质的退火过程&#xff0c;其中温度逐渐降低&#xff0c;粒子逐渐趋于能量最低状态。 在M…...

【Prettier】代码格式化工具Prettier的使用和配置介绍

前言 前段时间&#xff0c;因为项目的prettier的配置和eslint格式检查有些冲突&#xff0c;在其prettier官网和百度了一些配置相关的资料&#xff0c;在此做一些总结&#xff0c;以备不时之需。 Prettier官网 Prettier Prettier 是一种前端代码格式化工具&#xff0c;支持ja…...

【计算机网络】网络基础

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 如果文章对…...

MFC在对话框中实现打印和打印预览

首先在这里感谢互联网的大哥们&#xff01;同时我讨厌动不动就是要vip才能查看&#xff01;所以我写的不需要vip就能看。只求点个赞。 直接上代码&#xff0c;新建6个文件CPrintFrame.cpp&#xff1b;CPrintFrame.h&#xff1b;CPrintPreviewView.cpp&#xff1b;CPrintPrevie…...

移动端页面出现闪屏

v-cloak 的作用和用法 用法&#xff1a; 这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如 [v-cloak] { display: none } 一起用时&#xff0c;这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。官方API {{msg}} HTML 绑定 Vue实例&#xff0c;在页面加载时…...

elasticsearch的高亮查询三种模式查询及可能存在的问题

目录 高亮查询使用介绍 高亮参数 三种分析器 可能存在的查询问题 fvh查询时出现StringIndexOutOfBoundsException越界 检索高亮不正确 参考文档 高亮查询使用介绍 Elasticsearch 的高亮&#xff08;highlight&#xff09;可以从搜索结果中的一个或多个字段中获取突出显…...

【精品实战项目】深度学习预测、深度强化学习优化、附源码数据手把手教学

目录 前言 一、预测算法数据与代码介绍(torch和mxnet都有) 1.1 数据介绍 1.2 代码介绍 1.3 优化介绍 二、深度强化学习算法优化 2.1 DDPG 介绍 DPG--deterministic policy gradient DQN--deep Q-network DDPG--deep deterministic policy gradient 三、其他算法 总结…...

JavaScript 手写仿深拷贝

实现对象参数的深拷贝并返回拷贝之后的新对象&#xff0c;因为参数对象和参数对象的每个数据项的数据类型范围仅在数组、普通对象&#xff08;{}&#xff09;、基本数据类型中且无需考虑循环引用问题&#xff0c;所以不需要做过多的数据类型判断&#xff0c;核心步骤有&#xf…...

spring低版本设置cookie的samesite属性

场景&#xff1a;比较古老的项目了&#xff0c;ssh架子&#xff0c;Chrome 51 开始&#xff0c;浏览器的 Cookie 新增加了一个SameSite属性&#xff0c;可用于防止 CSRF 攻击和用户追踪。因此需要给其字段赋值。 网上找了很多资源&#xff0c;由于jar版本比较低&#xff0c;没有…...

GPT4o编写步进电机控制代码

我给出的要求如下&#xff1a; 基于STM32F407 HAL库&#xff0c;写一个步进电机控制程序&#xff0c;需要控制8个步进电机&#xff0c;我会给出描述步进电机的结构体变量&#xff0c;基于这些变量需要你做出以下功能&#xff0c;电机脉冲通过定时器中断翻转脉冲引脚的电平实现…...

关于Spring Boot的自动配置

目录 1.EnableAutoConfiguration注解 2.SpringBootConfiguration注解 3.Import注解 4.spring.factories 5.总结 &#xff08;1&#xff09;EnableAutoConfiguration &#xff08;2&#xff09;AutoConfigurationImportSelector &#xff08;3&#xff09; SpringFactoriesLoade…...

## 已解决:`java.sql.SQLSyntaxErrorException: SQL语法错误` 异常的正确解决方法,亲测有效!!! ###

1. 问题描述 java.sql.SQLSyntaxErrorException 是 Java 程序在执行 SQL 查询时&#xff0c;因 SQL 语法错误而抛出的异常。通常情况下&#xff0c;错误信息会指示出错的 SQL 语句及错误原因&#xff0c;如拼写错误、关键字遗漏、字段名称错误等。 典型的错误信息如下&#x…...

备战秋招60天算法挑战,Day22

题目链接&#xff1a; https://leetcode.cn/problems/missing-number/ 视频题解&#xff1a; https://www.bilibili.com/video/BV1HS42197Hc/ LeetCode 268.丢失的数字 题目描述 给定一个包含 [0, n] 中 n 个数的数组 nums &#xff0c;找出 [0, n] 这个范围内没有出现在数组…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

6.9-QT模拟计算器

源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…...