Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/imgproc/test/test_moments.cpp
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
// 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
#include "test_precomp.hpp"
42
#include "opencv2/ts/ocl_test.hpp"
43
44
namespace opencv_test { namespace {
45
46
#define OCL_TUNING_MODE 0
47
#if OCL_TUNING_MODE
48
#define OCL_TUNING_MODE_ONLY(code) code
49
#else
50
#define OCL_TUNING_MODE_ONLY(code)
51
#endif
52
53
// image moments
54
class CV_MomentsTest : public cvtest::ArrayTest
55
{
56
public:
57
CV_MomentsTest(bool try_umat);
58
59
protected:
60
61
enum { MOMENT_COUNT = 25 };
62
int prepare_test_case( int test_case_idx );
63
void prepare_to_validation( int /*test_case_idx*/ );
64
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
65
void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
66
double get_success_error_level( int test_case_idx, int i, int j );
67
void run_func();
68
bool is_binary;
69
bool try_umat_;
70
};
71
72
73
CV_MomentsTest::CV_MomentsTest(bool try_umat) :
74
try_umat_(try_umat)
75
{
76
test_array[INPUT].push_back(NULL);
77
test_array[OUTPUT].push_back(NULL);
78
test_array[REF_OUTPUT].push_back(NULL);
79
is_binary = false;
80
OCL_TUNING_MODE_ONLY(test_case_count = 10);
81
//element_wise_relative_error = false;
82
}
83
84
85
void CV_MomentsTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
86
{
87
cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
88
int depth = CV_MAT_DEPTH(type);
89
90
if( depth == CV_16U )
91
{
92
low = Scalar::all(0);
93
high = Scalar::all(1000);
94
}
95
else if( depth == CV_16S )
96
{
97
low = Scalar::all(-1000);
98
high = Scalar::all(1000);
99
}
100
else if( depth == CV_32F )
101
{
102
low = Scalar::all(-1);
103
high = Scalar::all(1);
104
}
105
}
106
107
void CV_MomentsTest::get_test_array_types_and_sizes( int test_case_idx,
108
vector<vector<Size> >& sizes, vector<vector<int> >& types )
109
{
110
RNG& rng = ts->get_rng();
111
cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
112
int depth = cvtest::randInt(rng) % 4;
113
depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : depth == 2 ? CV_16S : CV_32F;
114
115
is_binary = cvtest::randInt(rng) % 2 != 0;
116
117
OCL_TUNING_MODE_ONLY(
118
depth = CV_8U;
119
is_binary = false;
120
sizes[INPUT][0] = Size(1024,768)
121
);
122
123
types[INPUT][0] = CV_MAKETYPE(depth, 1);
124
types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;
125
sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(MOMENT_COUNT,1);
126
if(CV_MAT_DEPTH(types[INPUT][0])>=CV_32S)
127
sizes[INPUT][0].width = MAX(sizes[INPUT][0].width, 3);
128
129
cvmat_allowed = true;
130
}
131
132
133
double CV_MomentsTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
134
{
135
int depth = test_mat[INPUT][0].depth();
136
return depth != CV_32F ? FLT_EPSILON*10 : FLT_EPSILON*100;
137
}
138
139
int CV_MomentsTest::prepare_test_case( int test_case_idx )
140
{
141
int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
142
return code;
143
}
144
145
146
void CV_MomentsTest::run_func()
147
{
148
CvMoments* m = (CvMoments*)test_mat[OUTPUT][0].ptr<double>();
149
double* others = (double*)(m + 1);
150
if (try_umat_)
151
{
152
UMat u;
153
test_mat[INPUT][0].clone().copyTo(u);
154
OCL_TUNING_MODE_ONLY(
155
static double ttime = 0;
156
static int ncalls = 0;
157
moments(u, is_binary != 0);
158
double t = (double)getTickCount());
159
Moments new_m = moments(u, is_binary != 0);
160
OCL_TUNING_MODE_ONLY(
161
ttime += (double)getTickCount() - t;
162
ncalls++;
163
printf("%g\n", ttime/ncalls/u.total()));
164
*m = cvMoments(new_m);
165
}
166
else
167
cvMoments( test_array[INPUT][0], m, is_binary );
168
169
others[0] = cvGetNormalizedCentralMoment( m, 2, 0 );
170
others[1] = cvGetNormalizedCentralMoment( m, 1, 1 );
171
others[2] = cvGetNormalizedCentralMoment( m, 0, 2 );
172
others[3] = cvGetNormalizedCentralMoment( m, 3, 0 );
173
others[4] = cvGetNormalizedCentralMoment( m, 2, 1 );
174
others[5] = cvGetNormalizedCentralMoment( m, 1, 2 );
175
others[6] = cvGetNormalizedCentralMoment( m, 0, 3 );
176
}
177
178
179
void CV_MomentsTest::prepare_to_validation( int /*test_case_idx*/ )
180
{
181
Mat& src = test_mat[INPUT][0];
182
CvMoments m = cvMoments();
183
double* mdata = test_mat[REF_OUTPUT][0].ptr<double>();
184
int depth = src.depth();
185
int cn = src.channels();
186
int i, y, x, cols = src.cols;
187
double xc = 0., yc = 0.;
188
189
int coi = 0;
190
for( y = 0; y < src.rows; y++ )
191
{
192
double s0 = 0, s1 = 0, s2 = 0, s3 = 0;
193
uchar* ptr = src.ptr(y);
194
for( x = 0; x < cols; x++ )
195
{
196
double val;
197
if( depth == CV_8U )
198
val = ptr[x*cn + coi];
199
else if( depth == CV_16U )
200
val = ((ushort*)ptr)[x*cn + coi];
201
else if( depth == CV_16S )
202
val = ((short*)ptr)[x*cn + coi];
203
else
204
val = ((float*)ptr)[x*cn + coi];
205
206
if( is_binary )
207
val = val != 0;
208
209
s0 += val;
210
s1 += val*x;
211
s2 += val*x*x;
212
s3 += ((val*x)*x)*x;
213
}
214
215
m.m00 += s0;
216
m.m01 += s0*y;
217
m.m02 += (s0*y)*y;
218
m.m03 += ((s0*y)*y)*y;
219
220
m.m10 += s1;
221
m.m11 += s1*y;
222
m.m12 += (s1*y)*y;
223
224
m.m20 += s2;
225
m.m21 += s2*y;
226
227
m.m30 += s3;
228
}
229
230
if( m.m00 != 0 )
231
{
232
xc = m.m10/m.m00, yc = m.m01/m.m00;
233
m.inv_sqrt_m00 = 1./sqrt(fabs(m.m00));
234
}
235
236
for( y = 0; y < src.rows; y++ )
237
{
238
double s0 = 0, s1 = 0, s2 = 0, s3 = 0, y1 = y - yc;
239
uchar* ptr = src.ptr(y);
240
for( x = 0; x < cols; x++ )
241
{
242
double val, x1 = x - xc;
243
if( depth == CV_8U )
244
val = ptr[x*cn + coi];
245
else if( depth == CV_16U )
246
val = ((ushort*)ptr)[x*cn + coi];
247
else if( depth == CV_16S )
248
val = ((short*)ptr)[x*cn + coi];
249
else
250
val = ((float*)ptr)[x*cn + coi];
251
252
if( is_binary )
253
val = val != 0;
254
255
s0 += val;
256
s1 += val*x1;
257
s2 += val*x1*x1;
258
s3 += ((val*x1)*x1)*x1;
259
}
260
261
m.mu02 += s0*y1*y1;
262
m.mu03 += ((s0*y1)*y1)*y1;
263
264
m.mu11 += s1*y1;
265
m.mu12 += (s1*y1)*y1;
266
267
m.mu20 += s2;
268
m.mu21 += s2*y1;
269
270
m.mu30 += s3;
271
}
272
273
memcpy( mdata, &m, sizeof(m));
274
mdata += sizeof(m)/sizeof(m.m00);
275
276
/* calc normalized moments */
277
{
278
double inv_m00 = m.inv_sqrt_m00*m.inv_sqrt_m00;
279
double s2 = inv_m00*inv_m00; /* 1./(m00 ^ (2/2 + 1)) */
280
double s3 = s2*m.inv_sqrt_m00; /* 1./(m00 ^ (3/2 + 1)) */
281
282
mdata[0] = m.mu20 * s2;
283
mdata[1] = m.mu11 * s2;
284
mdata[2] = m.mu02 * s2;
285
286
mdata[3] = m.mu30 * s3;
287
mdata[4] = m.mu21 * s3;
288
mdata[5] = m.mu12 * s3;
289
mdata[6] = m.mu03 * s3;
290
}
291
292
double* a = test_mat[REF_OUTPUT][0].ptr<double>();
293
double* b = test_mat[OUTPUT][0].ptr<double>();
294
for( i = 0; i < MOMENT_COUNT; i++ )
295
{
296
if( fabs(a[i]) < 1e-3 )
297
a[i] = 0;
298
if( fabs(b[i]) < 1e-3 )
299
b[i] = 0;
300
}
301
}
302
303
304
// Hu invariants
305
class CV_HuMomentsTest : public cvtest::ArrayTest
306
{
307
public:
308
CV_HuMomentsTest();
309
310
protected:
311
312
enum { MOMENT_COUNT = 18, HU_MOMENT_COUNT = 7 };
313
314
int prepare_test_case( int test_case_idx );
315
void prepare_to_validation( int /*test_case_idx*/ );
316
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
317
void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
318
double get_success_error_level( int test_case_idx, int i, int j );
319
void run_func();
320
};
321
322
323
CV_HuMomentsTest::CV_HuMomentsTest()
324
{
325
test_array[INPUT].push_back(NULL);
326
test_array[OUTPUT].push_back(NULL);
327
test_array[REF_OUTPUT].push_back(NULL);
328
}
329
330
331
void CV_HuMomentsTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
332
{
333
cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
334
low = Scalar::all(-10000);
335
high = Scalar::all(10000);
336
}
337
338
339
void CV_HuMomentsTest::get_test_array_types_and_sizes( int test_case_idx,
340
vector<vector<Size> >& sizes, vector<vector<int> >& types )
341
{
342
cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
343
types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;
344
sizes[INPUT][0] = cvSize(MOMENT_COUNT,1);
345
sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(HU_MOMENT_COUNT,1);
346
}
347
348
349
double CV_HuMomentsTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
350
{
351
return FLT_EPSILON;
352
}
353
354
355
356
int CV_HuMomentsTest::prepare_test_case( int test_case_idx )
357
{
358
int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
359
if( code > 0 )
360
{
361
// ...
362
}
363
364
return code;
365
}
366
367
368
void CV_HuMomentsTest::run_func()
369
{
370
cvGetHuMoments( test_mat[INPUT][0].ptr<CvMoments>(),
371
test_mat[OUTPUT][0].ptr<CvHuMoments>() );
372
}
373
374
375
void CV_HuMomentsTest::prepare_to_validation( int /*test_case_idx*/ )
376
{
377
CvMoments* m = test_mat[INPUT][0].ptr<CvMoments>();
378
CvHuMoments* hu = test_mat[REF_OUTPUT][0].ptr<CvHuMoments>();
379
380
double inv_m00 = m->inv_sqrt_m00*m->inv_sqrt_m00;
381
double s2 = inv_m00*inv_m00; /* 1./(m00 ^ (2/2 + 1)) */
382
double s3 = s2*m->inv_sqrt_m00; /* 1./(m00 ^ (3/2 + 1)) */
383
384
double nu20 = m->mu20 * s2;
385
double nu11 = m->mu11 * s2;
386
double nu02 = m->mu02 * s2;
387
388
double nu30 = m->mu30 * s3;
389
double nu21 = m->mu21 * s3;
390
double nu12 = m->mu12 * s3;
391
double nu03 = m->mu03 * s3;
392
393
#undef sqr
394
#define sqr(a) ((a)*(a))
395
396
hu->hu1 = nu20 + nu02;
397
hu->hu2 = sqr(nu20 - nu02) + 4*sqr(nu11);
398
hu->hu3 = sqr(nu30 - 3*nu12) + sqr(3*nu21 - nu03);
399
hu->hu4 = sqr(nu30 + nu12) + sqr(nu21 + nu03);
400
hu->hu5 = (nu30 - 3*nu12)*(nu30 + nu12)*(sqr(nu30 + nu12) - 3*sqr(nu21 + nu03)) +
401
(3*nu21 - nu03)*(nu21 + nu03)*(3*sqr(nu30 + nu12) - sqr(nu21 + nu03));
402
hu->hu6 = (nu20 - nu02)*(sqr(nu30 + nu12) - sqr(nu21 + nu03)) +
403
4*nu11*(nu30 + nu12)*(nu21 + nu03);
404
hu->hu7 = (3*nu21 - nu03)*(nu30 + nu12)*(sqr(nu30 + nu12) - 3*sqr(nu21 + nu03)) +
405
(3*nu12 - nu30)*(nu21 + nu03)*(3*sqr(nu30 + nu12) - sqr(nu21 + nu03));
406
}
407
408
409
TEST(Imgproc_Moments, accuracy) { CV_MomentsTest test(false); test.safe_run(); }
410
OCL_TEST(Imgproc_Moments, accuracy) { CV_MomentsTest test(true); test.safe_run(); }
411
TEST(Imgproc_HuMoments, accuracy) { CV_HuMomentsTest test; test.safe_run(); }
412
413
class CV_SmallContourMomentTest : public cvtest::BaseTest
414
{
415
public:
416
CV_SmallContourMomentTest() {}
417
~CV_SmallContourMomentTest() {}
418
protected:
419
void run(int)
420
{
421
try
422
{
423
vector<Point> points;
424
points.push_back(Point(50, 56));
425
points.push_back(Point(53, 53));
426
points.push_back(Point(46, 54));
427
points.push_back(Point(49, 51));
428
429
Moments m = moments(points, false);
430
double area = contourArea(points);
431
432
CV_Assert( m.m00 == 0 && m.m01 == 0 && m.m10 == 0 && area == 0 );
433
}
434
catch(...)
435
{
436
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
437
}
438
}
439
};
440
441
TEST(Imgproc_ContourMoment, small) { CV_SmallContourMomentTest test; test.safe_run(); }
442
443
}} // namespace
444
445