光流(optical flow)和openCV中实现

光流(optical flow)和openCV中实现

光流的概念:

       是Gibson在1950年首先提出来的。它是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。一般而言,光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。

当人的眼睛观察运动物体时,物体的景象在人眼的视网膜上形成一系列连续变化的图像,这一系列连续变化的信息不断“流过”视网膜(即图像平面),好像一种光 的“流”,故称之为光流(optical flow)。光流表达了图像的变化,由于它包含了目标运动的信息,因此可被观察者用来确定目标的运动情况。

看下面的图,它展示了一个小球在5个连续的帧中的运动,箭头上的数字代表不同的帧,那个红色小球的运动构成了光流。

操作:

给你一个图上的一系列点,在另外一张图上找到与前面一些列点相同的点。

或者给你图I1上的点[ux, uy]T,找到I2上的点[ux + δx, uy + δy]T,最小化ε:

上面加入Wx表示一块区域,一般跟踪一个区域的点。

在图形学应用中,在多张图上跟踪点(特征)是一项基本的操作:在一张图上找到一个对象,观察对象如何移动。

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

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

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

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

特征点可以是Harris角点,也可以是边缘点等等。

考虑一个像素在第一帧的光强度(这里增加了一个维度时间,前面的时候我们只是处理图像,所以没有必要时间。现在需要增加这个维度)。它移动了 的距离到一下帧,用了时间。因为像素点是一样的,光强度也没有发生变化(其实这个光强度没有改变是很多光流算法的基本假设)。,所以我们可以说:

然后通过泰勒级数近似展开有:

所以:

上面的等式叫做光流等式,偏导数可以求出来,可是 u和v是未知的,所以无法解决上的等式。但是有很多方法可以解决这个问题,其中一个叫做Lucas-Kanade方法。

Lucas-Kanade:

有这么一个假定,所有的相邻像素有相似的行动,Lucas-Kanade方法使用3*3的一块区域,它假定这9个点有相同的行动,所以现在的问题变为有9个等式,2个未知量,这个问题当然能够解决。一个好的解决方式是使用最小二乘法。

令n=9,于是便有了9个等式:

其中q1,q2,…,代表像素点,  是偏导,上面的等式可以写成下面的形式:A
v = b,其中:

然后,得到下面的:

最终算出来的两个未知数的解是:

上面的解决小而连贯的运动,想想刚刚我们的假设是9个像素点速度一致。因为现实中大而连贯的运动是普遍存在的,我们需要大的窗口来捕获运动,可是大窗口违
背了运动连贯的假设,图像金字塔可以解决这个问题。(图像金字塔的内容以后本人掌握更多的再补充,现在不敢乱发表)。

OpenCV中的实现:

OpenCV提供了对上面介绍的方法的支持,函数名叫做:cv2.calcOpticalFlowPyrLK(),现在让我们在视频中跟踪一些点。为了决定跟踪哪些点,使用cv2.goodFeaturesToTrack()。

我们得到第一帧,探测Shi-Tomasi角点,然后我们使用 Lucas-Kanade光流法来跟综这些点。

