《opencv实用探索·二十》点追踪技术

news2024/12/22 19:18:30

前言:
在学习点追踪技术前需要先了解下光流发追踪目标,可以看上一章内容:光流法检测运动目标

如果以光流的方式追踪目标,基本上我们可以通过goodFeaturesToTrack函数计算一系列特征点,然后通过Lucas-Kanade算法进行一系列特征点的预测,并画出这些预测点的运动轨迹。点的追踪技术就是在这种方式基础上把goodFeaturesToTrack计算的一系列特征点换成一个我们选中的点进行追踪。

点追踪基本流程:
(1)采集一帧图像,用鼠标在图像上选择一个特征点,并使用cornerSubPix对特征点进行精细化调整
(2)循环采集下一帧图像,利用Lucas-Kanade光流法估计上一帧的特征点在下一帧中的位置
(3)保存估计的特征点在图像上进行追踪显示

需要用到的几个重要的函数:
cornerSubPix 是 OpenCV 中用于提高角点检测精度的函数之一。它用于在角点检测后对检测到的角点位置进行亚像素级别的精细化调整。

在角点检测过程中,通常使用诸如 goodFeaturesToTrack 等函数检测图像中的角点。这些函数可以找到可能是角点的位置,但它们的精度可能会受到像素级别的限制。cornerSubPix 的作用就是对这些检测到的角点位置进行进一步的精细化调整,使得角点的位置更加精确。

void cornerSubPix(InputArray image, InputOutputArray corners, Size winSize, Size zeroZone, TermCriteria criteria);

image:输入的灰度图像,用于角点精细化的操作。
corners:输入/输出参数,是一个 vector 或 Mat,包含需要精细化的角点的坐标。经过 cornerSubPix 处理后,这个数组中的角点坐标会被更新为更准确的位置。
winSize:搜索窗口的大小。这个参数定义了算法用于寻找角点的搜索范围。
zeroZone:定义了搜索区域的一些特殊的约束条件。
criteria:定义了终止条件,通常包括迭代的最大次数、精度等。
cornerSubPix 的工作原理是基于像素灰度值的梯度,它通过迭代优化来细化角点位置。这种亚像素级别的精细化可以提高角点检测的准确性,特别是在计算光流等计算中,有时候需要非常精确的角点位置信息。

对于cornerSubPix和calcOpticalFlowPyrLK,如果使用搜索窗口winSize怎么设置比较好?
winSize 参数的合适值取决于你正在处理的图像以及需要进行光流估计或特征跟踪的具体应用场景。这个值影响着光流算法或特征跟踪的准确性、计算效率和对运动变化的敏感度。
一般来说,winSize 的大小应该与你希望跟踪的特征尺度相匹配。以下是一些参考建议:
特征尺度大小:
对于小尺度的特征(如角点),选择一个相对较小的窗口大小可能更合适。这样可以更好地捕捉和跟踪这些特征的运动。
对于大尺度的特征(如纹理区域或物体),可能需要一个更大的窗口来更好地描述它们的运动。
运动速度和变化范围:
如果你处理的场景中物体的运动速度较快或者变化范围较大,可能需要一个更大的窗口来保证算法能够正确地捕捉到这些运动。
计算资源和实时性:
较大的窗口可能需要更多的计算资源,因此在资源受限或需要实时处理的情况下,可能需要权衡窗口大小和计算效率之间的关系。
一般情况下,使用较小的窗口大小可能对光流估计和特征跟踪有利,因为它们更灵敏,但也更容易受到图像噪声和局部变化的影响。同时,过小的窗口也可能限制了算法对大尺度运动的捕捉能力。
如果没有特定的规则来选择 winSize,可以通过实验和调整来找到最适合你的场景的值。通常,初始选择一个合理的默认值,然后通过观察跟踪结果和实际效果来进行调整。这个调整过程可能需要根据应用的具体情况进行多次迭代

calcOpticalFlowPyrLK函数已在上一章介绍过,这里不再赘述。

代码示例:


#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <iostream>
#include <ctype.h>

using namespace cv;
using namespace std;


Point2f point;
bool addRemovePt = false;

//--------------------------------【onMouse( )回调函数】------------------------------------
//		描述:鼠标操作回调
//-------------------------------------------------------------------------------------------------
static void onMouse(int event, int x, int y, int /*flags*/, void* /*param*/)
{
	if (event == EVENT_LBUTTONDOWN)
	{
		point = Point2f((float)x, (float)y);
		addRemovePt = true;
	}
}

