使用Opencv中均值漂移meanShift跟踪移动目标

2024-01-25 15:38

本文主要是介绍使用Opencv中均值漂移meanShift跟踪移动目标,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Mean Shift均值漂移算法是无参密度估计理论的一种,无参密度估计不需要事先知道对象的任何先验知识,完全依靠训练数据进行估计,并且可以用于任意形状的密度估计,在某一连续点处的密度函数值可由该点邻域中的若干样本点估计得出。

Mean shift将特征空间视为先验概率密度函数,那么输入就被视为是一组满足某种概率分布的样本点,这样一来,特征空间中数据最密集的地方,对应于概率密度最大的地方,且概率密度的质心就可以被视为是概率密度函数的局部最优值,也就是要求的聚类中心。对于每一个样本点,计算以它为中心的某个范围内所有样本点的均值,作为新的中心(这就是shift既中心的移动),移动直至收敛。这样每一轮迭代,中心都会向数据更密集的地方移动,直到最后稳定收敛到样本的“质心”

可以直观理解为:在样本空间中,任选一个点,然后以这个点为圆心,划定一个圆形的区域。在此区域内的所有点以圆心为起点,产生N个向量,然后把这些向量都相加,再以向量的终点为圆心,划定同样半径的圆形区域,执行同样操作,如此迭代,直到收敛。

 

均值漂移的“漂移”过程如下:

 

 

先把圆心移动到当前圆区域内的“质心”上:

 

 

再以质心为圆心的圆区域内寻找当前圆的质心,并移动到新的“质心”上:

 

如此迭代移动,直到最后满足了迭代条件,质心稳定在质量最密处:

 

Opencv中均值漂移算法由meanShift函数实现:

 

 

 
  1. int meanShift( InputArray probImage, CV_OUT CV_IN_OUT Rect& window,

  2. TermCriteria criteria );

 

 

第一个参数probImage,是直方图的反向投影矩阵;

 

第二个参数window,初始化的搜索窗口,同时也是输出的目标窗口;

第三个参数criteria,终止迭代条件,可以设置为满足一定迭代次数后终止,也可以设置为目标和初始搜索位置之间差落在某一区间终止,也可以设置为两者的组合;

meanShift函数返回int型变量,代表算法迭代的次数

 

以下程序实现了在一个视频中跟踪移动目标,大致步骤如下:

 

  • 1. 在视频播放过程中,通过鼠标框选需要跟踪的目标target
  • 2. 计算目标图像target的HSV中H、S分量的直方图targetHist
  • 3. 用targetHist反向投影计算原图像中的目标的概率分布
  • 4. 用meanShift通过迭代获取目标的新的位置window
  • 5. 以新的位置window执行步骤2

 

 
  1. #include "core/core.hpp"

  2. #include "highgui/highgui.hpp"

  3. #include "imgproc/imgproc.hpp"

  4. #include "video/tracking.hpp"

  5. #include<iostream>

  6.  
  7. using namespace cv;

  8. using namespace std;

  9.  
  10. Mat image;

  11. Mat rectImage;

  12. Mat imageCopy; //绘制矩形框时用来拷贝原图的图像

  13. bool leftButtonDownFlag=false; //左键单击后视频暂停播放的标志位

  14. Point originalPoint; //矩形框起点

  15. Point processPoint; //矩形框终点

  16.  
  17. Mat targetImageHSV;

  18. int histSize=200;

  19. float histR[]={0,255};

  20. const float *histRange=histR;

  21. int channels[]={0,1};

  22. Mat dstHist;

  23. Rect rect;

  24. vector<Point> pt; //保存目标轨迹

  25. void onMouse(int event,int x,int y,int flags ,void* ustc); //鼠标回调函数

  26.  
  27. int main(int argc,char*argv[])

  28. {

  29. VideoCapture video(argv[1]);

  30. double fps=video.get(CV_CAP_PROP_FPS); //获取视频帧率

  31. double pauseTime=1000/fps; //两幅画面中间间隔

  32. namedWindow("跟踪木头人",0);

  33. setMouseCallback("跟踪木头人",onMouse);

  34. while(true)

  35. {

  36. if(!leftButtonDownFlag) //判定鼠标左键没有按下,采取播放视频,否则暂停

  37. {

  38. video>>image;

  39. }

  40. if(!image.data||waitKey(pauseTime)==27) //图像为空或Esc键按下退出播放

  41. {

  42. break;

  43. }

  44. if(originalPoint!=processPoint&&!leftButtonDownFlag)

  45. {

  46. Mat imageHSV;

  47. Mat calcBackImage;

  48. cvtColor(image,imageHSV,CV_RGB2HSV);

  49. calcBackProject(&imageHSV,2,channels,dstHist,calcBackImage,&histRange); //反向投影

  50. TermCriteria criteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000, 0.001);

  51. meanShift(calcBackImage, rect, criteria);

  52. Mat imageROI=imageHSV(rect); //更新模板

  53. targetImageHSV=imageHSV(rect);

  54. calcHist(&imageROI, 2, channels, Mat(), dstHist, 1, &histSize, &histRange);

  55. normalize(dstHist, dstHist, 0.0, 1.0, NORM_MINMAX); //归一化

  56. rectangle(image, rect, Scalar(255, 0, 0),3); //目标绘制

  57. pt.push_back(Point(rect.x+rect.width/2,rect.y+rect.height/2));

  58. for(int i=0;i<pt.size()-1;i++)

  59. {

  60. line(image,pt[i],pt[i+1],Scalar(0,255,0),2.5);

  61. }

  62. }

  63. imshow("跟踪木头人",image);

  64. waitKey(100);

  65. }

  66. return 0;

  67. }

  68.  
  69. //*******************************************************************//

  70. //鼠标回调函数

  71. void onMouse(int event,int x,int y,int flags,void *ustc)

  72. {

  73. if(event==CV_EVENT_LBUTTONDOWN)

  74. {

  75. leftButtonDownFlag=true; //标志位

  76. originalPoint=Point(x,y); //设置左键按下点的矩形起点

  77. processPoint=originalPoint;

  78. }

  79. if(event==CV_EVENT_MOUSEMOVE&&leftButtonDownFlag)

  80. {

  81. imageCopy=image.clone();

  82. processPoint=Point(x,y);

  83. if(originalPoint!=processPoint)

  84. {

  85. //在复制的图像上绘制矩形

  86. rectangle(imageCopy,originalPoint,processPoint,Scalar(255,0,0),2);

  87. }

  88. imshow("跟踪木头人",imageCopy);

  89. }

  90. if(event==CV_EVENT_LBUTTONUP)

  91. {

  92. leftButtonDownFlag=false;

  93. rect=Rect(originalPoint,processPoint);

  94. rectImage=image(rect); //子图像显示

  95. imshow("Sub Image",rectImage);

  96. cvtColor(rectImage,targetImageHSV,CV_RGB2HSV);

  97. imshow("targetImageHSV",targetImageHSV);

  98. calcHist(&targetImageHSV,2,channels,Mat(),dstHist,1,&histSize,&histRange,true,false);

  99. normalize(dstHist,dstHist,0,255,CV_MINMAX);

  100. imshow("dstHist",dstHist);

  101. }

  102. }


 

