Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >跟踪算法(一)光流法跟踪

跟踪算法(一)光流法跟踪

作者头像
全栈程序员站长
发布于 2022-09-15 06:57:17
发布于 2022-09-15 06:57:17
1.2K0
举报

大家好,又见面了,我是你们的朋友全栈君。

COPY FROM:http://blog.csdn.net/crzy_sparrow/article/details/7407604

BTW:原文作者是我学习的榜样!

本文目录:

一.基于特征点的目标跟踪的一般方法

二.光流法

三.opencv中的光流法函数

四.用类封装基于光流法的目标跟踪方法

五.完整代码

六.参考文献

一.基于特征点的目标跟踪的一般方法

基于特征点的跟踪算法大致可以分为两个步骤:

1)探测当前帧的特征点;

2)通过当前帧和下一帧灰度比较,估计当前帧特征点在下一帧的位置;

3)过滤位置不变的特征点,余下的点就是目标了。

很显然,基于特征点的目标跟踪算法和1),2)两个步骤有关。特征点可以是Harris角点(见我的另外一篇博文),也可以是边缘点等等,而估计下一帧位置的方法也有不少,比如这里要讲的光流法,也可以是卡尔曼滤波法(咱是控制系的,上课经常遇到这个,所以看光流法看着看着就想到这个了)。

