Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/dnn/test/test_common.hpp
16354 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) 2013, OpenCV Foundation, 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 the copyright holders 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
#ifndef __OPENCV_TEST_COMMON_HPP__
43
#define __OPENCV_TEST_COMMON_HPP__
44
45
#ifdef HAVE_OPENCL
46
#include "opencv2/core/ocl.hpp"
47
#endif
48
49
namespace cv { namespace dnn {
50
CV__DNN_INLINE_NS_BEGIN
51
static inline void PrintTo(const cv::dnn::Backend& v, std::ostream* os)
52
{
53
switch (v) {
54
case DNN_BACKEND_DEFAULT: *os << "DEFAULT"; return;
55
case DNN_BACKEND_HALIDE: *os << "HALIDE"; return;
56
case DNN_BACKEND_INFERENCE_ENGINE: *os << "DLIE"; return;
57
case DNN_BACKEND_OPENCV: *os << "OCV"; return;
58
case DNN_BACKEND_VKCOM: *os << "VKCOM"; return;
59
} // don't use "default:" to emit compiler warnings
60
*os << "DNN_BACKEND_UNKNOWN(" << v << ")";
61
}
62
63
static inline void PrintTo(const cv::dnn::Target& v, std::ostream* os)
64
{
65
switch (v) {
66
case DNN_TARGET_CPU: *os << "CPU"; return;
67
case DNN_TARGET_OPENCL: *os << "OCL"; return;
68
case DNN_TARGET_OPENCL_FP16: *os << "OCL_FP16"; return;
69
case DNN_TARGET_MYRIAD: *os << "MYRIAD"; return;
70
case DNN_TARGET_VULKAN: *os << "VULKAN"; return;
71
} // don't use "default:" to emit compiler warnings
72
*os << "DNN_TARGET_UNKNOWN(" << v << ")";
73
}
74
75
using opencv_test::tuple;
76
using opencv_test::get;
77
static inline void PrintTo(const tuple<cv::dnn::Backend, cv::dnn::Target> v, std::ostream* os)
78
{
79
PrintTo(get<0>(v), os);
80
*os << "/";
81
PrintTo(get<1>(v), os);
82
}
83
84
CV__DNN_INLINE_NS_END
85
}} // namespace
86
87
88
static inline const std::string &getOpenCVExtraDir()
89
{
90
return cvtest::TS::ptr()->get_data_path();
91
}
92
93
static inline void normAssert(cv::InputArray ref, cv::InputArray test, const char *comment = "",
94
double l1 = 0.00001, double lInf = 0.0001)
95
{
96
double normL1 = cvtest::norm(ref, test, cv::NORM_L1) / ref.getMat().total();
97
EXPECT_LE(normL1, l1) << comment;
98
99
double normInf = cvtest::norm(ref, test, cv::NORM_INF);
100
EXPECT_LE(normInf, lInf) << comment;
101
}
102
103
static std::vector<cv::Rect2d> matToBoxes(const cv::Mat& m)
104
{
105
EXPECT_EQ(m.type(), CV_32FC1);
106
EXPECT_EQ(m.dims, 2);
107
EXPECT_EQ(m.cols, 4);
108
109
std::vector<cv::Rect2d> boxes(m.rows);
110
for (int i = 0; i < m.rows; ++i)
111
{
112
CV_Assert(m.row(i).isContinuous());
113
const float* data = m.ptr<float>(i);
114
double l = data[0], t = data[1], r = data[2], b = data[3];
115
boxes[i] = cv::Rect2d(l, t, r - l, b - t);
116
}
117
return boxes;
118
}
119
120
static inline void normAssertDetections(const std::vector<int>& refClassIds,
121
const std::vector<float>& refScores,
122
const std::vector<cv::Rect2d>& refBoxes,
123
const std::vector<int>& testClassIds,
124
const std::vector<float>& testScores,
125
const std::vector<cv::Rect2d>& testBoxes,
126
const char *comment = "", double confThreshold = 0.0,
127
double scores_diff = 1e-5, double boxes_iou_diff = 1e-4)
128
{
129
std::vector<bool> matchedRefBoxes(refBoxes.size(), false);
130
for (int i = 0; i < testBoxes.size(); ++i)
131
{
132
double testScore = testScores[i];
133
if (testScore < confThreshold)
134
continue;
135
136
int testClassId = testClassIds[i];
137
const cv::Rect2d& testBox = testBoxes[i];
138
bool matched = false;
139
for (int j = 0; j < refBoxes.size() && !matched; ++j)
140
{
141
if (!matchedRefBoxes[j] && testClassId == refClassIds[j] &&
142
std::abs(testScore - refScores[j]) < scores_diff)
143
{
144
double interArea = (testBox & refBoxes[j]).area();
145
double iou = interArea / (testBox.area() + refBoxes[j].area() - interArea);
146
if (std::abs(iou - 1.0) < boxes_iou_diff)
147
{
148
matched = true;
149
matchedRefBoxes[j] = true;
150
}
151
}
152
}
153
if (!matched)
154
std::cout << cv::format("Unmatched prediction: class %d score %f box ",
155
testClassId, testScore) << testBox << std::endl;
156
EXPECT_TRUE(matched) << comment;
157
}
158
159
// Check unmatched reference detections.
160
for (int i = 0; i < refBoxes.size(); ++i)
161
{
162
if (!matchedRefBoxes[i] && refScores[i] > confThreshold)
163
{
164
std::cout << cv::format("Unmatched reference: class %d score %f box ",
165
refClassIds[i], refScores[i]) << refBoxes[i] << std::endl;
166
EXPECT_LE(refScores[i], confThreshold) << comment;
167
}
168
}
169
}
170
171
// For SSD-based object detection networks which produce output of shape 1x1xNx7
172
// where N is a number of detections and an every detection is represented by
173
// a vector [batchId, classId, confidence, left, top, right, bottom].
174
static inline void normAssertDetections(cv::Mat ref, cv::Mat out, const char *comment = "",
175
double confThreshold = 0.0, double scores_diff = 1e-5,
176
double boxes_iou_diff = 1e-4)
177
{
178
CV_Assert(ref.total() % 7 == 0);
179
CV_Assert(out.total() % 7 == 0);
180
ref = ref.reshape(1, ref.total() / 7);
181
out = out.reshape(1, out.total() / 7);
182
183
cv::Mat refClassIds, testClassIds;
184
ref.col(1).convertTo(refClassIds, CV_32SC1);
185
out.col(1).convertTo(testClassIds, CV_32SC1);
186
std::vector<float> refScores(ref.col(2)), testScores(out.col(2));
187
std::vector<cv::Rect2d> refBoxes = matToBoxes(ref.colRange(3, 7));
188
std::vector<cv::Rect2d> testBoxes = matToBoxes(out.colRange(3, 7));
189
normAssertDetections(refClassIds, refScores, refBoxes, testClassIds, testScores,
190
testBoxes, comment, confThreshold, scores_diff, boxes_iou_diff);
191
}
192
193
static inline bool checkMyriadTarget()
194
{
195
#ifndef HAVE_INF_ENGINE
196
return false;
197
#else
198
cv::dnn::Net net;
199
cv::dnn::LayerParams lp;
200
net.addLayerToPrev("testLayer", "Identity", lp);
201
net.setPreferableBackend(cv::dnn::DNN_BACKEND_INFERENCE_ENGINE);
202
net.setPreferableTarget(cv::dnn::DNN_TARGET_MYRIAD);
203
static int inpDims[] = {1, 2, 3, 4};
204
net.setInput(cv::Mat(4, &inpDims[0], CV_32FC1, cv::Scalar(0)));
205
try
206
{
207
net.forward();
208
}
209
catch(...)
210
{
211
return false;
212
}
213
return true;
214
#endif
215
}
216
217
static inline bool readFileInMemory(const std::string& filename, std::string& content)
218
{
219
std::ios::openmode mode = std::ios::in | std::ios::binary;
220
std::ifstream ifs(filename.c_str(), mode);
221
if (!ifs.is_open())
222
return false;
223
224
content.clear();
225
226
ifs.seekg(0, std::ios::end);
227
content.reserve(ifs.tellg());
228
ifs.seekg(0, std::ios::beg);
229
230
content.assign((std::istreambuf_iterator<char>(ifs)),
231
std::istreambuf_iterator<char>());
232
233
return true;
234
}
235
236
namespace opencv_test {
237
238
using namespace cv::dnn;
239
240
static testing::internal::ParamGenerator<tuple<Backend, Target> > dnnBackendsAndTargets(
241
bool withInferenceEngine = true,
242
bool withHalide = false,
243
bool withCpuOCV = true,
244
bool withVkCom = true
245
)
246
{
247
std::vector<tuple<Backend, Target> > targets;
248
#ifdef HAVE_HALIDE
249
if (withHalide)
250
{
251
targets.push_back(make_tuple(DNN_BACKEND_HALIDE, DNN_TARGET_CPU));
252
#ifdef HAVE_OPENCL
253
if (cv::ocl::useOpenCL())
254
targets.push_back(make_tuple(DNN_BACKEND_HALIDE, DNN_TARGET_OPENCL));
255
#endif
256
}
257
#endif
258
#ifdef HAVE_INF_ENGINE
259
if (withInferenceEngine)
260
{
261
targets.push_back(make_tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_CPU));
262
#ifdef HAVE_OPENCL
263
if (cv::ocl::useOpenCL() && ocl::Device::getDefault().isIntel())
264
{
265
targets.push_back(make_tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL));
266
targets.push_back(make_tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL_FP16));
267
}
268
#endif
269
if (checkMyriadTarget())
270
targets.push_back(make_tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_MYRIAD));
271
}
272
#endif
273
if (withCpuOCV)
274
targets.push_back(make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU));
275
#ifdef HAVE_OPENCL
276
if (cv::ocl::useOpenCL())
277
{
278
targets.push_back(make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL));
279
targets.push_back(make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL_FP16));
280
}
281
#endif
282
#ifdef HAVE_VULKAN
283
if (withVkCom)
284
targets.push_back(make_tuple(DNN_BACKEND_VKCOM, DNN_TARGET_VULKAN));
285
#endif
286
if (targets.empty()) // validate at least CPU mode
287
targets.push_back(make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU));
288
return testing::ValuesIn(targets);
289
}
290
291
} // namespace
292
293
#endif
294
295