[cpp] view plaincopy

    1. #include "opencv2/video/tracking.hpp"
    2. #include "opencv2/imgproc/imgproc.hpp"
    3. #include "opencv2/highgui/highgui.hpp"
    4. #include <iostream>
    5. #include <ctype.h>
    6. using namespace cv;
    7. using namespace std;
    8. static void help()
    9. {
    10. // print a welcome message, and the OpenCV version
    11. cout << "\nThis is ademo of Lukas-Kanade optical flow lkdemo(),\n"
    12. "Using OpenCVversion "<< CV_VERSION << endl;
    13. cout << "\nIt usescamera by default, but you can provide a path to video as an argument.\n";
    14. cout << "\nHot keys:\n"
    15. "\tESC - quitthe program\n"
    16. "\tr -auto-initialize tracking\n"
    17. "\tc - deleteall the points\n"
    18. "\tn - switch the\"night\" mode on/off\n"
    19. "To add/removea feature point click it\n" << endl;
    20. }
    21. Point2f point;
    22. bool addRemovePt = false;
    23. static void onMouse(int event, int x, int y, int /*flags*/, void* /*param*/)
    24. {
    25. if (event == CV_EVENT_LBUTTONDOWN)
    26. {
    27. point = Point2f((float)x, (float)y);
    28. addRemovePt = true;
    29. }
    30. }
    31. int main(int argc, char** argv)
    32. {
    33. help();
    34. VideoCapture cap;
    35. TermCriteria termcrit(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03);
    36. Size subPixWinSize(10, 10), winSize(31, 31);
    37. const int MAX_COUNT = 500;
    38. bool needToInit = false;
    39. bool nightMode = false;
    40. /*if (argc == 1 || (argc == 2 && strlen(argv[1])== 1 && isdigit(argv[1][0])))
    41. cap.open(argc == 2 ? argv[1][0] - ‘0‘ :0);
    42. else if (argc == 2)
    43. cap.open(argv[1]);*/
    44. cap.open("G:\\视频分析入门练习\\视频分析入门练习 - 附件\\sample.avi");
    45. if (!cap.isOpened())
    46. {
    47. cout << "Could notinitialize capturing...\n";
    48. return 0;
    49. }
    50. namedWindow("LK", 1);
    51. setMouseCallback("LK", onMouse, 0);
    52. Mat gray, prevGray, image;
    53. vector<Point2f> points[2];
    54. for (;;)
    55. {
    56. Mat frame;
    57. cap >> frame;
    58. if (frame.empty())
    59. break;
    60. frame.copyTo(image);
    61. cvtColor(image, gray, COLOR_BGR2GRAY);
    62. if (nightMode)
    63. image = Scalar::all(0);
    64. if (needToInit)
    65. {
    66. // automaticinitialization
    67. goodFeaturesToTrack(gray, points[1],100, 0.01, 10, Mat(), 3, 0, 0.04);
    68. cornerSubPix(gray, points[1],subPixWinSize, Size(-1, -1), termcrit);
    69. addRemovePt = false;
    70. }
    71. else if(!points[0].empty())
    72. {
    73. vector<uchar> status;
    74. vector<float> err;
    75. if (prevGray.empty())
    76. gray.copyTo(prevGray);
    77. calcOpticalFlowPyrLK(prevGray, gray,points[0], points[1], status, err, winSize,
    78. 3, termcrit, 0, 0.001);
    79. size_t i, k;
    80. for (i = k = 0; i <points[1].size(); i++)
    81. {
    82. if (addRemovePt)
    83. {
    84. if (norm(point -points[1][i]) <= 5)
    85. {
    86. addRemovePt = false;
    87. continue;
    88. }
    89. }
    90. if (!status[i])
    91. continue;
    92. points[1][k++] = points[1][i];
    93. circle(image, points[1][i], 3, Scalar(0, 255, 0), -1, 8);
    94. }
    95. points[1].resize(k);
    96. }
    97. if (addRemovePt&& points[1].size() < (size_t)MAX_COUNT)
    98. {
    99. vector<Point2f> tmp;
    100. tmp.push_back(point);
    101. cornerSubPix(gray, tmp, winSize,cvSize(-1, -1), termcrit);
    102. points[1].push_back(tmp[0]);
    103. addRemovePt = false;
    104. }
    105. needToInit = false;
    106. imshow("LK", image);
    107. char c = (char)waitKey(100);
    108. if (c == 27)
    109. break;
    110. switch (c)
    111. {
    112. case ‘r‘:
    113. needToInit = true;
    114. break;
    115. case ‘c‘:
    116. points[0].clear();
    117. points[1].clear();
    118. break;
    119. case ‘n‘:
    120. nightMode = !nightMode;
    121. break;
    122. }
    123. std::swap(points[1], points[0]);
    124. cv::swap(prevGray, gray);
    125. }
    126. return 0;
    127. }

光流(optical flow)和openCV中实现

时间: 2024-08-11 03:38:28

光流(optical flow)和openCV中实现的相关文章

光流Optical Flow介绍与OpenCV实现

光流(optic flow)是什么呢?名字很专业,感觉很陌生,但本质上,我们是最熟悉不过的了.因为这种视觉现象我们每天都在经历.从本质上说,光流就是你在这个运动着的世界里感觉到的明显的视觉运动(呵呵,相对论,没有绝对的静止,也没有绝对的运动).例如,当你坐在火车上,然后往窗外看.你可以看到树.地面.建筑等等,他们都在往后退.这个运动就是光流.而且,我们都会发现,他们的运动速度居然不一样?这就给我们提供了一个挺有意思的信息:通过不同目标的运动速度判断它们与我们的距离.一些比较远的目标,例如云.山,

[OpenCV-Python] OpenCV 中视频分析 部分 VI

