金字塔LK光流法的三个假设

  • 亮度恒定,即图像场景中目标的像素在帧间运动时外观上保持不变;
  • 时间连续或者运动是”小运动“,即图像的运动随时间的变化比较缓慢;
  • 空间一致,即一个场景中同一表面上邻近的点具有相似的运动。

光流法的原理

光流的概念是Gibson在1950年首先提出来的。它是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。

一般而言,光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。当人的眼睛观察运动物体时,物体的景象在人眼的视网膜上形成一系列连续变化的图像,这一系列连续变化的信息不断“流过”视网膜(即图像平面),好像一种光的“流”,故称之为光流(optical flow)。光流表达了图像的变化,由于它包含了目标运动的信息,因此可被观察者用来确定目标的运动情况。 研究光流场的目的就是为了从图片序列中近似得到不能直接得到的运动场。运动场,其实就是物体在三维真实世界中的运动;光流场,是运动场在二维图像平面上(人的眼睛或者摄像头)的投影。

那通俗的讲就是通过一个图片序列,把每张图像中每个像素的运动速度和运动方向找出来就是光流场。第t帧的时候A点的位置是(x1, y1),那么我们在第t+1帧的时候再找到A点,假如它的位置是(x2,y2),那么我们就可以确定A点的运动了:(ux, vy) = (x2, y2) - (x1,y1)。

流程图

如何获取起始的points[0]

光流法预测当前帧的点

源代码

/************************************************************************
* @ Creator:OYXL
* @ Project Creation time:2018/5/31
* @ Function:LK光流法跟踪点
* @    Attention:NO
************************************************************************/
#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;static void help()
{// print a welcome message, and the OpenCV versioncout << "\nThis is a demo of Lukas-Kanade optical flow lkdemo(),\n""Using OpenCV version " << CV_VERSION << endl;cout << "\nIt uses camera by default, but you can provide a path to video as an argument.\n";cout << "\nHot keys: \n""\tESC - quit the program\n""\tr - auto-initialize tracking\n""\tc - delete all the points\n""\tn - switch the \"night\" mode on/off\n""To add/remove a feature point click it\n" << endl;
}Point2f point;
bool addRemovePt = false;static void onMouse( int event, int x, int y, int /*flags*/, void* /*param*/ )
{if( event == CV_EVENT_LBUTTONDOWN ){point = Point2f((float)x, (float)y);addRemovePt = true;}
}int main()
{help();VideoCapture cap(0);TermCriteria termcrit(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 20, 0.03);Size subPixWinSize(10,10), winSize(31,31);const int MAX_COUNT = 500;bool needToInit = false;bool nightMode = false;if( !cap.isOpened() ){cout << "Could not initialize capturing...\n";return 0;}namedWindow( "LK Demo", 1 );setMouseCallback( "LK Demo", onMouse, 0 );Mat gray, prevGray, image, frame;vector<Point2f> points[2];while (true){cap >> frame;if( frame.empty() )break;frame.copyTo(image);cvtColor(image, gray, COLOR_BGR2GRAY);if( nightMode )image = Scalar::all(0);//<按下"r"按键,自动初始化if(needToInit){// automatic initializationgoodFeaturesToTrack(gray, points[1], MAX_COUNT, 0.01, 10, Mat(), 3, 0, 0.04);cornerSubPix(gray, points[1], subPixWinSize, Size(-1,-1), termcrit);addRemovePt = false;}else if(!points[0].empty())//<前一帧的点不能为空{vector<uchar> status;vector<float> err;if(prevGray.empty()){gray.copyTo(prevGray);}calcOpticalFlowPyrLK(prevGray, gray, points[0], points[1], status, err, winSize,3, termcrit, 0, 0.001);int i, k;for( i = k = 0; i < points[1].size(); i++ ){if( addRemovePt )//<鼠标添加点{if( norm(point - points[1][i]) <= 5)//<point到points[1][i]的距离<5之间不能描点{addRemovePt = false;continue;}}//<如果相应特征的流发现则status置为1,否则,为0。if( !status[i] )continue;points[1][k++] = points[1][i];circle( image, points[1][i], 3, Scalar(0,255,0), -1, 8);}points[1].resize(k);}//<添加点if( addRemovePt && points[1].size() < (int)MAX_COUNT ){vector<Point2f> tmp;//<初始化tmp.push_back(point);cornerSubPix( gray, tmp, winSize, cvSize(-1,-1), termcrit);points[1].push_back(tmp[0]);addRemovePt = false;}needToInit = false;imshow("LK Demo", image);char c = (char)waitKey(10);if( c == 27 )break;switch( c ){case 'r':needToInit = true;break;case 'c':points[0].clear();points[1].clear();break;case 'n':nightMode = !nightMode;break;}std::swap(points[1], points[0]);cv::swap(prevGray, gray);}return 0;
}

分析

按下“r”键,自动检测角点,将检测到角点存入points[1]中

// automatic initialization
goodFeaturesToTrack(gray, points[1], MAX_COUNT, 0.01, 10, Mat(), 3, 0, 0.04);
cornerSubPix(gray, points[1], subPixWinSize, Size(-1,-1), termcrit);

鼠标描点,存入points[1]中

static void onMouse( int event, int x, int y, int /*flags*/, void* /*param*/ )
{if( event == CV_EVENT_LBUTTONDOWN ){point = Point2f((float)x, (float)y);addRemovePt = true;}
}

LK光流法预测当前帧的点

calcOpticalFlowPyrLK(prevGray, gray, points[0], points[1], status, err, winSize,3, termcrit, 0, 0.001);

函数原型:

void calcOpticalFlowPyrLK( InputArray prevImg, InputArray nextImg,InputArray prevPts, CV_OUT InputOutputArray nextPts,OutputArray status, OutputArray err,Size winSize=Size(21,21), int maxLevel=3,TermCriteria criteria=TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01),int flags=0, double minEigThreshold=1e-4);