//-----------------------------------【main( )函数】--------------------------------------------
//		描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main(int argc, char** argv)
{

	VideoCapture cap;

	TermCriteria termcrit(TermCriteria::MAX_ITER | TermCriteria::EPS, 20, 0.03);
	Size winSize(31, 31);

	const int MAX_COUNT = 500;

	cap.open(0);

	if (!cap.isOpened())
	{
		cout << "Could not initialize capturing...\n";
		return 0;
	}

	namedWindow("LK Demo", 1);
	setMouseCallback("LK Demo", onMouse, 0);

	Mat image;
	Mat grayNow, grayPre;
	vector<Point2f> pointsPre;
	vector<Point2f> pointsNow;

	for (;;)
	{
		//采集下一帧图像
		Mat frame;
		cap >> frame;
		if (frame.empty())
			break;
		frame.copyTo(image);
		cvtColor(image, grayNow, COLOR_BGR2GRAY);

		if (!pointsPre.empty())
		{
			vector<uchar> status;
			vector<float> err;
			//Lucas-Kanade光流法运动估计(根据上一帧中选择的点进行估计,pointsNow存放的是估计下一帧grayNow图像中的特征点)
			//搜索窗口大小为 winSize(31, 31)
			//termcrit为迭代终止条件
			calcOpticalFlowPyrLK(grayPre, grayNow, pointsPre, pointsNow, status, err, winSize,
				3, termcrit, 0, 0.001);
			size_t i, k;
			for (i = k = 0; i < pointsNow.size(); i++)
			{
				//去除不好的预测点
				if (!status[i])
					continue;

				pointsNow[k++] = pointsNow[i];  //把好的特征点重新保存到pointsNow容器中
				circle(image, pointsNow[i], 3, Scalar(0, 255, 0), -1, 8);  //在图像上显示鼠标选的特征点
			}
			pointsNow.resize(k);  //修改容器长度为最新数据的长度
		}

		//每次鼠标在下一帧图像上选择一个点,先对选择点进行精细化调整在保存
		if (addRemovePt && pointsNow.size() < (size_t)MAX_COUNT)
		{
			//获取鼠标点击坐标
			vector<Point2f> tmp;
			tmp.push_back(point);
			//对下一帧图像中选择的点进行精细化调整
			cornerSubPix(grayNow, tmp, winSize, Size(-1, -1), termcrit);
			//保存精细化调整后的选择点
			pointsNow.push_back(tmp[0]);
			addRemovePt = false;
		}

		imshow("LK Demo", image);

		char c = (char)waitKey(10);

		//采集下一帧图像之前,把当前帧数据保存到上一帧容器中
		pointsPre = pointsNow;
		grayPre = grayNow.clone();
	}

	return 0;
}

效果显示:
在这里插入图片描述

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

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

相关文章

Java智慧工地源码,智慧工地管理平台的技术架构和工作原理

智慧工地管理平台是将互联网的理念和技术引入建筑工地&#xff0c;从施工现场源头抓起&#xff0c;最大程度的收集人员、安全、环境、材料等关键业务数据&#xff0c;依托物联网、互联网&#xff0c;建立云端大数据管理平台&#xff0c;形成“端云大数据”的业务体系和新的管理…

考虑使用自定义的序列化形式

在Java中&#xff0c;有时候我们可能需要考虑使用自定义的序列化形式&#xff0c;以满足特定的需求或优化序列化过程。这通常涉及到实现Serializable接口的类&#xff0c;并自定义writeObject和readObject方法。以下是一个简单的例子&#xff0c;演示了如何使用自定义的序列化形…

货物数据处理pandas版

1求和 from openpyxl import load_workbook import pandas as pddef print_hi(name):# Use a breakpoint in the code line below to debug your script.print(fHi, {name}) # Press CtrlF8 to toggle the breakpoint.# Press the green button in the gutter to run the scr…

vue中2种取值的方式

1.url是这种方式的&#xff1a;http://localhost:3000/user/1 取得参数的方式为&#xff1a;this.$route.params.id 2.url为get方式用&#xff1f;拼接参数的&#xff1a;http://localhost:3000/user?phone131121123&companyId2ahttp://localhost:3000/ 取得参数值的方式…

HTTP代理神器Fiddler的配置

HTTP代理神器Fiddler Fiddler的简介 Fiddler是位于客户端和服务器端之间的代理&#xff0c;也是目前最常用的抓包工具之一 。它能够记录客户端和服务器之间的所有 请求&#xff0c;可以针对特定的请求&#xff0c;分析请求数据、设置断点、调试web应用、修改请求的数据&#…

不是生活有意思,是你热爱生活它才有意思

明制汉服的设计 同样是一款很重工的外套 细节上也是做到了极致 顺毛毛呢面料 领口袖口拼接仿貂毛环保毛条 前胸欧根纱刺绣圆形布 袖子贴民族风珠片刺绣织带 门襟搭配金属子母扣&#xff0c;真盘扣设计 时尚经典&#xff0c;搭配马面裙孩子穿上 真的很有气质奢华富贵 …

Android hwcomposer服务启动流程

Android hwcomposer服务启动流程 客户端 binder远程调用 服务端 surfaceflinger --binder--> hwcomposer .hal文件编译时生成支持binder进程间远程调用通信的cpp文件 在out/soong/.intermediates/hardware/interfaces/graphics/composer/2.1/ 目录下找…

时序预测 | Python实现GRU电力需求预测

