Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/core/test/test_dxt.cpp
16337 views
1
// This file is part of OpenCV project.
2
// It is subject to the license terms in the LICENSE file found in the top-level directory
3
// of this distribution and at http://opencv.org/license.html.
4
#include "test_precomp.hpp"
5
6
namespace opencv_test { namespace {
7
8
static Mat initDFTWave( int n, bool inv )
9
{
10
int i;
11
double angle = (inv ? 1 : -1)*CV_PI*2/n;
12
Complexd wi, w1;
13
Mat wave(1, n, CV_64FC2);
14
Complexd* w = wave.ptr<Complexd>();
15
16
w1.re = cos(angle);
17
w1.im = sin(angle);
18
w[0].re = wi.re = 1.;
19
w[0].im = wi.im = 0.;
20
21
for( i = 1; i < n; i++ )
22
{
23
double t = wi.re*w1.re - wi.im*w1.im;
24
wi.im = wi.re*w1.im + wi.im*w1.re;
25
wi.re = t;
26
w[i] = wi;
27
}
28
29
return wave;
30
}
31
32
33
static void DFT_1D( const Mat& _src, Mat& _dst, int flags, const Mat& _wave=Mat())
34
{
35
_dst.create(_src.size(), _src.type());
36
int i, j, k, n = _dst.cols + _dst.rows - 1;
37
Mat wave = _wave;
38
double scale = (flags & DFT_SCALE) ? 1./n : 1.;
39
size_t esz = _src.elemSize();
40
size_t srcstep = esz, dststep = esz;
41
const uchar* src0 = _src.ptr();
42
uchar* dst0 = _dst.ptr();
43
44
CV_Assert( _src.cols + _src.rows - 1 == n );
45
46
if( wave.empty() )
47
wave = initDFTWave( n, (flags & DFT_INVERSE) != 0 );
48
49
const Complexd* w = wave.ptr<Complexd>();
50
if( !_src.isContinuous() )
51
srcstep = _src.step;
52
if( !_dst.isContinuous() )
53
dststep = _dst.step;
54
55
if( _src.type() == CV_32FC2 )
56
{
57
for( i = 0; i < n; i++ )
58
{
59
Complexf* dst = (Complexf*)(dst0 + i*dststep);
60
Complexd sum(0,0);
61
int delta = i;
62
k = 0;
63
64
for( j = 0; j < n; j++ )
65
{
66
const Complexf* src = (const Complexf*)(src0 + j*srcstep);
67
sum.re += src->re*w[k].re - src->im*w[k].im;
68
sum.im += src->re*w[k].im + src->im*w[k].re;
69
k += delta;
70
k -= (k >= n ? n : 0);
71
}
72
73
dst->re = (float)(sum.re*scale);
74
dst->im = (float)(sum.im*scale);
75
}
76
}
77
else if( _src.type() == CV_64FC2 )
78
{
79
for( i = 0; i < n; i++ )
80
{
81
Complexd* dst = (Complexd*)(dst0 + i*dststep);
82
Complexd sum(0,0);
83
int delta = i;
84
k = 0;
85
86
for( j = 0; j < n; j++ )
87
{
88
const Complexd* src = (const Complexd*)(src0 + j*srcstep);
89
sum.re += src->re*w[k].re - src->im*w[k].im;
90
sum.im += src->re*w[k].im + src->im*w[k].re;
91
k += delta;
92
k -= (k >= n ? n : 0);
93
}
94
95
dst->re = sum.re*scale;
96
dst->im = sum.im*scale;
97
}
98
}
99
else
100
CV_Error(CV_StsUnsupportedFormat, "");
101
}
102
103
104
static void DFT_2D( const Mat& src, Mat& dst, int flags )
105
{
106
const int cn = 2;
107
int i;
108
dst.create(src.size(), src.type());
109
Mat tmp( src.cols, src.rows, src.type());
110
Mat wave = initDFTWave( dst.cols, (flags & DFT_INVERSE) != 0 );
111
112
// 1. row-wise transform
113
for( i = 0; i < dst.rows; i++ )
114
{
115
Mat srci = src.row(i).reshape(cn, src.cols), dsti = tmp.col(i);
116
DFT_1D(srci, dsti, flags, wave );
117
}
118
119
if( (flags & DFT_ROWS) == 0 )
120
{
121
if( dst.cols != dst.rows )
122
wave = initDFTWave( dst.rows, (flags & DFT_INVERSE) != 0 );
123
124
// 2. column-wise transform
125
for( i = 0; i < dst.cols; i++ )
126
{
127
Mat srci = tmp.row(i).reshape(cn, tmp.cols), dsti = dst.col(i);
128
DFT_1D(srci, dsti, flags, wave );
129
}
130
}
131
else
132
cvtest::transpose(tmp, dst);
133
}
134
135
136
static Mat initDCTWave( int n, bool inv )
137
{
138
int i, k;
139
double angle = CV_PI*0.5/n;
140
Mat wave(n, n, CV_64F);
141
142
double scale = sqrt(1./n);
143
for( k = 0; k < n; k++ )
144
wave.at<double>(0, k) = scale;
145
scale *= sqrt(2.);
146
for( i = 1; i < n; i++ )
147
for( k = 0; k < n; k++ )
148
wave.at<double>(i, k) = scale*cos( angle*i*(2*k + 1) );
149
150
if( inv )
151
cv::transpose( wave, wave );
152
153
return wave;
154
}
155
156
157
static void DCT_1D( const Mat& _src, Mat& _dst, int flags, const Mat& _wave=Mat() )
158
{
159
_dst.create( _src.size(), _src.type() );
160
int i, j, n = _dst.cols + _dst.rows - 1;
161
Mat wave = _wave;
162
int srcstep = 1, dststep = 1;
163
double* w;
164
165
CV_Assert( _src.cols + _src.rows - 1 == n);
166
167
if( wave.empty() )
168
wave = initDCTWave( n, (flags & DFT_INVERSE) != 0 );
169
w = wave.ptr<double>();
170
171
if( !_src.isContinuous() )
172
srcstep = (int)(_src.step/_src.elemSize());
173
if( !_dst.isContinuous() )
174
dststep = (int)(_dst.step/_dst.elemSize());
175
176
if( _src.type() == CV_32FC1 )
177
{
178
float *dst = _dst.ptr<float>();
179
180
for( i = 0; i < n; i++, dst += dststep )
181
{
182
const float* src = _src.ptr<float>();
183
double sum = 0;
184
185
for( j = 0; j < n; j++, src += srcstep )
186
sum += src[0]*w[j];
187
w += n;
188
dst[0] = (float)sum;
189
}
190
}
191
else if( _src.type() == CV_64FC1 )
192
{
193
double *dst = _dst.ptr<double>();
194
195
for( i = 0; i < n; i++, dst += dststep )
196
{
197
const double* src = _src.ptr<double>();
198
double sum = 0;
199
200
for( j = 0; j < n; j++, src += srcstep )
201
sum += src[0]*w[j];
202
w += n;
203
dst[0] = sum;
204
}
205
}
206
else
207
assert(0);
208
}
209
210
211
static void DCT_2D( const Mat& src, Mat& dst, int flags )
212
{
213
const int cn = 1;
214
int i;
215
dst.create( src.size(), src.type() );
216
Mat tmp(dst.cols, dst.rows, dst.type() );
217
Mat wave = initDCTWave( dst.cols, (flags & DCT_INVERSE) != 0 );
218
219
// 1. row-wise transform
220
for( i = 0; i < dst.rows; i++ )
221
{
222
Mat srci = src.row(i).reshape(cn, src.cols);
223
Mat dsti = tmp.col(i);
224
DCT_1D(srci, dsti, flags, wave);
225
}
226
227
if( (flags & DCT_ROWS) == 0 )
228
{
229
if( dst.cols != dst.rows )
230
wave = initDCTWave( dst.rows, (flags & DCT_INVERSE) != 0 );
231
232
// 2. column-wise transform
233
for( i = 0; i < dst.cols; i++ )
234
{
235
Mat srci = tmp.row(i).reshape(cn, tmp.cols);
236
Mat dsti = dst.col(i);
237
DCT_1D( srci, dsti, flags, wave );
238
}
239
}
240
else
241
cvtest::transpose( tmp, dst );
242
}
243
244
245
static void convertFromCCS( const Mat& _src0, const Mat& _src1, Mat& _dst, int flags )
246
{
247
if( _dst.rows > 1 && (_dst.cols > 1 || (flags & DFT_ROWS)) )
248
{
249
int i, count = _dst.rows, len = _dst.cols;
250
bool is2d = (flags & DFT_ROWS) == 0;
251
Mat src0row, src1row, dstrow;
252
for( i = 0; i < count; i++ )
253
{
254
int j = !is2d || i == 0 ? i : count - i;
255
src0row = _src0.row(i);
256
src1row = _src1.row(j);
257
dstrow = _dst.row(i);
258
convertFromCCS( src0row, src1row, dstrow, 0 );
259
}
260
261
if( is2d )
262
{
263
src0row = _src0.col(0);
264
dstrow = _dst.col(0);
265
convertFromCCS( src0row, src0row, dstrow, 0 );
266
if( (len & 1) == 0 )
267
{
268
src0row = _src0.col(_src0.cols - 1);
269
dstrow = _dst.col(len/2);
270
convertFromCCS( src0row, src0row, dstrow, 0 );
271
}
272
}
273
}
274
else
275
{
276
int i, n = _dst.cols + _dst.rows - 1, n2 = (n+1) >> 1;
277
int cn = _src0.channels();
278
int srcstep = cn, dststep = 1;
279
280
if( !_dst.isContinuous() )
281
dststep = (int)(_dst.step/_dst.elemSize());
282
283
if( !_src0.isContinuous() )
284
srcstep = (int)(_src0.step/_src0.elemSize1());
285
286
if( _dst.depth() == CV_32F )
287
{
288
Complexf* dst = _dst.ptr<Complexf>();
289
const float* src0 = _src0.ptr<float>();
290
const float* src1 = _src1.ptr<float>();
291
int delta0, delta1;
292
293
dst->re = src0[0];
294
dst->im = 0;
295
296
if( (n & 1) == 0 )
297
{
298
dst[n2*dststep].re = src0[(cn == 1 ? n-1 : n2)*srcstep];
299
dst[n2*dststep].im = 0;
300
}
301
302
delta0 = srcstep;
303
delta1 = delta0 + (cn == 1 ? srcstep : 1);
304
if( cn == 1 )
305
srcstep *= 2;
306
307
for( i = 1; i < n2; i++, delta0 += srcstep, delta1 += srcstep )
308
{
309
float t0 = src0[delta0];
310
float t1 = src0[delta1];
311
312
dst[i*dststep].re = t0;
313
dst[i*dststep].im = t1;
314
315
t0 = src1[delta0];
316
t1 = -src1[delta1];
317
318
dst[(n-i)*dststep].re = t0;
319
dst[(n-i)*dststep].im = t1;
320
}
321
}
322
else
323
{
324
Complexd* dst = _dst.ptr<Complexd>();
325
const double* src0 = _src0.ptr<double>();
326
const double* src1 = _src1.ptr<double>();
327
int delta0, delta1;
328
329
dst->re = src0[0];
330
dst->im = 0;
331
332
if( (n & 1) == 0 )
333
{
334
dst[n2*dststep].re = src0[(cn == 1 ? n-1 : n2)*srcstep];
335
dst[n2*dststep].im = 0;
336
}
337
338
delta0 = srcstep;
339
delta1 = delta0 + (cn == 1 ? srcstep : 1);
340
if( cn == 1 )
341
srcstep *= 2;
342
343
for( i = 1; i < n2; i++, delta0 += srcstep, delta1 += srcstep )
344
{
345
double t0 = src0[delta0];
346
double t1 = src0[delta1];
347
348
dst[i*dststep].re = t0;
349
dst[i*dststep].im = t1;
350
351
t0 = src1[delta0];
352
t1 = -src1[delta1];
353
354
dst[(n-i)*dststep].re = t0;
355
dst[(n-i)*dststep].im = t1;
356
}
357
}
358
}
359
}
360
361
362
static void fixCCS( Mat& mat, int cols, int flags )
363
{
364
int i, rows = mat.rows;
365
int rows2 = (flags & DFT_ROWS) ? rows : rows/2 + 1, cols2 = cols/2 + 1;
366
367
CV_Assert( cols2 == mat.cols );
368
369
if( mat.type() == CV_32FC2 )
370
{
371
for( i = 0; i < rows2; i++ )
372
{
373
Complexf* row = mat.ptr<Complexf>(i);
374
if( (flags & DFT_ROWS) || i == 0 || (i == rows2 - 1 && rows % 2 == 0) )
375
{
376
row[0].im = 0;
377
if( cols % 2 == 0 )
378
row[cols2-1].im = 0;
379
}
380
else
381
{
382
Complexf* row2 = mat.ptr<Complexf>(rows-i);
383
row2[0].re = row[0].re;
384
row2[0].im = -row[0].im;
385
386
if( cols % 2 == 0 )
387
{
388
row2[cols2-1].re = row[cols2-1].re;
389
row2[cols2-1].im = -row[cols2-1].im;
390
}
391
}
392
}
393
}
394
else if( mat.type() == CV_64FC2 )
395
{
396
for( i = 0; i < rows2; i++ )
397
{
398
Complexd* row = mat.ptr<Complexd>(i);
399
if( (flags & DFT_ROWS) || i == 0 || (i == rows2 - 1 && rows % 2 == 0) )
400
{
401
row[0].im = 0;
402
if( cols % 2 == 0 )
403
row[cols2-1].im = 0;
404
}
405
else
406
{
407
Complexd* row2 = mat.ptr<Complexd>(rows-i);
408
row2[0].re = row[0].re;
409
row2[0].im = -row[0].im;
410
411
if( cols % 2 == 0 )
412
{
413
row2[cols2-1].re = row[cols2-1].re;
414
row2[cols2-1].im = -row[cols2-1].im;
415
}
416
}
417
}
418
}
419
}
420
421
static void mulComplex( const Mat& src1, const Mat& src2, Mat& dst, int flags )
422
{
423
dst.create(src1.rows, src1.cols, src1.type());
424
int i, j, depth = src1.depth(), cols = src1.cols*2;
425
426
CV_Assert( src1.size == src2.size && src1.type() == src2.type() &&
427
(src1.type() == CV_32FC2 || src1.type() == CV_64FC2) );
428
429
const Mat* src1_ = &src1;
430
Mat src1_tmp;
431
if (dst.data == src1.data)
432
{
433
src1_tmp = src1.clone();
434
src1_ = &src1_tmp;
435
}
436
const Mat* src2_ = &src2;
437
Mat src2_tmp;
438
if (dst.data == src2.data)
439
{
440
src2_tmp = src2.clone();
441
src2_ = &src2_tmp;
442
}
443
444
for( i = 0; i < dst.rows; i++ )
445
{
446
if( depth == CV_32F )
447
{
448
const float* a = src1_->ptr<float>(i);
449
const float* b = src2_->ptr<float>(i);
450
float* c = dst.ptr<float>(i);
451
452
if( !(flags & CV_DXT_MUL_CONJ) )
453
for( j = 0; j < cols; j += 2 )
454
{
455
double re = (double)a[j]*(double)b[j] - (double)a[j+1]*(double)b[j+1];
456
double im = (double)a[j+1]*(double)b[j] + (double)a[j]*(double)b[j+1];
457
458
c[j] = (float)re;
459
c[j+1] = (float)im;
460
}
461
else
462
for( j = 0; j < cols; j += 2 )
463
{
464
double re = (double)a[j]*(double)b[j] + (double)a[j+1]*(double)b[j+1];
465
double im = (double)a[j+1]*(double)b[j] - (double)a[j]*(double)b[j+1];
466
467
c[j] = (float)re;
468
c[j+1] = (float)im;
469
}
470
}
471
else
472
{
473
const double* a = src1_->ptr<double>(i);
474
const double* b = src2_->ptr<double>(i);
475
double* c = dst.ptr<double>(i);
476
477
if( !(flags & CV_DXT_MUL_CONJ) )
478
for( j = 0; j < cols; j += 2 )
479
{
480
double re = a[j]*b[j] - a[j+1]*b[j+1];
481
double im = a[j+1]*b[j] + a[j]*b[j+1];
482
483
c[j] = re;
484
c[j+1] = im;
485
}
486
else
487
for( j = 0; j < cols; j += 2 )
488
{
489
double re = a[j]*b[j] + a[j+1]*b[j+1];
490
double im = a[j+1]*b[j] - a[j]*b[j+1];
491
492
c[j] = re;
493
c[j+1] = im;
494
}
495
}
496
}
497
}
498
499
class CxCore_DXTBaseTest : public cvtest::ArrayTest
500
{
501
public:
502
typedef cvtest::ArrayTest Base;
503
CxCore_DXTBaseTest( bool _allow_complex=false, bool _allow_odd=false,
504
bool _spectrum_mode=false );
505
protected:
506
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
507
int prepare_test_case( int test_case_idx );
508
double get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ );
509
int flags; // transformation flags
510
bool allow_complex; // whether input/output may be complex or not:
511
// true for DFT and MulSpectrums, false for DCT
512
bool allow_odd; // whether input/output may be have odd (!=1) dimensions:
513
// true for DFT and MulSpectrums, false for DCT
514
bool spectrum_mode; // (2 complex/ccs inputs, 1 complex/ccs output):
515
// true for MulSpectrums, false for DFT and DCT
516
bool inplace; // inplace operation (set for each individual test case)
517
bool temp_dst; // use temporary destination (for real->ccs DFT and ccs MulSpectrums)
518
};
519
520
521
CxCore_DXTBaseTest::CxCore_DXTBaseTest( bool _allow_complex, bool _allow_odd, bool _spectrum_mode )
522
: Base(), flags(0), allow_complex(_allow_complex), allow_odd(_allow_odd),
523
spectrum_mode(_spectrum_mode), inplace(false), temp_dst(false)
524
{
525
test_array[INPUT].push_back(NULL);
526
if( spectrum_mode )
527
test_array[INPUT].push_back(NULL);
528
test_array[OUTPUT].push_back(NULL);
529
test_array[REF_OUTPUT].push_back(NULL);
530
test_array[TEMP].push_back(NULL);
531
test_array[TEMP].push_back(NULL);
532
533
max_log_array_size = 9;
534
element_wise_relative_error = spectrum_mode;
535
}
536
537
538
void CxCore_DXTBaseTest::get_test_array_types_and_sizes( int test_case_idx,
539
vector<vector<Size> >& sizes,
540
vector<vector<int> >& types )
541
{
542
RNG& rng = ts->get_rng();
543
int bits = cvtest::randInt(rng);
544
int depth = cvtest::randInt(rng)%2 + CV_32F;
545
int cn = !allow_complex || !(bits & 256) ? 1 : 2;
546
Size size;
547
Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
548
549
flags = bits & (CV_DXT_INVERSE | CV_DXT_SCALE | CV_DXT_ROWS | CV_DXT_MUL_CONJ);
550
if( spectrum_mode )
551
flags &= ~CV_DXT_INVERSE;
552
types[TEMP][0] = types[TEMP][1] = types[INPUT][0] =
553
types[OUTPUT][0] = CV_MAKETYPE(depth, cn);
554
size = sizes[INPUT][0];
555
556
temp_dst = false;
557
558
if( flags & CV_DXT_ROWS && (bits&1024) )
559
{
560
if( bits&16 )
561
size.width = 1;
562
else
563
size.height = 1;
564
flags &= ~CV_DXT_ROWS;
565
}
566
567
const int P2_MIN_SIZE = 32;
568
if( ((bits >> 10) & 1) == 0 )
569
{
570
size.width = (size.width / P2_MIN_SIZE)*P2_MIN_SIZE;
571
size.width = MAX(size.width, 1);
572
size.height = (size.height / P2_MIN_SIZE)*P2_MIN_SIZE;
573
size.height = MAX(size.height, 1);
574
}
575
576
if( !allow_odd )
577
{
578
if( size.width > 1 && (size.width&1) != 0 )
579
size.width = (size.width + 1) & -2;
580
581
if( size.height > 1 && (size.height&1) != 0 && !(flags & CV_DXT_ROWS) )
582
size.height = (size.height + 1) & -2;
583
}
584
585
sizes[INPUT][0] = sizes[OUTPUT][0] = size;
586
sizes[TEMP][0] = sizes[TEMP][1] = cvSize(0,0);
587
588
if( spectrum_mode )
589
{
590
if( cn == 1 )
591
{
592
types[OUTPUT][0] = depth + 8;
593
sizes[TEMP][0] = size;
594
}
595
sizes[INPUT][0] = sizes[INPUT][1] = size;
596
types[INPUT][1] = types[INPUT][0];
597
}
598
else if( /*(cn == 2 && (bits&32)) ||*/ (cn == 1 && allow_complex) )
599
{
600
types[TEMP][0] = depth + 8; // CV_??FC2
601
sizes[TEMP][0] = size;
602
size = cvSize(size.width/2+1, size.height);
603
604
if( flags & CV_DXT_INVERSE )
605
{
606
if( cn == 2 )
607
{
608
types[OUTPUT][0] = depth;
609
sizes[INPUT][0] = size;
610
}
611
types[TEMP][1] = types[TEMP][0];
612
sizes[TEMP][1] = sizes[TEMP][0];
613
}
614
else
615
{
616
if( allow_complex )
617
types[OUTPUT][0] = depth + 8;
618
619
if( cn == 2 )
620
{
621
types[INPUT][0] = depth;
622
types[TEMP][1] = types[TEMP][0];
623
sizes[TEMP][1] = size;
624
}
625
else
626
{
627
types[TEMP][1] = depth;
628
sizes[TEMP][1] = sizes[TEMP][0];
629
}
630
temp_dst = true;
631
}
632
}
633
634
inplace = false;
635
if( spectrum_mode ||
636
(!temp_dst && types[INPUT][0] == types[OUTPUT][0]) ||
637
(temp_dst && types[INPUT][0] == types[TEMP][1]) )
638
inplace = (bits & 64) != 0;
639
640
types[REF_OUTPUT][0] = types[OUTPUT][0];
641
sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
642
}
643
644
645
double CxCore_DXTBaseTest::get_success_error_level( int test_case_idx, int i, int j )
646
{
647
return Base::get_success_error_level( test_case_idx, i, j );
648
}
649
650
651
int CxCore_DXTBaseTest::prepare_test_case( int test_case_idx )
652
{
653
int code = Base::prepare_test_case( test_case_idx );
654
if( code > 0 )
655
{
656
int in_type = test_mat[INPUT][0].type();
657
int out_type = test_mat[OUTPUT][0].type();
658
659
if( CV_MAT_CN(in_type) == 2 && CV_MAT_CN(out_type) == 1 )
660
fixCCS( test_mat[INPUT][0], test_mat[OUTPUT][0].cols, flags );
661
662
if( inplace )
663
cvtest::copy( test_mat[INPUT][test_case_idx & (int)spectrum_mode],
664
temp_dst ? test_mat[TEMP][1] :
665
in_type == out_type ? test_mat[OUTPUT][0] :
666
test_mat[TEMP][0] );
667
}
668
669
return code;
670
}
671
672
673
////////////////////// FFT ////////////////////////
674
class CxCore_DFTTest : public CxCore_DXTBaseTest
675
{
676
public:
677
CxCore_DFTTest();
678
protected:
679
void run_func();
680
void prepare_to_validation( int test_case_idx );
681
};
682
683
684
CxCore_DFTTest::CxCore_DFTTest() : CxCore_DXTBaseTest( true, true, false )
685
{
686
}
687
688
689
void CxCore_DFTTest::run_func()
690
{
691
Mat& dst = temp_dst ? test_mat[TEMP][1] : test_mat[OUTPUT][0];
692
const Mat& src = inplace ? dst : test_mat[INPUT][0];
693
694
if(!(flags & CV_DXT_INVERSE))
695
cv::dft( src, dst, flags );
696
else
697
cv::idft(src, dst, flags & ~CV_DXT_INVERSE);
698
}
699
700
701
void CxCore_DFTTest::prepare_to_validation( int /*test_case_idx*/ )
702
{
703
Mat& src = test_mat[INPUT][0];
704
Mat& dst = test_mat[REF_OUTPUT][0];
705
Mat* tmp_src = &src;
706
Mat* tmp_dst = &dst;
707
int src_cn = src.channels();
708
int dst_cn = dst.channels();
709
710
if( src_cn != 2 || dst_cn != 2 )
711
{
712
tmp_src = &test_mat[TEMP][0];
713
714
if( !(flags & CV_DXT_INVERSE ) )
715
{
716
Mat& cvdft_dst = test_mat[TEMP][1];
717
convertFromCCS( cvdft_dst, cvdft_dst,
718
test_mat[OUTPUT][0], flags );
719
*tmp_src = Scalar::all(0);
720
cvtest::insert( src, *tmp_src, 0 );
721
}
722
else
723
{
724
convertFromCCS( src, src, *tmp_src, flags );
725
tmp_dst = &test_mat[TEMP][1];
726
}
727
}
728
729
if( src.rows == 1 || (src.cols == 1 && !(flags & CV_DXT_ROWS)) )
730
DFT_1D( *tmp_src, *tmp_dst, flags );
731
else
732
DFT_2D( *tmp_src, *tmp_dst, flags );
733
734
if( tmp_dst != &dst )
735
cvtest::extract( *tmp_dst, dst, 0 );
736
}
737
738
////////////////////// DCT ////////////////////////
739
class CxCore_DCTTest : public CxCore_DXTBaseTest
740
{
741
public:
742
CxCore_DCTTest();
743
protected:
744
void run_func();
745
void prepare_to_validation( int test_case_idx );
746
};
747
748
749
CxCore_DCTTest::CxCore_DCTTest() : CxCore_DXTBaseTest( false, false, false )
750
{
751
}
752
753
754
void CxCore_DCTTest::run_func()
755
{
756
Mat& dst = test_mat[OUTPUT][0];
757
const Mat& src = inplace ? dst : test_mat[INPUT][0];
758
759
if(!(flags & CV_DXT_INVERSE))
760
cv::dct( src, dst, flags );
761
else
762
cv::idct( src, dst, flags & ~CV_DXT_INVERSE);
763
}
764
765
766
void CxCore_DCTTest::prepare_to_validation( int /*test_case_idx*/ )
767
{
768
const Mat& src = test_mat[INPUT][0];
769
Mat& dst = test_mat[REF_OUTPUT][0];
770
771
if( src.rows == 1 || (src.cols == 1 && !(flags & CV_DXT_ROWS)) )
772
DCT_1D( src, dst, flags );
773
else
774
DCT_2D( src, dst, flags );
775
}
776
777
778
////////////////////// MulSpectrums ////////////////////////
779
class CxCore_MulSpectrumsTest : public CxCore_DXTBaseTest
780
{
781
public:
782
CxCore_MulSpectrumsTest();
783
protected:
784
void run_func();
785
void prepare_to_validation( int test_case_idx );
786
double get_success_error_level( int test_case_idx, int i, int j );
787
};
788
789
790
CxCore_MulSpectrumsTest::CxCore_MulSpectrumsTest() : CxCore_DXTBaseTest( true, true, true )
791
{
792
}
793
794
double CxCore_MulSpectrumsTest::get_success_error_level( int test_case_idx, int i, int j )
795
{
796
CV_UNUSED(test_case_idx);
797
CV_Assert(i == OUTPUT);
798
CV_Assert(j == 0);
799
int elem_depth = CV_MAT_DEPTH(cvGetElemType(test_array[i][j]));
800
CV_Assert(elem_depth == CV_32F || elem_depth == CV_64F);
801
802
element_wise_relative_error = false;
803
double maxInputValue = 1000; // ArrayTest::get_minmax_bounds
804
double err = 8 * maxInputValue; // result = A*B + C*D
805
return (elem_depth == CV_32F ? FLT_EPSILON : DBL_EPSILON) * err;
806
}
807
808
void CxCore_MulSpectrumsTest::run_func()
809
{
810
Mat& dst = !test_mat[TEMP].empty() && !test_mat[TEMP][0].empty() ?
811
test_mat[TEMP][0] : test_mat[OUTPUT][0];
812
const Mat* src1 = &test_mat[INPUT][0], *src2 = &test_mat[INPUT][1];
813
814
if( inplace )
815
{
816
if( ts->get_current_test_info()->test_case_idx & 1 )
817
src2 = &dst;
818
else
819
src1 = &dst;
820
}
821
822
cv::mulSpectrums( *src1, *src2, dst, flags, (flags & CV_DXT_MUL_CONJ) != 0 );
823
}
824
825
826
void CxCore_MulSpectrumsTest::prepare_to_validation( int /*test_case_idx*/ )
827
{
828
Mat* src1 = &test_mat[INPUT][0];
829
Mat* src2 = &test_mat[INPUT][1];
830
Mat& dst = test_mat[OUTPUT][0];
831
Mat& dst0 = test_mat[REF_OUTPUT][0];
832
int cn = src1->channels();
833
834
if( cn == 1 )
835
{
836
convertFromCCS( *src1, *src1, dst, flags );
837
convertFromCCS( *src2, *src2, dst0, flags );
838
src1 = &dst;
839
src2 = &dst0;
840
}
841
842
mulComplex( *src1, *src2, dst0, flags );
843
if( cn == 1 )
844
{
845
Mat& temp = test_mat[TEMP][0];
846
convertFromCCS( temp, temp, dst, flags );
847
}
848
}
849
850
TEST(Core_DCT, accuracy) { CxCore_DCTTest test; test.safe_run(); }
851
TEST(Core_DFT, accuracy) { CxCore_DFTTest test; test.safe_run(); }
852
TEST(Core_MulSpectrums, accuracy) { CxCore_MulSpectrumsTest test; test.safe_run(); }
853
854
class Core_DFTComplexOutputTest : public cvtest::BaseTest
855
{
856
public:
857
Core_DFTComplexOutputTest() {}
858
~Core_DFTComplexOutputTest() {}
859
protected:
860
void run(int)
861
{
862
RNG& rng = theRNG();
863
for( int i = 0; i < 10; i++ )
864
{
865
int m = rng.uniform(2, 11);
866
int n = rng.uniform(2, 11);
867
int depth = rng.uniform(0, 2) + CV_32F;
868
Mat src8u(m, n, depth), src(m, n, depth), dst(m, n, CV_MAKETYPE(depth, 2));
869
Mat z = Mat::zeros(m, n, depth), dstz;
870
randu(src8u, Scalar::all(0), Scalar::all(10));
871
src8u.convertTo(src, src.type());
872
dst = Scalar::all(123);
873
Mat mv[] = {src, z}, srcz;
874
merge(mv, 2, srcz);
875
dft(srcz, dstz);
876
dft(src, dst, DFT_COMPLEX_OUTPUT);
877
if (cvtest::norm(dst, dstz, NORM_INF) > 1e-3)
878
{
879
cout << "actual:\n" << dst << endl << endl;
880
cout << "reference:\n" << dstz << endl << endl;
881
CV_Error(CV_StsError, "");
882
}
883
}
884
}
885
};
886
887
TEST(Core_DFT, complex_output) { Core_DFTComplexOutputTest test; test.safe_run(); }
888
889
TEST(Core_DFT, complex_output2)
890
{
891
for( int i = 0; i < 100; i++ )
892
{
893
int type = theRNG().uniform(0, 2) ? CV_64F : CV_32F;
894
int m = theRNG().uniform(1, 10);
895
int n = theRNG().uniform(1, 10);
896
Mat x(m, n, type), out;
897
randu(x, -1., 1.);
898
dft(x, out, DFT_ROWS | DFT_COMPLEX_OUTPUT);
899
double nrm = cvtest::norm(out, NORM_INF);
900
double thresh = n*m*2;
901
if( nrm > thresh )
902
{
903
cout << "x: " << x << endl;
904
cout << "out: " << out << endl;
905
ASSERT_LT(nrm, thresh);
906
}
907
}
908
}
909
910
class Core_DXTReverseTest : public cvtest::BaseTest
911
{
912
public:
913
enum Mode
914
{
915
ModeDFT,
916
ModeDCT
917
};
918
Core_DXTReverseTest(Mode m) : mode(m) {}
919
private:
920
Mode mode;
921
protected:
922
void run(int)
923
{
924
for (int i = 0; i < 3; ++i)
925
{
926
if (mode == ModeDCT && i != 0)
927
continue;
928
int flags = 0;
929
int flags_inv = DFT_INVERSE | DFT_SCALE;
930
int cn_in = 0;
931
int cn_out = 0;
932
switch (i)
933
{
934
case 0: cn_in = 1; cn_out = 1; break;
935
case 1: cn_in = 1; cn_out = 2; flags |= DFT_COMPLEX_OUTPUT; flags_inv |= DFT_REAL_OUTPUT; break;
936
case 2: cn_in = 2; cn_out = 2; break;
937
};
938
for (int j = 0; j < 100; ++j)
939
{
940
RNG& rng = ts->get_rng();
941
int type = rng.uniform(0, 2) ? CV_64F : CV_32F;
942
int m = rng.uniform(1, 10);
943
int n = rng.uniform(1, 10);
944
if (mode == ModeDCT)
945
{
946
m *= 2;
947
n *= 2;
948
}
949
Mat one(m, n, CV_MAKETYPE(type, cn_in));
950
cvtest::randUni(rng, one, Scalar::all(-1.), Scalar::all(1.));
951
Mat out;
952
Mat two;
953
if (mode == ModeDFT)
954
{
955
cv::dft(one, out, flags);
956
cv::dft(out, two, flags_inv);
957
}
958
else if (mode == ModeDCT)
959
{
960
cv::dct(one, out, flags);
961
cv::dct(out, two, flags_inv);
962
}
963
if (out.channels() != cn_out || two.channels() != cn_in || cvtest::norm(one, two, NORM_INF) > 1e-5)
964
{
965
cout << "Test #" << j + 1 << " - "
966
<< "elements: " << m << " x " << n << ", "
967
<< "channels: "
968
<< one.channels() << " (" << cn_in << ")" << " -> "
969
<< out.channels() << " (" << cn_out << ")" << " -> "
970
<< two.channels() << " (" << cn_in << ")"
971
<< endl;
972
cout << "signal:\n" << one << endl << endl;
973
cout << "spectrum:\n" << out << endl << endl;
974
cout << "inverse:\n" << two << endl << endl;
975
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
976
break;
977
}
978
}
979
}
980
}
981
};
982
983
TEST(Core_DFT, reverse) { Core_DXTReverseTest test(Core_DXTReverseTest::ModeDFT); test.safe_run(); }
984
TEST(Core_DCT, reverse) { Core_DXTReverseTest test(Core_DXTReverseTest::ModeDCT); test.safe_run(); }
985
986
}} // namespace
987
988