光流(optical flow)和openCV中实现
当前位置:以往代写 > C/C++ 教程 >光流(optical flow)和openCV中实现
2019-06-13

光流(optical flow)和openCV中实现

光流(optical flow)和openCV中实现

副标题#e#

光流的观念:

是Gibson在1950年首先提出来的。它是空间举动物体在调查成像平面上的像素举动的瞬时速度,是操作图像序列中像素在时间域上的变革以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应干系,从而计较出相邻帧之间物体的举动信息的一种要领。一般而言,光流是由于场景中前景方针自己的移动、相机的举动,可能两者的配合举动所发生的。

当人的眼睛调查举动物体时,物体的情形在人眼的视网膜上形成一系列持续变革的图像,这一系列持续变革的信息不绝“流过”视网膜(即图像平面),仿佛一种光的“流”,故称之为光流(optical flow)。光流表达了图像的变革,由于它包括了方针举动的信息,因此可被调查者用来确定方针的举动环境。

看下面的图,它展示了一个小球在5个持续的帧中的举动,箭头上的数字代表差异的帧,谁人赤色小球的举动组成了光流。

光流(optical flow)和openCV中实现

操纵:

给你一个图上的一系列点,在别的一张图上找到与前面一些列点沟通的点。

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

光流(optical flow)和openCV中实现

上面插手Wx暗示一块区域,一般跟踪一个区域的点。

在图形学应用中,在多张图上跟踪点(特征)是一项根基的操纵:在一张图上找到一个工具,调查工具如何移动。

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

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

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

3)过滤位置稳定的特征点,余下的点就是方针了。

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

思量一个像素光流(optical flow)和openCV中实现在第一帧的光强度(这里增加了一个维度时间,前面的时候我们只是处理惩罚图像,所以没有须要时间。此刻需要增加这个维度)。它移动了 光流(optical flow)和openCV中实现的间隔到一下帧,用了光流(optical flow)和openCV中实现时间。因为像素点是一样的,光强度也没有产生变革(其实这个光强度没有改变是许多光流算法的根基假设)。,所以我们可以说:

光流(optical flow)和openCV中实现

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

光流(optical flow)和openCV中实现

所以:

光流(optical flow)和openCV中实现

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


#p#副标题#e#

Lucas-Kanade:

有这么一个假定,所有的相邻像素有相似的动作,Lucas-Kanade要领利用3*3的一块区域,它假定这9个点有沟通的动作,所以此刻的问题变为有9个等式,2个未知量,这个问题虽然可以或许办理。一个好的办理方法是利用最小二乘法。

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

光流(optical flow)和openCV中实现

光流(optical flow)和openCV中实现

光流(optical flow)和openCV中实现

光流(optical flow)和openCV中实现

个中q1,q2,…,代表像素点,光流(optical flow)和openCV中实现 是偏导,上面的等式可以写成下面的形式:A v = b,个中:

光流(optical flow)和openCV中实现

然后,获得下面的:

光流(optical flow)和openCV中实现

光流(optical flow)和openCV中实现

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

光流(optical flow)和openCV中实现

#p#分页标题#e#

上面的办理小而连贯的举动,想想方才我们的假设是9个像素点速度一致。因为现实中大而连贯的举动是普遍存在的,我们需要大的窗口来捕捉举动,但是大窗口违背了举动连贯的假设,图像金字塔可以办理这个问题。(图像金字塔的内容今后本人把握更多的再增补,此刻不敢乱颁发)。

#p#副标题#e#

OpenCV中的实现:

OpenCV提供了对上面先容的要领的支持,函数名叫做:cv2.calcOpticalFlowPyrLK(),此刻让我们在视频中跟踪一些点。为了抉择跟踪哪些点,利用cv2.goodFeaturesToTrack()。

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

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

#p#分页标题#e#

功效:随意取得一些特征点,特征点会跟着车的移动而移动

光流(optical flow)和openCV中实现

    关键字:

在线提交作业