跟踪结果1:

 

2:

 

3:

 

4:

 

 

蓝色方框是跟踪的目标,绿色线条是目标中心走过的轨迹。

这篇关于使用Opencv中均值漂移meanShift跟踪移动目标的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/643729

相关文章

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

MySQL中EXISTS与IN用法使用与对比分析

《MySQL中EXISTS与IN用法使用与对比分析》在MySQL中,EXISTS和IN都用于子查询中根据另一个查询的结果来过滤主查询的记录,本文将基于工作原理、效率和应用场景进行全面对比... 目录一、基本用法详解1. IN 运算符2. EXISTS 运算符二、EXISTS 与 IN 的选择策略三、性能对比

使用Python构建智能BAT文件生成器的完美解决方案

《使用Python构建智能BAT文件生成器的完美解决方案》这篇文章主要为大家详细介绍了如何使用wxPython构建一个智能的BAT文件生成器,它不仅能够为Python脚本生成启动脚本,还提供了完整的文... 目录引言运行效果图项目背景与需求分析核心需求技术选型核心功能实现1. 数据库设计2. 界面布局设计3

SQL Server跟踪自动统计信息更新实战指南

《SQLServer跟踪自动统计信息更新实战指南》本文详解SQLServer自动统计信息更新的跟踪方法,推荐使用扩展事件实时捕获更新操作及详细信息,同时结合系统视图快速检查统计信息状态,重点强调修... 目录SQL Server 如何跟踪自动统计信息更新:深入解析与实战指南 核心跟踪方法1️⃣ 利用系统目录

使用IDEA部署Docker应用指南分享

《使用IDEA部署Docker应用指南分享》本文介绍了使用IDEA部署Docker应用的四步流程:创建Dockerfile、配置IDEADocker连接、设置运行调试环境、构建运行镜像,并强调需准备本... 目录一、创建 dockerfile 配置文件二、配置 IDEA 的 Docker 连接三、配置 Do

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.

python使用try函数详解

《python使用try函数详解》Pythontry语句用于异常处理,支持捕获特定/多种异常、else/final子句确保资源释放,结合with语句自动清理,可自定义异常及嵌套结构,灵活应对错误场景... 目录try 函数的基本语法捕获特定异常捕获多个异常使用 else 子句使用 finally 子句捕获所

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali