1
1
#include < iostream>
2
2
#include < vector>
3
3
4
- #include " opencv2/core.hpp"
4
+ #include < opencv2/core.hpp>
5
5
#include < opencv2/core/utility.hpp>
6
- #include " opencv2/imgproc.hpp"
7
- #include " opencv2/highgui.hpp"
8
- #include " opencv2/video.hpp"
9
- #include " opencv2/cudaoptflow.hpp"
10
- #include " opencv2/cudaimgproc.hpp"
6
+ #include < opencv2/imgproc.hpp>
7
+ #include < opencv2/highgui.hpp>
8
+ #include < opencv2/video.hpp>
9
+ #include < opencv2/cudaoptflow.hpp>
10
+ #include < opencv2/cudaimgproc.hpp>
11
+ #include < opencv2/cudaarithm.hpp>
11
12
12
13
using namespace std ;
13
14
using namespace cv ;
@@ -66,6 +67,132 @@ static void drawArrows(Mat& frame, const vector<Point2f>& prevPts, const vector<
66
67
}
67
68
}
68
69
70
+ inline bool isFlowCorrect (Point2f u)
71
+ {
72
+ return !cvIsNaN (u.x ) && !cvIsNaN (u.y ) && fabs (u.x ) < 1e9 && fabs (u.y ) < 1e9 ;
73
+ }
74
+
75
+ static Vec3b computeColor (float fx, float fy)
76
+ {
77
+ static bool first = true ;
78
+
79
+ // relative lengths of color transitions:
80
+ // these are chosen based on perceptual similarity
81
+ // (e.g. one can distinguish more shades between red and yellow
82
+ // than between yellow and green)
83
+ const int RY = 15 ;
84
+ const int YG = 6 ;
85
+ const int GC = 4 ;
86
+ const int CB = 11 ;
87
+ const int BM = 13 ;
88
+ const int MR = 6 ;
89
+ const int NCOLS = RY + YG + GC + CB + BM + MR;
90
+ static Vec3i colorWheel[NCOLS];
91
+
92
+ if (first)
93
+ {
94
+ int k = 0 ;
95
+
96
+ for (int i = 0 ; i < RY; ++i, ++k)
97
+ colorWheel[k] = Vec3i (255 , 255 * i / RY, 0 );
98
+
99
+ for (int i = 0 ; i < YG; ++i, ++k)
100
+ colorWheel[k] = Vec3i (255 - 255 * i / YG, 255 , 0 );
101
+
102
+ for (int i = 0 ; i < GC; ++i, ++k)
103
+ colorWheel[k] = Vec3i (0 , 255 , 255 * i / GC);
104
+
105
+ for (int i = 0 ; i < CB; ++i, ++k)
106
+ colorWheel[k] = Vec3i (0 , 255 - 255 * i / CB, 255 );
107
+
108
+ for (int i = 0 ; i < BM; ++i, ++k)
109
+ colorWheel[k] = Vec3i (255 * i / BM, 0 , 255 );
110
+
111
+ for (int i = 0 ; i < MR; ++i, ++k)
112
+ colorWheel[k] = Vec3i (255 , 0 , 255 - 255 * i / MR);
113
+
114
+ first = false ;
115
+ }
116
+
117
+ const float rad = sqrt (fx * fx + fy * fy);
118
+ const float a = atan2 (-fy, -fx) / (float )CV_PI;
119
+
120
+ const float fk = (a + 1 .0f ) / 2 .0f * (NCOLS - 1 );
121
+ const int k0 = static_cast <int >(fk);
122
+ const int k1 = (k0 + 1 ) % NCOLS;
123
+ const float f = fk - k0;
124
+
125
+ Vec3b pix;
126
+
127
+ for (int b = 0 ; b < 3 ; b++)
128
+ {
129
+ const float col0 = colorWheel[k0][b] / 255 .0f ;
130
+ const float col1 = colorWheel[k1][b] / 255 .0f ;
131
+
132
+ float col = (1 - f) * col0 + f * col1;
133
+
134
+ if (rad <= 1 )
135
+ col = 1 - rad * (1 - col); // increase saturation with radius
136
+ else
137
+ col *= .75 ; // out of range
138
+
139
+ pix[2 - b] = static_cast <uchar>(255.0 * col);
140
+ }
141
+
142
+ return pix;
143
+ }
144
+
145
+ static void drawOpticalFlow (const Mat_<float >& flowx, const Mat_<float >& flowy, Mat& dst, float maxmotion = -1 )
146
+ {
147
+ dst.create (flowx.size (), CV_8UC3);
148
+ dst.setTo (Scalar::all (0 ));
149
+
150
+ // determine motion range:
151
+ float maxrad = maxmotion;
152
+
153
+ if (maxmotion <= 0 )
154
+ {
155
+ maxrad = 1 ;
156
+ for (int y = 0 ; y < flowx.rows ; ++y)
157
+ {
158
+ for (int x = 0 ; x < flowx.cols ; ++x)
159
+ {
160
+ Point2f u (flowx (y, x), flowy (y, x));
161
+
162
+ if (!isFlowCorrect (u))
163
+ continue ;
164
+
165
+ maxrad = max (maxrad, sqrt (u.x * u.x + u.y * u.y ));
166
+ }
167
+ }
168
+ }
169
+
170
+ for (int y = 0 ; y < flowx.rows ; ++y)
171
+ {
172
+ for (int x = 0 ; x < flowx.cols ; ++x)
173
+ {
174
+ Point2f u (flowx (y, x), flowy (y, x));
175
+
176
+ if (isFlowCorrect (u))
177
+ dst.at <Vec3b>(y, x) = computeColor (u.x / maxrad, u.y / maxrad);
178
+ }
179
+ }
180
+ }
181
+
182
+ static void showFlow (const char * name, const GpuMat& d_flow)
183
+ {
184
+ GpuMat planes[2 ];
185
+ cuda::split (d_flow, planes);
186
+
187
+ Mat flowx (planes[0 ]);
188
+ Mat flowy (planes[1 ]);
189
+
190
+ Mat out;
191
+ drawOpticalFlow (flowx, flowy, out, 10 );
192
+
193
+ imshow (name, out);
194
+ }
195
+
69
196
template <typename T> inline T clamp (T x, T a, T b)
70
197
{
71
198
return ((x) > (a) ? ((x) < (b) ? (x) : (b)) : (a));
@@ -80,15 +207,16 @@ template <typename T> inline T mapValue(T x, T a, T b, T c, T d)
80
207
int main (int argc, const char * argv[])
81
208
{
82
209
const char * keys =
83
- " { h help | | print help message }"
210
+ " { h help | | print help message }"
84
211
" { l left | ../data/pic1.png | specify left image }"
85
212
" { r right | ../data/pic2.png | specify right image }"
86
- " { gray | | use grayscale sources [PyrLK Sparse] }"
87
- " { win_size | 21 | specify windows size [PyrLK] }"
88
- " { max_level | 3 | specify max level [PyrLK] }"
89
- " { iters | 30 | specify iterations count [PyrLK] }"
90
- " { points | 4000 | specify points count [GoodFeatureToTrack] }"
91
- " { min_dist | 0 | specify minimal distance between points [GoodFeatureToTrack] }" ;
213
+ " { flow | sparse | specify flow type [PyrLK] }"
214
+ " { gray | | use grayscale sources [PyrLK Sparse] }"
215
+ " { win_size | 21 | specify windows size [PyrLK] }"
216
+ " { max_level | 3 | specify max level [PyrLK] }"
217
+ " { iters | 30 | specify iterations count [PyrLK] }"
218
+ " { points | 4000 | specify points count [GoodFeatureToTrack] }"
219
+ " { min_dist | 0 | specify minimal distance between points [GoodFeatureToTrack] }" ;
92
220
93
221
CommandLineParser cmd (argc, argv, keys);
94
222
@@ -108,6 +236,22 @@ int main(int argc, const char* argv[])
108
236
return -1 ;
109
237
}
110
238
239
+ string flow_type = cmd.get <string>(" flow" );
240
+ bool is_sparse = true ;
241
+ if (flow_type == " sparse" )
242
+ {
243
+ is_sparse = true ;
244
+ }
245
+ else if (flow_type == " dense" )
246
+ {
247
+ is_sparse = false ;
248
+ }
249
+ else
250
+ {
251
+ cerr << " please specify 'sparse' or 'dense' as flow type" << endl;
252
+ return -1 ;
253
+ }
254
+
111
255
bool useGray = cmd.has (" gray" );
112
256
int winSize = cmd.get <int >(" win_size" );
113
257
int maxLevel = cmd.get <int >(" max_level" );
@@ -124,9 +268,6 @@ int main(int argc, const char* argv[])
124
268
return -1 ;
125
269
}
126
270
127
- namedWindow (" PyrLK [Sparse]" , WINDOW_NORMAL);
128
- namedWindow (" PyrLK [Dense] Flow Field" , WINDOW_NORMAL);
129
-
130
271
cout << " Image size : " << frame0.cols << " x " << frame0.rows << endl;
131
272
cout << " Points count : " << points << endl;
132
273
@@ -138,43 +279,53 @@ int main(int argc, const char* argv[])
138
279
cv::cvtColor (frame1, frame1Gray, COLOR_BGR2GRAY);
139
280
140
281
// goodFeaturesToTrack
141
-
142
282
GpuMat d_frame0Gray (frame0Gray);
143
283
GpuMat d_prevPts;
144
284
145
285
Ptr<cuda::CornersDetector> detector = cuda::createGoodFeaturesToTrackDetector (d_frame0Gray.type (), points, 0.01 , minDist);
146
-
147
286
detector->detect (d_frame0Gray, d_prevPts);
148
287
149
- // Sparse
150
-
151
- Ptr<cuda::SparsePyrLKOpticalFlow> d_pyrLK = cuda::SparsePyrLKOpticalFlow::create (
152
- Size (winSize, winSize), maxLevel, iters);
153
-
154
288
GpuMat d_frame0 (frame0);
155
289
GpuMat d_frame1 (frame1);
156
290
GpuMat d_frame1Gray (frame1Gray);
157
291
GpuMat d_nextPts;
158
292
GpuMat d_status;
293
+ GpuMat d_flow (frame0.size (), CV_32FC2);
159
294
160
- d_pyrLK-> calc (useGray ? d_frame0Gray : d_frame0, useGray ? d_frame1Gray : d_frame1, d_prevPts, d_nextPts, d_status);
161
-
162
- // Draw arrows
163
-
164
- vector<Point2f> prevPts (d_prevPts. cols );
165
- download ( d_prevPts, prevPts );
295
+ if (is_sparse)
296
+ {
297
+ // Sparse
298
+ Ptr<cuda::SparsePyrLKOpticalFlow> d_pyrLK_sparse = cuda::SparsePyrLKOpticalFlow::create (
299
+ Size (winSize, winSize), maxLevel, iters );
300
+ d_pyrLK_sparse-> calc (useGray ? d_frame0Gray : d_frame0, useGray ? d_frame1Gray : d_frame1, d_prevPts, d_nextPts, d_status );
166
301
167
- vector<Point2f> nextPts (d_nextPts.cols );
168
- download (d_nextPts, nextPts);
302
+ // Draw arrows
303
+ vector<Point2f> prevPts (d_prevPts.cols );
304
+ download (d_prevPts, prevPts);
169
305
170
- vector<uchar> status (d_status .cols );
171
- download (d_status, status );
306
+ vector<Point2f> nextPts (d_nextPts .cols );
307
+ download (d_nextPts, nextPts );
172
308
173
- drawArrows (frame0, prevPts, nextPts, status, Scalar (255 , 0 , 0 ));
309
+ vector<uchar> status (d_status.cols );
310
+ download (d_status, status);
174
311
175
- imshow (" PyrLK [Sparse]" , frame0);
312
+ namedWindow (" PyrLK [Sparse]" , WINDOW_NORMAL);
313
+ drawArrows (frame0, prevPts, nextPts, status, Scalar (255 , 0 , 0 ));
314
+ imshow (" PyrLK [Sparse]" , frame0);
315
+ }
316
+ else
317
+ {
318
+ // Dense
319
+ Ptr<cuda::DensePyrLKOpticalFlow> d_pyrLK_dense = cuda::DensePyrLKOpticalFlow::create (
320
+ Size (winSize, winSize), maxLevel, iters);
321
+ d_pyrLK_dense->calc (d_frame0Gray, d_frame1Gray, d_flow);
322
+
323
+ // Draw flows
324
+ namedWindow (" PyrLK [Dense] Flow Field" , WINDOW_NORMAL);
325
+ showFlow (" PyrLK [Dense] Flow Field" , d_flow);
326
+ }
176
327
177
- waitKey ();
328
+ waitKey (0 );
178
329
179
330
return 0 ;
180
- }
331
+ }
0 commit comments