部分 VI视频分析 39 Meanshift 和 和 Camshift 目标 ? 本节我们要学习使用 Meanshift 和 Camshift 算法在视频中找到并跟踪目标对象39.1 Meanshift Meanshift 算法的基本原理是和很简单的.假设我们有一堆点(比如直方图反向投影得到的点),和一个小的圆形窗口,我们要完成的任务就是将这个窗口移动到最大灰度密度处(或者是点最多的地方).如下图所示: 初始窗口是蓝色的"C1",它的圆心为蓝色方框"C1_o",而窗

【人脸识别】Optical Flow算法在人脸防伪中的应用

1.本文简介:(原文PDF链接http://pan.baidu.com/s/1c0g0iQW) 学习本PDF后的一点总结.文章主要讲解了在人脸识别中的照片防伪技术,如何区分含有人脸的二维图片和三维真实人脸图是本文的主要工作. 实际应用举例:假冒者拿着你的照片来做人脸测试,意图通过识别程序,本文就是利用光流场来排除这样的伪造. 2.关键词: Optical FLow:光流场或光流动方向,趋势. Stereo vision:立体视觉. 3.正文内容 3.1 基本流程 下图是在人脸识别之前,需要进行的

光流算法:关于OpenCV读写middlebury网站给定的光流的代码

Middlebury是每个研究光流算法的人不可能不使用的网站,Middlebury提供了许多标准的测试库,这极大地推进了光流算法的进展.Middlebury提供的标准库,其计算出的光流保存在后缀名为.flo的文件中,Middlebury本身也提供了读取.flo文件中C++源码和Matlab源码.尽管如此,将源码写成与OpenCV结合的形式是我们更期望的,以下我写的读写.flo文件的源码.相对于Middlebury给定的源码,更简洁易懂. #include "CCC/COMCV.h" #

论文笔记之:Optical Flow Estimation using a Spatial Pyramid Network

Optical Flow Estimation using a Spatial Pyramid Network spynet 本文将经典的 spatial-pyramid formulation 和 deep learning 的方法相结合,以一种 coarse to fine approach,进行光流的计算.This estiamates large motions in a coarse to fine approach by warping one image of a pair at

FlowNet: Learning Optical Flow with Convolutional Networks

作者:嫩芽33出处:http://www.cnblogs.com/nenya33/p/7122701.html 版权:本文版权归作者和博客园共有 转载:欢迎转载,但未经作者同意,必须保留此段声明:必须在文章中给出原文连接:否则必究法律责任 学习了一篇用CNN做光流的paper,简称FlowNet. 1. 论文题目  FlowNet: Learning Optical Flow with Convolutional Networks 2.背景 为什么想到用CNN做光流:最近提出的CNN架构可以做逐

opencv中的 HOGDescriptor 类

其定义在  object.hpp中找到的: [cpp] view plain copy struct CV_EXPORTS_W HOGDescriptor { public: enum { L2Hys=0 }; enum { DEFAULT_NLEVELS=64 }; CV_WRAP HOGDescriptor() : winSize(64,128), blockSize(16,16), blockStride(8,8), cellSize(8,8), nbins(9), derivApertu

OpenCV中的Haar+Adaboost(五):AdaBoost之DAB与GAB

之前的文章主要讲解了OpenCV中与检测相关的内容,包括Haar特征.积分图和检测分类器结构:之后的文章将逐步开始介绍训练相关的内容.而本节主要介绍AdaBoost的理论,以及AdaBoost中的DAB与GAB算法,为后续讲解奠定基础. (一) AdaBoost背景介绍 在了解AdaBoost之前,先介绍弱学习和强学习的概念: 1. 弱学习:识别错误率小于1/2,即准确率仅比随机猜测略高的学习算法 2. 强学习:识别准确率很高并能在多项式时间内完成的学习算法 显然,无论对于任何分类问题,弱学习都

有关meanshift跟踪的理解(在opencv中实现)(转载)

meanshift算法思想其实很简单:利用概率密度的梯度爬升来寻找局部最优.它要做的就是输入一个在图像的范围,然后一直迭代(朝着重心迭代)直到满足你的要求为止.但是他是怎么用于做图像跟踪的呢?这是我自从学习meanshift以来,一直的困惑.而且网上也没有合理的解释.经过这几天的思考,和对反向投影的理解使得我对它的原理有了大致的认识. 在opencv中,进行meanshift其实很简单,输入一张图像(imgProb),再输入一个开始迭代的方框(windowIn)和一个迭代条件(criteria)