时序预测 | Python实现GRU电力需求预测 目录 时序预测 | Python实现GRU电力需求预测预测效果基本描述程序设计参考资料预测效果 基本描述 该数据集因其每小时的用电量数据以及 TSO 对消耗和定价的相应预测而值得注意,从而可以将预期预测与当前最先进的行业预测进行比较。使用该…

【如何提取React项目中的公共模块,多个项目共用】

文章目录 目录 前言 一、创建公共模块 二、初始化公共模块 三、给公共模块添加内容 四、添加对公共模块的依赖 五、使用公共模块里的资源 后记 前言 在工作中经常会遇到这样的需求&#xff0c;有个React项目&#xff0c;代码分为客户端&#xff0c;管理端两份&#xff…

04 python函数

4.1 函数的快速开发体验 """ 演示&#xff0c;快速体验函数的开发和使用 """#需求&#xff0c;统计字符串的长度&#xff0c;不使用内置函数len()str1 itheima str2 itcast str3 python#定义一个计数的变量 count 0 for i in str1:count 1…

【高级网络程序设计】Block1总结

这一个Block分为四个部分&#xff0c;第一部分是Introduction to Threads and Concurrency &#xff0c;第二部分是Interruptting and Terminating a Thread&#xff0c;第三部分是Keep Threads safety&#xff1a;the volatile variable and locks&#xff0c;第四部分是Beyon…

RabbitMQ不公平分发问题分析及问题解决

1.不公平分发 1.1 不公平分发策略是什么&#xff1f; 在 RabbitMQ 中&#xff0c;不公平分发&#xff08;Unfair Dispatch&#xff09;是指当多个消费者&#xff08;Consumers&#xff09;同时订阅同一个队列&#xff08;Queue&#xff09;时&#xff0c;消息的分发机制是不公…

把文化注入品牌,五粮液荣获“全国企业文化优秀成果特等奖”

执笔 | 萧 萧 编辑 | 扬 灵 12月15日&#xff0c;以“塑造优秀企业文化&#xff0c;凝聚企业发展力量”为主题的全国企业文化年会(2023&#xff09;首次在长江首城、中国酒都、中国动力电池之都宜宾盛大举行。 凭借“弘扬和美文化&#xff0c;谱写高质量发展新篇章”成果…

2018年AMC8数学竞赛真题的典型考点和详细解析

从战争中学习战争最有效。前几天&#xff0c;六分成长分析了2023年、2022年、2020、2019年的AMC8的典型考题、考点和详细答案解析。今天继续为大家分享2018年的AMC8的五道典型考题。 欢迎您查看历史文章了解之前各年的真题解析&#xff0c;本系列会持续更新&#xff0c;直到大家…

Linux:进程地址空间

目录 1.程序地址空间 2.进程地址空间 1.程序地址空间 我们在讲C/C语言的时候&#xff0c;32位平台下&#xff0c;我们见过这样的空间布局图 我们来验证一下这张图的正确性&#xff1a; int un_gval;int init_gval100;int main(int argc, char* argv[],char* env[]){//代码…

Nat. Mach. Intell. | 通过深度神经网络联合建模多个切片来构建一个三维全生物体空间图谱

今天为大家介绍的是来自Angela Ruohao Wu 和Can Yang团队的一篇论文。空间转录组学&#xff08;ST&#xff09;技术正在革新探索组织空间结构的方式。目前&#xff0c;ST数据分析通常局限于单个二维&#xff08;2D&#xff09;组织切片&#xff0c;这限制了我们理解在三维&…

【ArkTS】入门

代码结构分析 struct Index{ } 「自定义组件&#xff1a;可复用的UI单元」 xxx 「装饰器&#xff1a;用来装饰类结构、方法、变量」 Entry 标记当前组件是入口组件&#xff08;该组件可被独立访问&#xff0c;通俗来讲&#xff1a;它自己就是一个页面&#xff09;Component 用…

【后端学前端】第四天 css动画 垂直轮播效果(css变量、位移缩放动画、动画延迟)

1、学习信息 视频地址&#xff1a;css动画 垂直轮播效果&#xff08;css变量、位移缩放动画、动画延迟&#xff09;_哔哩哔哩_bilibili 2、源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title…

QT for Android安卓编译环境搭建+首次编译3个大坑

1、安装 编译环境能否搭建成功&#xff0c;主要是看各个依赖软件的版本是否匹配。依赖的软件有3个&#xff1a;JDK、安卓SDK、安卓NDK。 我的qt版本是5.14.1&#xff0c;我亲测以下版本可以成功让编译安卓&#xff1a; QT5.14 JDK1.8.0 安卓SDK26.1 安卓NDK20.1 在QT-&g…

爬虫 scrapy ——scrapy shell调试及下载当当网数据(十一)

目录 一、scrapy shell 1.什么是scrapy shell&#xff1f; 2.安装 ipython 3.使用scrapy shell 二、当当网案例 1.在items.py中定义数据结构 2.在dang.py中解析数据 3.使用pipeline保存 4.多条管道的使用 5.多页下载 参考 一、scrapy shell 1.什么是scrapy shell&am…