Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/ts/src/cuda_test.cpp
16337 views
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
// License Agreement
11
// For Open Source Computer Vision Library
12
//
13
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15
// Third party copyrights are property of their respective owners.
16
//
17
// Redistribution and use in source and binary forms, with or without modification,
18
// are permitted provided that the following conditions are met:
19
//
20
// * Redistribution's of source code must retain the above copyright notice,
21
// this list of conditions and the following disclaimer.
22
//
23
// * Redistribution's in binary form must reproduce the above copyright notice,
24
// this list of conditions and the following disclaimer in the documentation
25
// and/or other materials provided with the distribution.
26
//
27
// * The name of the copyright holders may not be used to endorse or promote products
28
// derived from this software without specific prior written permission.
29
//
30
// This software is provided by the copyright holders and contributors "as is" and
31
// any express or implied warranties, including, but not limited to, the implied
32
// warranties of merchantability and fitness for a particular purpose are disclaimed.
33
// In no event shall the Intel Corporation or contributors be liable for any direct,
34
// indirect, incidental, special, exemplary, or consequential damages
35
// (including, but not limited to, procurement of substitute goods or services;
36
// loss of use, data, or profits; or business interruption) however caused
37
// and on any theory of liability, whether in contract, strict liability,
38
// or tort (including negligence or otherwise) arising in any way out of
39
// the use of this software, even if advised of the possibility of such damage.
40
//
41
//M*/
42
43
#include "opencv2/ts/cuda_test.hpp"
44
#include <stdexcept>
45
46
using namespace cv;
47
using namespace cv::cuda;
48
using namespace cvtest;
49
using namespace testing;
50
using namespace testing::internal;
51
52
namespace perf
53
{
54
void printCudaInfo();
55
}
56
57
namespace cvtest
58
{
59
//////////////////////////////////////////////////////////////////////
60
// random generators
61
62
int randomInt(int minVal, int maxVal)
63
{
64
RNG& rng = TS::ptr()->get_rng();
65
return rng.uniform(minVal, maxVal);
66
}
67
68
double randomDouble(double minVal, double maxVal)
69
{
70
RNG& rng = TS::ptr()->get_rng();
71
return rng.uniform(minVal, maxVal);
72
}
73
74
Size randomSize(int minVal, int maxVal)
75
{
76
return Size(randomInt(minVal, maxVal), randomInt(minVal, maxVal));
77
}
78
79
Scalar randomScalar(double minVal, double maxVal)
80
{
81
return Scalar(randomDouble(minVal, maxVal), randomDouble(minVal, maxVal), randomDouble(minVal, maxVal), randomDouble(minVal, maxVal));
82
}
83
84
Mat randomMat(Size size, int type, double minVal, double maxVal)
85
{
86
return randomMat(TS::ptr()->get_rng(), size, type, minVal, maxVal, false);
87
}
88
89
//////////////////////////////////////////////////////////////////////
90
// GpuMat create
91
92
GpuMat createMat(Size size, int type, bool useRoi)
93
{
94
Size size0 = size;
95
96
if (useRoi)
97
{
98
size0.width += randomInt(5, 15);
99
size0.height += randomInt(5, 15);
100
}
101
102
GpuMat d_m(size0, type);
103
104
if (size0 != size)
105
d_m = d_m(Rect((size0.width - size.width) / 2, (size0.height - size.height) / 2, size.width, size.height));
106
107
return d_m;
108
}
109
110
GpuMat loadMat(const Mat& m, bool useRoi)
111
{
112
GpuMat d_m = createMat(m.size(), m.type(), useRoi);
113
d_m.upload(m);
114
return d_m;
115
}
116
117
//////////////////////////////////////////////////////////////////////
118
// Image load
119
120
Mat readImage(const std::string& fileName, int flags)
121
{
122
return imread(TS::ptr()->get_data_path() + fileName, flags);
123
}
124
125
Mat readImageType(const std::string& fname, int type)
126
{
127
Mat src = readImage(fname, CV_MAT_CN(type) == 1 ? IMREAD_GRAYSCALE : IMREAD_COLOR);
128
if (CV_MAT_CN(type) == 4)
129
{
130
Mat temp;
131
cvtColor(src, temp, COLOR_BGR2BGRA);
132
swap(src, temp);
133
}
134
src.convertTo(src, CV_MAT_DEPTH(type), CV_MAT_DEPTH(type) == CV_32F ? 1.0 / 255.0 : 1.0);
135
return src;
136
}
137
138
//////////////////////////////////////////////////////////////////////
139
// Gpu devices
140
141
bool supportFeature(const DeviceInfo& info, FeatureSet feature)
142
{
143
return TargetArchs::builtWith(feature) && info.supports(feature);
144
}
145
146
DeviceManager& DeviceManager::instance()
147
{
148
static DeviceManager obj;
149
return obj;
150
}
151
152
void DeviceManager::load(int i)
153
{
154
devices_.clear();
155
devices_.reserve(1);
156
157
std::ostringstream msg;
158
159
if (i < 0 || i >= getCudaEnabledDeviceCount())
160
{
161
msg << "Incorrect device number - " << i;
162
throw std::runtime_error(msg.str());
163
}
164
165
DeviceInfo info(i);
166
167
if (!info.isCompatible())
168
{
169
msg << "Device " << i << " [" << info.name() << "] is NOT compatible with current CUDA module build";
170
throw std::runtime_error(msg.str());
171
}
172
173
devices_.push_back(info);
174
}
175
176
void DeviceManager::loadAll()
177
{
178
int deviceCount = getCudaEnabledDeviceCount();
179
180
devices_.clear();
181
devices_.reserve(deviceCount);
182
183
for (int i = 0; i < deviceCount; ++i)
184
{
185
DeviceInfo info(i);
186
if (info.isCompatible())
187
{
188
devices_.push_back(info);
189
}
190
}
191
}
192
193
void parseCudaDeviceOptions(int argc, char **argv)
194
{
195
cv::CommandLineParser cmd(argc, argv,
196
"{ cuda_device | -1 | CUDA device on which tests will be executed (-1 means all devices) }"
197
"{ h help | false | Print help info }"
198
);
199
200
if (cmd.has("help"))
201
{
202
std::cout << "\nAvailable options besides google test option: \n";
203
cmd.printMessage();
204
}
205
206
int device = cmd.get<int>("cuda_device");
207
if (device < 0)
208
{
209
cvtest::DeviceManager::instance().loadAll();
210
std::cout << "Run tests on all supported CUDA devices \n" << std::endl;
211
}
212
else
213
{
214
cvtest::DeviceManager::instance().load(device);
215
cv::cuda::DeviceInfo info(device);
216
std::cout << "Run tests on CUDA device " << device << " [" << info.name() << "] \n" << std::endl;
217
}
218
}
219
220
//////////////////////////////////////////////////////////////////////
221
// Additional assertion
222
223
namespace
224
{
225
template <typename T, typename OutT> std::string printMatValImpl(const Mat& m, Point p)
226
{
227
const int cn = m.channels();
228
229
std::ostringstream ostr;
230
ostr << "(";
231
232
p.x /= cn;
233
234
ostr << static_cast<OutT>(m.at<T>(p.y, p.x * cn));
235
for (int c = 1; c < m.channels(); ++c)
236
{
237
ostr << ", " << static_cast<OutT>(m.at<T>(p.y, p.x * cn + c));
238
}
239
ostr << ")";
240
241
return ostr.str();
242
}
243
244
std::string printMatVal(const Mat& m, Point p)
245
{
246
typedef std::string (*func_t)(const Mat& m, Point p);
247
248
static const func_t funcs[] =
249
{
250
printMatValImpl<uchar, int>, printMatValImpl<schar, int>, printMatValImpl<ushort, int>, printMatValImpl<short, int>,
251
printMatValImpl<int, int>, printMatValImpl<float, float>, printMatValImpl<double, double>
252
};
253
254
return funcs[m.depth()](m, p);
255
}
256
}
257
258
void minMaxLocGold(const Mat& src, double* minVal_, double* maxVal_, Point* minLoc_, Point* maxLoc_, const Mat& mask)
259
{
260
if (src.depth() != CV_8S)
261
{
262
minMaxLoc(src, minVal_, maxVal_, minLoc_, maxLoc_, mask);
263
return;
264
}
265
266
// OpenCV's minMaxLoc doesn't support CV_8S type
267
double minVal = std::numeric_limits<double>::max();
268
Point minLoc(-1, -1);
269
270
double maxVal = -std::numeric_limits<double>::max();
271
Point maxLoc(-1, -1);
272
273
for (int y = 0; y < src.rows; ++y)
274
{
275
const schar* src_row = src.ptr<schar>(y);
276
const uchar* mask_row = mask.empty() ? 0 : mask.ptr<uchar>(y);
277
278
for (int x = 0; x < src.cols; ++x)
279
{
280
if (!mask_row || mask_row[x])
281
{
282
schar val = src_row[x];
283
284
if (val < minVal)
285
{
286
minVal = val;
287
minLoc = cv::Point(x, y);
288
}
289
290
if (val > maxVal)
291
{
292
maxVal = val;
293
maxLoc = cv::Point(x, y);
294
}
295
}
296
}
297
}
298
299
if (minVal_) *minVal_ = minVal;
300
if (maxVal_) *maxVal_ = maxVal;
301
302
if (minLoc_) *minLoc_ = minLoc;
303
if (maxLoc_) *maxLoc_ = maxLoc;
304
}
305
306
Mat getMat(InputArray arr)
307
{
308
if (arr.kind() == _InputArray::CUDA_GPU_MAT)
309
{
310
Mat m;
311
arr.getGpuMat().download(m);
312
return m;
313
}
314
315
return arr.getMat();
316
}
317
318
AssertionResult assertMatNear(const char* expr1, const char* expr2, const char* eps_expr, InputArray m1_, InputArray m2_, double eps)
319
{
320
Mat m1 = getMat(m1_);
321
Mat m2 = getMat(m2_);
322
323
if (m1.size() != m2.size())
324
{
325
std::stringstream msg;
326
msg << "Matrices \"" << expr1 << "\" and \"" << expr2 << "\" have different sizes : \""
327
<< expr1 << "\" [" << PrintToString(m1.size()) << "] vs \""
328
<< expr2 << "\" [" << PrintToString(m2.size()) << "]";
329
return AssertionFailure() << msg.str();
330
}
331
332
if (m1.type() != m2.type())
333
{
334
std::stringstream msg;
335
msg << "Matrices \"" << expr1 << "\" and \"" << expr2 << "\" have different types : \""
336
<< expr1 << "\" [" << PrintToString(MatType(m1.type())) << "] vs \""
337
<< expr2 << "\" [" << PrintToString(MatType(m2.type())) << "]";
338
return AssertionFailure() << msg.str();
339
}
340
341
Mat diff;
342
absdiff(m1.reshape(1), m2.reshape(1), diff);
343
344
double maxVal = 0.0;
345
Point maxLoc;
346
minMaxLocGold(diff, 0, &maxVal, 0, &maxLoc);
347
348
if (maxVal > eps)
349
{
350
std::stringstream msg;
351
msg << "The max difference between matrices \"" << expr1 << "\" and \"" << expr2
352
<< "\" is " << maxVal << " at (" << maxLoc.y << ", " << maxLoc.x / m1.channels() << ")"
353
<< ", which exceeds \"" << eps_expr << "\", where \""
354
<< expr1 << "\" at (" << maxLoc.y << ", " << maxLoc.x / m1.channels() << ") evaluates to " << printMatVal(m1, maxLoc) << ", \""
355
<< expr2 << "\" at (" << maxLoc.y << ", " << maxLoc.x / m1.channels() << ") evaluates to " << printMatVal(m2, maxLoc) << ", \""
356
<< eps_expr << "\" evaluates to " << eps;
357
return AssertionFailure() << msg.str();
358
}
359
360
return AssertionSuccess();
361
}
362
363
double checkSimilarity(InputArray m1, InputArray m2)
364
{
365
Mat diff;
366
matchTemplate(getMat(m1), getMat(m2), diff, TM_CCORR_NORMED);
367
return std::abs(diff.at<float>(0, 0) - 1.f);
368
}
369
370
//////////////////////////////////////////////////////////////////////
371
// Helper structs for value-parameterized tests
372
373
vector<MatType> types(int depth_start, int depth_end, int cn_start, int cn_end)
374
{
375
vector<MatType> v;
376
377
v.reserve((depth_end - depth_start + 1) * (cn_end - cn_start + 1));
378
379
for (int depth = depth_start; depth <= depth_end; ++depth)
380
{
381
for (int cn = cn_start; cn <= cn_end; ++cn)
382
{
383
v.push_back(MatType(CV_MAKE_TYPE(depth, cn)));
384
}
385
}
386
387
return v;
388
}
389
390
const vector<MatType>& all_types()
391
{
392
static vector<MatType> v = types(CV_8U, CV_64F, 1, 4);
393
394
return v;
395
}
396
397
void PrintTo(const UseRoi& useRoi, std::ostream* os)
398
{
399
if (useRoi)
400
(*os) << "sub matrix";
401
else
402
(*os) << "whole matrix";
403
}
404
405
void PrintTo(const Inverse& inverse, std::ostream* os)
406
{
407
if (inverse)
408
(*os) << "inverse";
409
else
410
(*os) << "direct";
411
}
412
413
//////////////////////////////////////////////////////////////////////
414
// Other
415
416
void dumpImage(const std::string& fileName, const Mat& image)
417
{
418
imwrite(TS::ptr()->get_data_path() + fileName, image);
419
}
420
421
void showDiff(InputArray gold_, InputArray actual_, double eps)
422
{
423
Mat gold = getMat(gold_);
424
Mat actual = getMat(actual_);
425
426
Mat diff;
427
absdiff(gold, actual, diff);
428
threshold(diff, diff, eps, 255.0, cv::THRESH_BINARY);
429
430
namedWindow("gold", WINDOW_NORMAL);
431
namedWindow("actual", WINDOW_NORMAL);
432
namedWindow("diff", WINDOW_NORMAL);
433
434
imshow("gold", gold);
435
imshow("actual", actual);
436
imshow("diff", diff);
437
438
waitKey();
439
}
440
441
namespace
442
{
443
bool keyPointsEquals(const cv::KeyPoint& p1, const cv::KeyPoint& p2)
444
{
445
const double maxPtDif = 1.0;
446
const double maxSizeDif = 1.0;
447
const double maxAngleDif = 2.0;
448
const double maxResponseDif = 0.1;
449
450
double dist = cv::norm(p1.pt - p2.pt);
451
452
if (dist < maxPtDif &&
453
fabs(p1.size - p2.size) < maxSizeDif &&
454
abs(p1.angle - p2.angle) < maxAngleDif &&
455
abs(p1.response - p2.response) < maxResponseDif &&
456
p1.octave == p2.octave &&
457
p1.class_id == p2.class_id)
458
{
459
return true;
460
}
461
462
return false;
463
}
464
465
struct KeyPointLess
466
{
467
bool operator()(const cv::KeyPoint& kp1, const cv::KeyPoint& kp2) const
468
{
469
return kp1.pt.y < kp2.pt.y || (kp1.pt.y == kp2.pt.y && kp1.pt.x < kp2.pt.x);
470
}
471
};
472
}
473
474
testing::AssertionResult assertKeyPointsEquals(const char* gold_expr, const char* actual_expr, std::vector<cv::KeyPoint>& gold, std::vector<cv::KeyPoint>& actual)
475
{
476
if (gold.size() != actual.size())
477
{
478
std::stringstream msg;
479
msg << "KeyPoints size mistmach\n"
480
<< "\"" << gold_expr << "\" : " << gold.size() << "\n"
481
<< "\"" << actual_expr << "\" : " << actual.size();
482
return AssertionFailure() << msg.str();
483
}
484
485
std::sort(actual.begin(), actual.end(), KeyPointLess());
486
std::sort(gold.begin(), gold.end(), KeyPointLess());
487
488
for (size_t i = 0; i < gold.size(); ++i)
489
{
490
const cv::KeyPoint& p1 = gold[i];
491
const cv::KeyPoint& p2 = actual[i];
492
493
if (!keyPointsEquals(p1, p2))
494
{
495
std::stringstream msg;
496
msg << "KeyPoints differ at " << i << "\n"
497
<< "\"" << gold_expr << "\" vs \"" << actual_expr << "\" : \n"
498
<< "pt : " << testing::PrintToString(p1.pt) << " vs " << testing::PrintToString(p2.pt) << "\n"
499
<< "size : " << p1.size << " vs " << p2.size << "\n"
500
<< "angle : " << p1.angle << " vs " << p2.angle << "\n"
501
<< "response : " << p1.response << " vs " << p2.response << "\n"
502
<< "octave : " << p1.octave << " vs " << p2.octave << "\n"
503
<< "class_id : " << p1.class_id << " vs " << p2.class_id;
504
return AssertionFailure() << msg.str();
505
}
506
}
507
508
return ::testing::AssertionSuccess();
509
}
510
511
int getMatchedPointsCount(std::vector<cv::KeyPoint>& gold, std::vector<cv::KeyPoint>& actual)
512
{
513
std::sort(actual.begin(), actual.end(), KeyPointLess());
514
std::sort(gold.begin(), gold.end(), KeyPointLess());
515
516
int validCount = 0;
517
518
for (size_t i = 0; i < gold.size(); ++i)
519
{
520
const cv::KeyPoint& p1 = gold[i];
521
const cv::KeyPoint& p2 = actual[i];
522
523
if (keyPointsEquals(p1, p2))
524
++validCount;
525
}
526
527
return validCount;
528
}
529
530
int getMatchedPointsCount(const std::vector<cv::KeyPoint>& keypoints1, const std::vector<cv::KeyPoint>& keypoints2, const std::vector<cv::DMatch>& matches)
531
{
532
int validCount = 0;
533
534
for (size_t i = 0; i < matches.size(); ++i)
535
{
536
const cv::DMatch& m = matches[i];
537
538
const cv::KeyPoint& p1 = keypoints1[m.queryIdx];
539
const cv::KeyPoint& p2 = keypoints2[m.trainIdx];
540
541
if (keyPointsEquals(p1, p2))
542
++validCount;
543
}
544
545
return validCount;
546
}
547
548
void printCudaInfo()
549
{
550
perf::printCudaInfo();
551
}
552
}
553
554
555
void cv::cuda::PrintTo(const DeviceInfo& info, std::ostream* os)
556
{
557
(*os) << info.name();
558
if (info.deviceID())
559
(*os) << " [ID: " << info.deviceID() << "]";
560
}
561
562