prevImg:深度为8位的前一帧图像或金字塔图像。

nextImg:和prevImg有相同的大小和类型,后一帧图像或金字塔。

prevPts:计算光流所需要的输入2D点矢量,点坐标必须是单精度浮点数(前一帧的点集)。

nextPts:输出2D点矢量(也是单精度浮点数坐标),点矢量中包含的是在后一帧图像上计算得到的输入特征新位置(预测当前帧的点)。

status:输出状态矢量(元素是无符号char类型,uchar),如果相应特征的流发现则矢量元素置为1,否则,为0。

err:输出误差矢量。

winSize:每个金字塔层搜索窗大小。

maxLevel:金字塔层的最大数目;如果置0,金字塔不使用(单层);如果置1,金字塔2层,等等以此类推。

criteria:指定搜索算法收敛迭代的类型,默认criteria=TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01)。

flags:默认为0

minEigThreshold:算法计算的光流等式的2x2常规矩阵的最小特征值。

注意

if( norm(point - points[1][i]) <= 5)//<point到points[1][i]的距离<5之间不能描点

这句话表达的意思是,鼠标新画的点与点points[1][i]之间的距离不能小于5个像素,否则画的点将不会显示在当前帧上,有兴趣的话可以将这个值改大一点,再试试。

norm(point - points[1][i])这句话可以翻译成sqrt((point.x-points[1][i].x)^2+(point.y-points[1][i].y)^2),sqrt是开根函数。

效果图

如果将前一帧的也画出来,然后将前后两帧的点用线段连接起来,看起来效果会更明显一点。

如果想要了解算法公式,推荐博客:

https://blog.csdn.net/zouxy09/article/details/8683859

https://blog.csdn.net/u014568921/article/details/46638557

https://blog.csdn.net/ap1005834/article/details/51226660