本文中,用改进的Harris角点提取特征点(见我另一篇博文:http://blog.csdn.net/crzy_sparrow/article/details/7391511),用Lucas-Kanade光流法实现目标跟踪。

二.光流法

这一部分《learing opencv》一书的第10章Lucas-Kanade光流部分写得非常详细,推荐大家看书。我这里也粘帖一些选自书中的内容。

另外我对这一部分附上一些个人的看法(谬误之处还望不吝指正):

1.首先是假设条件:

(1)亮度恒定,就是同一点随着时间的变化,其亮度不会发生改变。这是基本光流法的假定(所有光流法变种都必须满足),用于得到光流法基本方程;

(2)小运动,这个也必须满足,就是时间的变化不会引起位置的剧烈变化,这样灰度才能对位置求偏导(换句话说,小运动情况下我们才能用前后帧之间单位位置变化引起的灰度变化去近似灰度对位置的偏导数),这也是光流法不可或缺的假定;

(3)空间一致,一个场景上邻近的点投影到图像上也是邻近点,且邻近点速度一致。这是Lucas-Kanade光流法特有的假定,因为光流法基本方程约束只有一个,而要求x,y方向的速度,有两个未知变量。我们假定特征点邻域内做相似运动,就可以连立n多个方程求取x,y方向的速度(n为特征点邻域总点数,包括该特征点)。

2.方程求解

多个方程求两个未知变量,又是线性方程,很容易就想到用最小二乘法,事实上opencv也是这么做的。其中,最小误差平方和为最优化指标。

3.好吧,前面说到了小运动这个假定,聪明的你肯定很不爽了,目标速度很快那这货不是二掉了。幸运的是多尺度能解决这个问题。首先,对每一帧建立一个高斯金字塔,最大尺度图片在最顶层,原始图片在底层。然后,从顶层开始估计下一帧所在位置,作为下一层的初始位置,沿着金字塔向下搜索,重复估计动作,直到到达金字塔的底层。聪明的你肯定发现了:这样搜索不仅可以解决大运动目标跟踪,也可以一定程度上解决孔径问题(相同大小的窗口能覆盖大尺度图片上尽量多的角点,而这些角点无法在原始图片上被覆盖)。

三.opencv中的光流法函数

opencv2.3.1中已经实现了基于光流法的特征点位置估计函数(当前帧位置已知,前后帧灰度已知),介绍如下(摘自opencv2.3.1参考手册):

[cpp] view plain copy

  1. calcOpticalFlowPyrLK
  2. Calculates an optical flow for a sparse feature set using the iterative Lucas-Kanade method with pyramids.
  3. void calcOpticalFlowPyrLK(InputArray prevImg, InputArray nextImg, InputArray prevPts,
  4. InputOutputArray nextPts, OutputArray status, OutputArray err,
  5. Size winSize=Size(15,15), int maxLevel=3, TermCriteria crite-
  6. ria=TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01),
  7. double derivLambda=0.5, int flags=0 )
  8. Parameters
  9. prevImg – First 8-bit single-channel or 3-channel input image.
  10. nextImg – Second input image of the same size and the same type as prevImg .
  11. prevPts – Vector of 2D points for which the flow needs to be found. The point coordinates
  12. must be single-precision floating-point numbers.
  13. nextPts – Output vector of 2D points (with single-precision floating-point coordinates)
  14. containing the calculated new positions of input features in the second image. When
  15. OPTFLOW_USE_INITIAL_FLOW flag is passed, the vector must have the same size as in the
  16. input.
  17. status – Output status vector. Each element of the vector is set to 1 if the flow for the
  18. corresponding features has been found. Otherwise, it is set to 0.
  19. err – Output vector that contains the difference between patches around the original and
  20. moved points.
  21. winSize – Size of the search window at each pyramid level.
  22. maxLevel – 0-based maximal pyramid level number. If set to 0, pyramids are not used
  23. (single level). If set to 1, two levels are used, and so on.
  24. criteria – Parameter specifying the termination criteria of the iterative search algorithm
  25. (after the specified maximum number of iterations criteria.maxCount or when the search
  26. window moves by less than criteria.epsilon .
  27. derivLambda – Not used.
  28. flags – Operation flags:
  29. – OPTFLOW_USE_INITIAL_FLOW Use initial estimations stored in nextPts . If the
  30. flag is not set, then prevPts is copied to nextPts and is considered as the initial estimate.

四.用类封装基于光流法的目标跟踪方法

废话少说,附上代码,包括特征点提取,跟踪特征点,标记特征点等。

[cpp] view plain copy

  1. <span style=“font-size:18px;”>//帧处理基类
  2. class FrameProcessor{
  3. public:
  4. virtual void process(Mat &input,Mat &ouput)=0;
  5. };
  6. //特征跟踪类,继承自帧处理基类
  7. class FeatureTracker : public FrameProcessor{
  8. Mat gray; //当前灰度图
  9. Mat gray_prev; //之前的灰度图
  10. vector<Point2f> points[2];//前后两帧的特征点
  11. vector<Point2f> initial;//初始特征点
  12. vector<Point2f> features;//检测到的特征
  13. int max_count; //要跟踪特征的最大数目
  14. double qlevel; //特征检测的指标
  15. double minDist;//特征点之间最小容忍距离
  16. vector<uchar> status; //特征点被成功跟踪的标志
  17. vector<float> err; //跟踪时的特征点小区域误差和
  18. public:
  19. FeatureTracker():max_count(500),qlevel(0.01),minDist(10.){}
  20. void process(Mat &frame,Mat &output){
  21. //得到灰度图
  22. cvtColor (frame,gray,CV_BGR2GRAY);
  23. frame.copyTo (output);
  24. //特征点太少了,重新检测特征点
  25. if(addNewPoint()){
  26. detectFeaturePoint ();
  27. //插入检测到的特征点
  28. points[0].insert (points[0].end (),features.begin (),features.end ());
  29. initial.insert (initial.end (),features.begin (),features.end ());
  30. }
  31. //第一帧
  32. if(gray_prev.empty ()){
  33. gray.copyTo (gray_prev);
  34. }
  35. //根据前后两帧灰度图估计前一帧特征点在当前帧的位置
  36. //默认窗口是15*15
  37. calcOpticalFlowPyrLK (
  38. gray_prev,//前一帧灰度图
  39. gray,//当前帧灰度图
  40. points[0],//前一帧特征点位置
  41. points[1],//当前帧特征点位置
  42. status,//特征点被成功跟踪的标志
  43. err);//前一帧特征点点小区域和当前特征点小区域间的差,根据差的大小可删除那些运动变化剧烈的点
  44. int k = 0;
  45. //去除那些未移动的特征点
  46. for(int i=0;i<points[1].size ();i++){
  47. if(acceptTrackedPoint (i)){
  48. initial[k]=initial[i];
  49. points[1][k++] = points[1][i];
  50. }
  51. }
  52. points[1].resize (k);
  53. initial.resize (k);
  54. //标记被跟踪的特征点
  55. handleTrackedPoint (frame,output);
  56. //为下一帧跟踪初始化特征点集和灰度图像
  57. std::swap(points[1],points[0]);
  58. cv::swap(gray_prev,gray);
  59. }
  60. void detectFeaturePoint(){
  61. goodFeaturesToTrack (gray,//输入图片
  62. features,//输出特征点
  63. max_count,//特征点最大数目
  64. qlevel,//质量指标
  65. minDist);//最小容忍距离
  66. }
  67. bool addNewPoint(){
  68. //若特征点数目少于10,则决定添加特征点
  69. return points[0].size ()<=10;
  70. }
  71. //若特征点在前后两帧移动了,则认为该点是目标点,且可被跟踪
  72. bool acceptTrackedPoint(int i){
  73. return status[i]&&
  74. (abs(points[0][i].x-points[1][i].x)+
  75. abs(points[0][i].y-points[1][i].y) >2);
  76. }
  77. //画特征点
  78. void handleTrackedPoint(Mat &frame,Mat &output){
  79. for(int i=0;i<points[i].size ();i++){
  80. //当前特征点到初始位置用直线表示
  81. line(output,initial[i],points[1][i],Scalar::all (0));
  82. //当前位置用圈标出
  83. circle(output,points[1][i],3,Scalar::all(0),(-1));
  84. }
  85. }
  86. };</span>

五.完整代码 完整的运行代码有300+行,粘上来太多了,大家去我传的资源里下载吧。

下载地址:http://download.csdn.net/detail/crzy_sparrow/4183674

运行结果:

六.参考文献

【1】The classic article by B. Lucas and T. Kanade, An iterative image registration technique with an application to stereo vision in Int. Joint Conference in Artificial Intelligence, pp. 674-679,1981, that describes the original feature point tracking algorithm. 【2】The article by J. Shi and C. Tomasi, Good Features to Track in IEEE Conference on Computer Vision and Pattern Recognition, pp. 593-600, 1994, that describes an improved version of the original feature point tracking algorithm.

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/163533.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
VSLAM前端:金字塔光流跟踪算法
 像素点在二维图像中的运动被定义为光流,其在相邻帧图像中存在有位移运动,即存在像素的光流。我们的目的是计算出光流,计算要满足几个前提假设:1.灰度不变性:同一个像素的灰度值在各个图像中是固定不变的;2. 相邻帧之前像素的位移不能太大;3.运动像素周围的像素具有同样的运动规律。
猫叔Rex
2021/04/07
1.8K0
VSLAM前端:金字塔光流跟踪算法
python光流法算法学习「建议收藏」
光流法是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。一般而言,光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。 简单来说,光流是空间运动物体在观测成像平面上的像素运动的“瞬时速度”。光流的研究是利用图像序列中的像素强度数据的时域变化和相关性来确定各自像素位置的“运动”。研究光流场的目的就是为了从图片序列中近似得到不能直接得到的运动场。
全栈程序员站长
2022/09/15
1.7K0
光流法原理概述「建议收藏」
光流的概念是Gibson在1950年首先提出来的。它是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。一般而言,光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。
全栈程序员站长
2022/09/15
3.1K0
DeepFlow高效的光流匹配算法(上)
本周主要介绍一篇基于传统光流法而改进的实现快速的稠密光流算法。该算法已经集成到OpenCV中,算法介绍网址:http://lear.inrialpes.fr/src/deepmatching/
点云PCL博主
2019/09/09
3.7K0
DeepFlow高效的光流匹配算法(上)
CV学习笔记(八):光流法原理
在之前的几篇关于OpenCV的文章中我集中介绍了OpenCV中比较常用的操作和函数.在我们基础的学习中,这些函数其实在图像进行预操作的过程中已经够用了.因此在之后的文章中,我们要继续深入使用OpenCV中的一些函数来去实现几个简单的实例.能够在学习的过程中获得满足感.
云时之间
2020/02/24
1.3K0
如何使用光流法进行目标追踪【文末送书】
如今,“图像分类”、“目标检测”、“语义分割”、“实例分割”和“目标追踪”等5大领域是计算机视觉的热门应用。其中“图像分类”与“目标检测”是最基础的应用,在此基础上,派生出了“语义分割”、“实例分割”和“目标跟踪”等相对高级的应用。
Color Space
2023/09/22
1.2K0
如何使用光流法进行目标追踪【文末送书】
CV学习笔记(九):光流法的实现
在这一篇文章中,我们使用OpenCV中的calcOpticalFlowPyrLK()函数来实现,是基于金字塔LK光流算法,计算某些点集的稀疏光流。
云时之间
2020/02/26
1K0
C++ OpenCV视频操作之KLT稀疏光流对象跟踪(二)
上一篇《C++ OpenCV视频操作之KLT稀疏光流对象跟踪(一)》中我们先试过了在每帧图像中先获取特征点,到了了Shi-Tomas特征提取,这章我们就看看KLT稀疏光流跟踪的方法。
Vaccae
2019/07/25
2.4K0
光流法与直接法视觉里程计
根据使用的图像信息不同,可分为: 稀疏直接法:只处理稀疏角点或关键点 稠密直接法:使用所有像素 半稠密直接法:使用部分梯度明显的像素
小飞侠xp
2019/06/20
1.1K0
光流法测距
(1)亮度恒定,就是同一点随着时间的变化,其亮度不会发生改变。这是基本光流法的假定(所有光流法变种都必须满足),用于得到光流法基本方程;
全栈程序员站长
2022/09/15
6180
OpenCV中的光流及视频特征点追踪
这篇博客将介绍光流的概念以及如何使用 Lucas-Kanade 方法估计光流,并演示如何使用 cv2.calcOpticalFlowPyrLK() 来跟踪视频中的特征点。
玖柒的小窝
2021/10/25
1K0
光流法详解之一(LK光流)
Lucas–Kanade光流算法是一种两帧差分的光流估计算法。它由Bruce D. Lucas 和 Takeo Kanade提出 [1]。
一棹烟波
2019/05/25
5.3K0
【目标跟踪】光流跟踪(python、c++代码)
读书猿
2024/02/05
7060
【目标跟踪】光流跟踪(python、c++代码)
干货 | OpenCV中KLT光流跟踪原理详解与代码演示
在视频移动对象跟踪中,稀疏光流跟踪是一种经典的对象跟踪算法,可以绘制运动对象的跟踪轨迹与运行方向,是一种简单、实时高效的跟踪算法,这个算法最早是有Bruce D. Lucas and Takeo Kanade两位作者提出来的,所以又被称为KLT。KLT算法工作有三个假设前提条件:
OpenCV学堂
2018/11/30
7.5K0
干货 | OpenCV中KLT光流跟踪原理详解与代码演示
目标跟踪与定位——Introduction to motion
要随着时间变化来跟踪物体并检测动作: 方法之一是提取特定的特征 观察这些特征是怎么从一帧变化到下一帧的,这里可以用到光流法(optical flow)。
小飞侠xp
2018/10/12
1.2K0
目标跟踪与定位——Introduction to motion
光流估计综述:从传统方法到深度学习
近年来,深度学习技术,作为一把利剑,广泛地应用于计算机视觉等人工智能领域。如今时常见诸报端的“人工智能时代”,从技术角度看,是“深度学习时代”。
小白学视觉
2020/09/22
3.8K0
光流估计综述:从传统方法到深度学习
光流法学习「建议收藏」
在相邻的两帧图像中,点(x,y)发生了位移(u,v),那么移动前后两点的亮度应该是相等的。如下:
全栈程序员站长
2022/09/06
5110
光流法学习「建议收藏」
SLAM程序阅读(第8讲 LK光流法)
细心的同学已经发现,小绿换了文章的封皮,因为有一些同学都觉得原来那张图比较捞,不沉稳也不正经…而更细心的同学也会发现,小绿连题目都改了,原来叫“解读”,现在叫“阅读”,这也是因为一些热心的同学在后台积极提问,然而小绿作为一个门徒,实在是有些束手无策,没法很透彻的解答同学们的问题…
小白学视觉
2019/10/24
1.4K0
L-K光流推导及OpenCV代码实现
光流简单的来说就是通过摄像头的移动,在移动过程中,每一帧的图像特征点会发生移动,这个移动的过程中(x1,y1,z1)在我们下一帧的动作中,去找到原来的所有特征点的新坐标,而这个移动路径,就是所谓的,光
Pulsar-V
2018/04/18
1.5K0
L-K光流推导及OpenCV代码实现
C++ OpenCV视频操作之CamShift跟踪算法
CamShift算法,全称是 Continuously AdaptiveMeanShift,顾名思义,它是对Mean Shift 算法的改进,能够自动调节搜索窗口大小来适应目标的大小,可以跟踪视频中尺寸变化的目标。它也是一种半自动跟踪算法,需要手动标定跟踪目标。
Vaccae
2019/07/25
2.9K0
相关推荐
VSLAM前端:金字塔光流跟踪算法
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档