added dual tvl1 optical flow gpu implementation
[profile/ivi/opencv.git] / modules / gpu / test / test_optflow.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "test_precomp.hpp"
43
44 #ifdef HAVE_CUDA
45
46 //////////////////////////////////////////////////////
47 // BroxOpticalFlow
48
49 //#define BROX_DUMP
50
51 struct BroxOpticalFlow : testing::TestWithParam<cv::gpu::DeviceInfo>
52 {
53     cv::gpu::DeviceInfo devInfo;
54
55     virtual void SetUp()
56     {
57         devInfo = GetParam();
58
59         cv::gpu::setDevice(devInfo.deviceID());
60     }
61 };
62
63 GPU_TEST_P(BroxOpticalFlow, Regression)
64 {
65     cv::Mat frame0 = readImageType("opticalflow/frame0.png", CV_32FC1);
66     ASSERT_FALSE(frame0.empty());
67
68     cv::Mat frame1 = readImageType("opticalflow/frame1.png", CV_32FC1);
69     ASSERT_FALSE(frame1.empty());
70
71     cv::gpu::BroxOpticalFlow brox(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/,
72                                   10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/);
73
74     cv::gpu::GpuMat u;
75     cv::gpu::GpuMat v;
76     brox(loadMat(frame0), loadMat(frame1), u, v);
77
78     std::string fname(cvtest::TS::ptr()->get_data_path());
79     if (devInfo.majorVersion() >= 2)
80         fname += "opticalflow/brox_optical_flow_cc20.bin";
81     else
82         fname += "opticalflow/brox_optical_flow.bin";
83
84 #ifndef BROX_DUMP
85     std::ifstream f(fname.c_str(), std::ios_base::binary);
86
87     int rows, cols;
88
89     f.read((char*) &rows, sizeof(rows));
90     f.read((char*) &cols, sizeof(cols));
91
92     cv::Mat u_gold(rows, cols, CV_32FC1);
93
94     for (int i = 0; i < u_gold.rows; ++i)
95         f.read(u_gold.ptr<char>(i), u_gold.cols * sizeof(float));
96
97     cv::Mat v_gold(rows, cols, CV_32FC1);
98
99     for (int i = 0; i < v_gold.rows; ++i)
100         f.read(v_gold.ptr<char>(i), v_gold.cols * sizeof(float));
101
102     EXPECT_MAT_NEAR(u_gold, u, 0);
103     EXPECT_MAT_NEAR(v_gold, v, 0);
104 #else
105     std::ofstream f(fname.c_str(), std::ios_base::binary);
106
107     f.write((char*) &u.rows, sizeof(u.rows));
108     f.write((char*) &u.cols, sizeof(u.cols));
109
110     cv::Mat h_u(u);
111     cv::Mat h_v(v);
112
113     for (int i = 0; i < u.rows; ++i)
114         f.write(h_u.ptr<char>(i), u.cols * sizeof(float));
115
116     for (int i = 0; i < v.rows; ++i)
117         f.write(h_v.ptr<char>(i), v.cols * sizeof(float));
118 #endif
119 }
120
121 GPU_TEST_P(BroxOpticalFlow, OpticalFlowNan)
122 {
123     cv::Mat frame0 = readImageType("opticalflow/frame0.png", CV_32FC1);
124     ASSERT_FALSE(frame0.empty());
125
126     cv::Mat frame1 = readImageType("opticalflow/frame1.png", CV_32FC1);
127     ASSERT_FALSE(frame1.empty());
128
129     cv::Mat r_frame0, r_frame1;
130     cv::resize(frame0, r_frame0, cv::Size(1380,1000));
131     cv::resize(frame1, r_frame1, cv::Size(1380,1000));
132
133     cv::gpu::BroxOpticalFlow brox(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/,
134                                   5 /*inner_iterations*/, 150 /*outer_iterations*/, 10 /*solver_iterations*/);
135
136     cv::gpu::GpuMat u;
137     cv::gpu::GpuMat v;
138     brox(loadMat(r_frame0), loadMat(r_frame1), u, v);
139
140     cv::Mat h_u, h_v;
141     u.download(h_u);
142     v.download(h_v);
143
144     EXPECT_TRUE(cv::checkRange(h_u));
145     EXPECT_TRUE(cv::checkRange(h_v));
146 };
147
148 INSTANTIATE_TEST_CASE_P(GPU_Video, BroxOpticalFlow, ALL_DEVICES);
149
150 //////////////////////////////////////////////////////
151 // GoodFeaturesToTrack
152
153 namespace
154 {
155     IMPLEMENT_PARAM_CLASS(MinDistance, double)
156 }
157
158 PARAM_TEST_CASE(GoodFeaturesToTrack, cv::gpu::DeviceInfo, MinDistance)
159 {
160     cv::gpu::DeviceInfo devInfo;
161     double minDistance;
162
163     virtual void SetUp()
164     {
165         devInfo = GET_PARAM(0);
166         minDistance = GET_PARAM(1);
167
168         cv::gpu::setDevice(devInfo.deviceID());
169     }
170 };
171
172 GPU_TEST_P(GoodFeaturesToTrack, Accuracy)
173 {
174     cv::Mat image = readImage("opticalflow/frame0.png", cv::IMREAD_GRAYSCALE);
175     ASSERT_FALSE(image.empty());
176
177     int maxCorners = 1000;
178     double qualityLevel = 0.01;
179
180     cv::gpu::GoodFeaturesToTrackDetector_GPU detector(maxCorners, qualityLevel, minDistance);
181
182     cv::gpu::GpuMat d_pts;
183     detector(loadMat(image), d_pts);
184
185     ASSERT_FALSE(d_pts.empty());
186
187     std::vector<cv::Point2f> pts(d_pts.cols);
188     cv::Mat pts_mat(1, d_pts.cols, CV_32FC2, (void*) &pts[0]);
189     d_pts.download(pts_mat);
190
191     std::vector<cv::Point2f> pts_gold;
192     cv::goodFeaturesToTrack(image, pts_gold, maxCorners, qualityLevel, minDistance);
193
194     ASSERT_EQ(pts_gold.size(), pts.size());
195
196     size_t mistmatch = 0;
197     for (size_t i = 0; i < pts.size(); ++i)
198     {
199         cv::Point2i a = pts_gold[i];
200         cv::Point2i b = pts[i];
201
202         bool eq = std::abs(a.x - b.x) < 1 && std::abs(a.y - b.y) < 1;
203
204         if (!eq)
205             ++mistmatch;
206     }
207
208     double bad_ratio = static_cast<double>(mistmatch) / pts.size();
209
210     ASSERT_LE(bad_ratio, 0.01);
211 }
212
213 GPU_TEST_P(GoodFeaturesToTrack, EmptyCorners)
214 {
215     int maxCorners = 1000;
216     double qualityLevel = 0.01;
217
218     cv::gpu::GoodFeaturesToTrackDetector_GPU detector(maxCorners, qualityLevel, minDistance);
219
220     cv::gpu::GpuMat src(100, 100, CV_8UC1, cv::Scalar::all(0));
221     cv::gpu::GpuMat corners(1, maxCorners, CV_32FC2);
222
223     detector(src, corners);
224
225     ASSERT_TRUE(corners.empty());
226 }
227
228 INSTANTIATE_TEST_CASE_P(GPU_Video, GoodFeaturesToTrack, testing::Combine(
229     ALL_DEVICES,
230     testing::Values(MinDistance(0.0), MinDistance(3.0))));
231
232 //////////////////////////////////////////////////////
233 // PyrLKOpticalFlow
234
235 namespace
236 {
237     IMPLEMENT_PARAM_CLASS(UseGray, bool)
238 }
239
240 PARAM_TEST_CASE(PyrLKOpticalFlow, cv::gpu::DeviceInfo, UseGray)
241 {
242     cv::gpu::DeviceInfo devInfo;
243     bool useGray;
244
245     virtual void SetUp()
246     {
247         devInfo = GET_PARAM(0);
248         useGray = GET_PARAM(1);
249
250         cv::gpu::setDevice(devInfo.deviceID());
251     }
252 };
253
254 GPU_TEST_P(PyrLKOpticalFlow, Sparse)
255 {
256     cv::Mat frame0 = readImage("opticalflow/frame0.png", useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR);
257     ASSERT_FALSE(frame0.empty());
258
259     cv::Mat frame1 = readImage("opticalflow/frame1.png", useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR);
260     ASSERT_FALSE(frame1.empty());
261
262     cv::Mat gray_frame;
263     if (useGray)
264         gray_frame = frame0;
265     else
266         cv::cvtColor(frame0, gray_frame, cv::COLOR_BGR2GRAY);
267
268     std::vector<cv::Point2f> pts;
269     cv::goodFeaturesToTrack(gray_frame, pts, 1000, 0.01, 0.0);
270
271     cv::gpu::GpuMat d_pts;
272     cv::Mat pts_mat(1, (int) pts.size(), CV_32FC2, (void*) &pts[0]);
273     d_pts.upload(pts_mat);
274
275     cv::gpu::PyrLKOpticalFlow pyrLK;
276
277     cv::gpu::GpuMat d_nextPts;
278     cv::gpu::GpuMat d_status;
279     pyrLK.sparse(loadMat(frame0), loadMat(frame1), d_pts, d_nextPts, d_status);
280
281     std::vector<cv::Point2f> nextPts(d_nextPts.cols);
282     cv::Mat nextPts_mat(1, d_nextPts.cols, CV_32FC2, (void*) &nextPts[0]);
283     d_nextPts.download(nextPts_mat);
284
285     std::vector<unsigned char> status(d_status.cols);
286     cv::Mat status_mat(1, d_status.cols, CV_8UC1, (void*) &status[0]);
287     d_status.download(status_mat);
288
289     std::vector<cv::Point2f> nextPts_gold;
290     std::vector<unsigned char> status_gold;
291     cv::calcOpticalFlowPyrLK(frame0, frame1, pts, nextPts_gold, status_gold, cv::noArray());
292
293     ASSERT_EQ(nextPts_gold.size(), nextPts.size());
294     ASSERT_EQ(status_gold.size(), status.size());
295
296     size_t mistmatch = 0;
297     for (size_t i = 0; i < nextPts.size(); ++i)
298     {
299         cv::Point2i a = nextPts[i];
300         cv::Point2i b = nextPts_gold[i];
301
302         if (status[i] != status_gold[i])
303         {
304             ++mistmatch;
305             continue;
306         }
307
308         if (status[i])
309         {
310             bool eq = std::abs(a.x - b.x) <= 1 && std::abs(a.y - b.y) <= 1;
311
312             if (!eq)
313                 ++mistmatch;
314         }
315     }
316
317     double bad_ratio = static_cast<double>(mistmatch) / nextPts.size();
318
319     ASSERT_LE(bad_ratio, 0.01);
320 }
321
322 INSTANTIATE_TEST_CASE_P(GPU_Video, PyrLKOpticalFlow, testing::Combine(
323     ALL_DEVICES,
324     testing::Values(UseGray(true), UseGray(false))));
325
326 //////////////////////////////////////////////////////
327 // FarnebackOpticalFlow
328
329 namespace
330 {
331     IMPLEMENT_PARAM_CLASS(PyrScale, double)
332     IMPLEMENT_PARAM_CLASS(PolyN, int)
333     CV_FLAGS(FarnebackOptFlowFlags, 0, cv::OPTFLOW_FARNEBACK_GAUSSIAN)
334     IMPLEMENT_PARAM_CLASS(UseInitFlow, bool)
335 }
336
337 PARAM_TEST_CASE(FarnebackOpticalFlow, cv::gpu::DeviceInfo, PyrScale, PolyN, FarnebackOptFlowFlags, UseInitFlow)
338 {
339     cv::gpu::DeviceInfo devInfo;
340     double pyrScale;
341     int polyN;
342     int flags;
343     bool useInitFlow;
344
345     virtual void SetUp()
346     {
347         devInfo = GET_PARAM(0);
348         pyrScale = GET_PARAM(1);
349         polyN = GET_PARAM(2);
350         flags = GET_PARAM(3);
351         useInitFlow = GET_PARAM(4);
352
353         cv::gpu::setDevice(devInfo.deviceID());
354     }
355 };
356
357 GPU_TEST_P(FarnebackOpticalFlow, Accuracy)
358 {
359     cv::Mat frame0 = readImage("opticalflow/rubberwhale1.png", cv::IMREAD_GRAYSCALE);
360     ASSERT_FALSE(frame0.empty());
361
362     cv::Mat frame1 = readImage("opticalflow/rubberwhale2.png", cv::IMREAD_GRAYSCALE);
363     ASSERT_FALSE(frame1.empty());
364
365     double polySigma = polyN <= 5 ? 1.1 : 1.5;
366
367     cv::gpu::FarnebackOpticalFlow farn;
368     farn.pyrScale = pyrScale;
369     farn.polyN = polyN;
370     farn.polySigma = polySigma;
371     farn.flags = flags;
372
373     cv::gpu::GpuMat d_flowx, d_flowy;
374     farn(loadMat(frame0), loadMat(frame1), d_flowx, d_flowy);
375
376     cv::Mat flow;
377     if (useInitFlow)
378     {
379         cv::Mat flowxy[] = {cv::Mat(d_flowx), cv::Mat(d_flowy)};
380         cv::merge(flowxy, 2, flow);
381
382         farn.flags |= cv::OPTFLOW_USE_INITIAL_FLOW;
383         farn(loadMat(frame0), loadMat(frame1), d_flowx, d_flowy);
384     }
385
386     cv::calcOpticalFlowFarneback(
387         frame0, frame1, flow, farn.pyrScale, farn.numLevels, farn.winSize,
388         farn.numIters, farn.polyN, farn.polySigma, farn.flags);
389
390     std::vector<cv::Mat> flowxy;
391     cv::split(flow, flowxy);
392
393     EXPECT_MAT_SIMILAR(flowxy[0], d_flowx, 0.1);
394     EXPECT_MAT_SIMILAR(flowxy[1], d_flowy, 0.1);
395 }
396
397 INSTANTIATE_TEST_CASE_P(GPU_Video, FarnebackOpticalFlow, testing::Combine(
398     ALL_DEVICES,
399     testing::Values(PyrScale(0.3), PyrScale(0.5), PyrScale(0.8)),
400     testing::Values(PolyN(5), PolyN(7)),
401     testing::Values(FarnebackOptFlowFlags(0), FarnebackOptFlowFlags(cv::OPTFLOW_FARNEBACK_GAUSSIAN)),
402     testing::Values(UseInitFlow(false), UseInitFlow(true))));
403
404 //////////////////////////////////////////////////////
405 // OpticalFlowDual_TVL1
406
407 PARAM_TEST_CASE(OpticalFlowDual_TVL1, cv::gpu::DeviceInfo, UseRoi)
408 {
409     cv::gpu::DeviceInfo devInfo;
410     bool useRoi;
411
412     virtual void SetUp()
413     {
414         devInfo = GET_PARAM(0);
415         useRoi = GET_PARAM(1);
416
417         cv::gpu::setDevice(devInfo.deviceID());
418     }
419 };
420
421 GPU_TEST_P(OpticalFlowDual_TVL1, Accuracy)
422 {
423     cv::Mat frame0 = readImage("opticalflow/rubberwhale1.png", cv::IMREAD_GRAYSCALE);
424     ASSERT_FALSE(frame0.empty());
425
426     cv::Mat frame1 = readImage("opticalflow/rubberwhale2.png", cv::IMREAD_GRAYSCALE);
427     ASSERT_FALSE(frame1.empty());
428
429     cv::gpu::OpticalFlowDual_TVL1_GPU d_alg;
430     cv::gpu::GpuMat d_flowx = createMat(frame0.size(), CV_32FC1, useRoi);
431     cv::gpu::GpuMat d_flowy = createMat(frame0.size(), CV_32FC1, useRoi);
432     d_alg(loadMat(frame0, useRoi), loadMat(frame1, useRoi), d_flowx, d_flowy);
433
434     cv::OpticalFlowDual_TVL1 alg;
435     cv::Mat flow;
436     alg(frame0, frame1, flow);
437     cv::Mat gold[2];
438     cv::split(flow, gold);
439
440     EXPECT_MAT_SIMILAR(gold[0], d_flowx, 3e-3);
441     EXPECT_MAT_SIMILAR(gold[1], d_flowy, 3e-3);
442 }
443
444 INSTANTIATE_TEST_CASE_P(GPU_Video, OpticalFlowDual_TVL1, testing::Combine(
445     ALL_DEVICES,
446     WHOLE_SUBMAT));
447
448 #endif // HAVE_CUDA