OpenCV:金字塔LK光流法相关推荐

  1. OpenCV Using Python——基于SURF特征提取和金字塔LK光流法的单目视觉三维重建 (光流、场景流)...

    https://blog.csdn.net/shadow_guo/article/details/44312691 基于SURF特征提取和金字塔LK光流法的单目视觉三维重建 1. 单目视觉三维重建问题 ...

  2. 图像金字塔LK光流法原理分析

    图像金字塔LK光流法原理分析 1.LK光流法原理分析 2.基于图像金字塔的LK光流法原理分析 本篇博客只讲述原理,c++代码实现请参考博客< 基于金字塔LK的光流法实现-根据论文自己实现的c++ ...

  3. 【老生谈算法】matlab实现金字塔LK光流法源码——金字塔LK光流法

    基于金字塔LK光流法的MATLAB代码 1.原文下载: 本算法原文如下,有需要的朋友可以点击进行下载 序号 原文(点击下载) 本项目原文 [老生谈算法]基于金字塔LK光流法的MATLAB代码.docx ...

  4. 金字塔LK光流法数学原理学习笔记

    参考: 1.总结:光流--LK光流--基于金字塔分层的LK光流--中值流 https://blog.csdn.net/sgfmby1994/article/details/68489944 2.< ...

  5. OpenCV3学习(11.2)LK光流法原理及opencv实现

    光流的概念:(Optical flow or optic flow) 它是一种运动模式,这种运动模式指的是一个物体.表面.边缘在一个视角下由一个观察者(比如眼睛.摄像头等)和背景之间形成的明显移动.光 ...

  6. 详解LK光流法(含金字塔多层光流),反向光流法(附代码)

    LK光流法可用来跟踪特征点的位置. 比如在img1中的特征点,由于相机或物体的运动,在img2中来到了不同的位置.后面会称img1为Template(T),img2为I. 光流法有个假设: 灰度不变假 ...

  7. LK光流法与反向LK光流法

    文章目录 一.基本概念 二.2D中的LK光流法 1.空间点在图像中的灰度表示 2.2D中的LK光流法推导 3.将2D光流法抽象成超定方程问题 4.超定线性方程的最小二乘最优解定理证明 5.将2D光流法 ...

  8. 视觉SLAM前端——LK光流法

    目录: LK光流介绍 单层LK光流 多层LK光流 LK光流   LK光流是一种描述图像运动的方法,利用LK光流可以实现对图像的追踪,从而求解图像运动的位姿.其基本思想如下:   img1,img2分别 ...

  9. [LK光流法,disflow using Dense Inverse Search, VariationalRefinement变分优化 原理和代码]

    文章目录 1.Fast Optical Flow using Dense Inverse Search 1.1 W的含义: 1.2 LK光流模型 1.3 LK光流模型求解(不含迭代) 1.4 LK光流 ...

最新文章

  1. 从实习被劝退,到收获阿里腾讯的offer,谈谈读研给我带来的转变
  2. keras module 'tensorflow' has no attribute 'placeholder'
  3. 测试女生周期的软件名字,什么软件可以提醒生理期?适合女生可用的便签软件...
  4. 一文读懂云原生一体化数仓
  5. 程序在发布前就应该发现的一些错误
  6. 今日恐慌与贪婪指数为31 恐慌程度有所上升
  7. 吴恩达《机器学习》第八章:逻辑回归
  8. 在职工象棋赛上弃子拿下一盘
  9. SQL Server维护计划–好处,功能和特性
  10. jquery 逗号分割截取字符串_经典面试题:分割回文串
  11. 【论文解读】一种新的涨分神器!构造code-switching增广数据进行fine-tuning!
  12. 参数利用SpringMVC构建REST接口:第七篇 控制层实现
  13. ubuntu16.04利用SVN下载文件
  14. 公专网集群对讲系统在城市执法过程中的应用
  15. 我的 2020 年终总结
  16. Maxima绘图基础
  17. Referenced file contains errors (xml文件第一行小红叉错误)
  18. 【Eclipse下载与安装教程】
  19. java如何生成api文档_api文档自动生成工具
  20. jupyterLab 如何修改字体大小

热门文章

  1. stm32 串口输出 中文乱码
  2. 深入理解Linux管道实现
  3. BZOJ 1070 修车-神奇网络流
  4. 关于考级和古筝学习--略谈之,有感而发啊
  5. Ambassador系列-02-Module模块
  6. DataX 简介及架构原理
  7. 织梦编辑器加HTML视频显示很小,dede织梦编辑器中插入视频文件方法
  8. [书摘]老外侃中国(埃瑞克【挪威】口述,郭莹撰稿)
  9. OC5864 0.6A 60V 内置MOS管 小体积高恒压精度的 DC-DC降压型转换器
  10. 对当下工作现状不满 想辞职但又不敢 选择python解放自己