7bffaa87c6ac0928c0a6768c9b7695d0815b3f9d
[opencv] / tests / cxcore / src / adxt.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 //////////////////////////////////////////////////////////////////////////////////////////
43 ////////////////// tests for discrete linear transforms (FFT, DCT ...) ///////////////////
44 //////////////////////////////////////////////////////////////////////////////////////////
45
46 #include "cxcoretest.h"
47 #include <float.h>
48
49 typedef struct CvTsComplex32f
50 {
51     float re, im;
52 }
53 CvTsComplex32f;
54
55 typedef struct CvTsComplex64f
56 {
57     double re, im;
58 }
59 CvTsComplex64f;
60
61 static CvMat* cvTsInitDFTWave( int n, int inv )
62 {
63     int i;
64     double angle = (inv ? 1 : -1)*CV_PI*2/n;
65     CvTsComplex64f wi, w1;
66     CvMat* wave = cvCreateMat( 1, n, CV_64FC2 );
67     CvTsComplex64f* w = (CvTsComplex64f*)wave->data.db;
68
69     w1.re = cos(angle);
70     w1.im = sin(angle);
71     w[0].re = wi.re = 1.;
72     w[0].im = wi.im = 0.;
73
74     for( i = 1; i < n; i++ )
75     {
76         double t = wi.re*w1.re - wi.im*w1.im;
77         wi.im = wi.re*w1.im + wi.im*w1.re;
78         wi.re = t;
79         w[i] = wi;
80     }
81
82     return wave;
83 }
84
85
86 static void cvTsDFT_1D( const CvMat* _src, CvMat* _dst, int flags, CvMat* wave=0 )
87 {
88     int i, j, k, n = _dst->cols + _dst->rows - 1;
89     const CvMat* wave0 = wave;
90     double scale = (flags & CV_DXT_SCALE) ? 1./n : 1.;
91     assert( _src->cols + _src->rows - 1 == n );
92     int src_step = 1, dst_step = 1;
93     CvTsComplex64f* w;
94
95     assert( CV_ARE_TYPES_EQ(_src,_dst) && _src->rows*_src->cols == _dst->rows*_dst->cols );
96
97     if( !wave )
98         wave = cvTsInitDFTWave( n, flags & CV_DXT_INVERSE );
99
100     w = (CvTsComplex64f*)wave->data.db;
101     if( !CV_IS_MAT_CONT(_src->type) )
102         src_step = _src->step/CV_ELEM_SIZE(_src->type);
103     if( !CV_IS_MAT_CONT(_dst->type) )
104         dst_step = _dst->step/CV_ELEM_SIZE(_dst->type);
105
106     if( CV_MAT_TYPE(_src->type) == CV_32FC2 )
107     {
108         CvTsComplex32f* dst = (CvTsComplex32f*)_dst->data.fl;
109         for( i = 0; i < n; i++, dst += dst_step )
110         {
111             CvTsComplex32f* src = (CvTsComplex32f*)_src->data.fl;
112             CvTsComplex64f sum = {0,0};
113             int delta = i;
114             k = 0;
115
116             for( j = 0; j < n; j++, src += src_step )
117             {
118                 sum.re += src->re*w[k].re - src->im*w[k].im;
119                 sum.im += src->re*w[k].im + src->im*w[k].re;
120                 k += delta;
121                 k -= (k >= n ? n : 0);
122             }
123
124             dst->re = (float)(sum.re*scale);
125             dst->im = (float)(sum.im*scale);
126         }
127     }
128     else if( CV_MAT_TYPE(_src->type) == CV_64FC2 )
129     {
130         CvTsComplex64f* dst = (CvTsComplex64f*)_dst->data.db;
131         for( i = 0; i < n; i++, dst += dst_step )
132         {
133             CvTsComplex64f* src = (CvTsComplex64f*)_src->data.db;
134             CvTsComplex64f sum = {0,0};
135             int delta = i;
136             k = 0;
137
138             for( j = 0; j < n; j++, src += src_step )
139             {
140                 sum.re += src->re*w[k].re - src->im*w[k].im;
141                 sum.im += src->re*w[k].im + src->im*w[k].re;
142                 k += delta;
143                 k -= (k >= n ? n : 0);
144             }
145
146             dst->re = sum.re*scale;
147             dst->im = sum.im*scale;
148         }
149     }
150     else
151         assert(0);
152
153     if( !wave0 )
154         cvReleaseMat( &wave );
155 }
156
157
158 static void cvTsDFT_2D( const CvMat* src, CvMat* dst, int flags )
159 {
160     int i;
161     CvMat* tmp = cvCreateMat( dst->cols, dst->rows, dst->type );
162     CvMat* wave = cvTsInitDFTWave( dst->cols, flags & CV_DXT_INVERSE );
163
164     // 1. row-wise transform
165     for( i = 0; i < dst->rows; i++ )
166     {
167         CvMat src_row, dst_row;
168         cvGetRow( src, &src_row, i );
169         cvGetCol( tmp, &dst_row, i );
170         cvTsDFT_1D( &src_row, &dst_row, flags, wave );
171     }
172
173     if( !(flags & CV_DXT_ROWS) )
174     {
175         if( dst->cols != dst->rows )
176         {
177             cvReleaseMat( &wave );
178             wave = cvTsInitDFTWave( dst->rows, flags & CV_DXT_INVERSE );
179         }
180
181         // 2. column-wise transform
182         for( i = 0; i < dst->cols; i++ )
183         {
184             CvMat src_row, dst_row;
185             cvGetRow( tmp, &src_row, i );
186             cvGetCol( dst, &dst_row, i );
187             cvTsDFT_1D( &src_row, &dst_row, flags, wave );
188         }
189     }
190     else
191         cvTsTranspose( tmp, dst );
192
193     cvReleaseMat( &wave );
194     cvReleaseMat( &tmp );
195 }
196
197
198 static CvMat* cvTsInitDCTWave( int n, int inv )
199 {
200     int i, k;
201     double angle = CV_PI*0.5/n;
202     CvMat* wave = cvCreateMat( n, n, CV_64FC1 );
203
204     double scale = sqrt(1./n);
205     for( k = 0; k < n; k++ )
206         wave->data.db[k] = scale;
207     scale *= sqrt(2.);
208     for( i = 1; i < n; i++ )
209         for( k = 0; k < n; k++ )
210             wave->data.db[i*n + k] = scale*cos( angle*i*(2*k + 1) );
211
212     if( inv )
213         cvTsTranspose( wave, wave );
214
215     return wave;
216 }
217
218
219 static void cvTsDCT_1D( const CvMat* _src, CvMat* _dst, int flags, CvMat* wave=0 )
220 {
221     int i, j, n = _dst->cols + _dst->rows - 1;
222     const CvMat* wave0 = wave;
223     assert( _src->cols + _src->rows - 1 == n);
224     int src_step = 1, dst_step = 1;
225     double* w;
226
227     assert( CV_ARE_TYPES_EQ(_src,_dst) && _src->rows*_src->cols == _dst->rows*_dst->cols );
228
229     if( !wave )
230         wave = cvTsInitDCTWave( n, flags & CV_DXT_INVERSE );
231     w = wave->data.db;
232
233     if( !CV_IS_MAT_CONT(_src->type) )
234         src_step = _src->step/CV_ELEM_SIZE(_src->type);
235     if( !CV_IS_MAT_CONT(_dst->type) )
236         dst_step = _dst->step/CV_ELEM_SIZE(_dst->type);
237
238     if( CV_MAT_TYPE(_src->type) == CV_32FC1 )
239     {
240         float *dst = _dst->data.fl;
241
242         for( i = 0; i < n; i++, dst += dst_step )
243         {
244             const float* src = _src->data.fl;
245             double sum = 0;
246
247             for( j = 0; j < n; j++, src += src_step )
248                 sum += src[0]*w[j];
249             w += n;
250             dst[0] = (float)sum;
251         }
252     }
253     else if( CV_MAT_TYPE(_src->type) == CV_64FC1 )
254     {
255         double *dst = _dst->data.db;
256
257         for( i = 0; i < n; i++, dst += dst_step )
258         {
259             const double* src = _src->data.db;
260             double sum = 0;
261
262             for( j = 0; j < n; j++, src += src_step )
263                 sum += src[0]*w[j];
264             w += n;
265             dst[0] = sum;
266         }
267     }
268     else
269         assert(0);
270
271     if( !wave0 )
272         cvReleaseMat( &wave );
273 }
274
275
276 static void cvTsDCT_2D( const CvMat* src, CvMat* dst, int flags )
277 {
278     int i;
279     CvMat* tmp = cvCreateMat( dst->cols, dst->rows, dst->type );
280     CvMat* wave = cvTsInitDCTWave( dst->cols, flags & CV_DXT_INVERSE );
281
282     // 1. row-wise transform
283     for( i = 0; i < dst->rows; i++ )
284     {
285         CvMat src_row, dst_row;
286         cvGetRow( src, &src_row, i );
287         cvGetCol( tmp, &dst_row, i );
288         cvTsDCT_1D( &src_row, &dst_row, flags, wave );
289     }
290
291     if( !(flags & CV_DXT_ROWS) )
292     {
293         if( dst->cols != dst->rows )
294         {
295             cvReleaseMat( &wave );
296             wave = cvTsInitDCTWave( dst->rows, flags & CV_DXT_INVERSE );
297         }
298
299         // 2. column-wise transform
300         for( i = 0; i < dst->cols; i++ )
301         {
302             CvMat src_row, dst_row;
303             cvGetRow( tmp, &src_row, i );
304             cvGetCol( dst, &dst_row, i );
305             cvTsDCT_1D( &src_row, &dst_row, flags, wave );
306         }
307     }
308     else
309     {
310         cvTranspose( tmp, dst );
311     }
312
313     cvReleaseMat( &wave );
314     cvReleaseMat( &tmp );
315 }
316
317
318 static void cvTsConvertFromCCS( const CvMat* _src0, const CvMat* _src1,
319                                 CvMat* _dst, int flags )
320 {
321     if( _dst->rows > 1 && (_dst->cols > 1 || (flags & CV_DXT_ROWS)) )
322     {
323         int i, count = _dst->rows, len = _dst->cols;
324         int is_2d = (flags & CV_DXT_ROWS) == 0;
325         CvMat src0_row, src1_row, dst_row;
326         for( i = 0; i < count; i++ )
327         {
328             int j = !is_2d || i == 0 ? i : count - i;
329             cvGetRow( _src0, &src0_row, i );
330             cvGetRow( _src1, &src1_row, j );
331             cvGetRow( _dst, &dst_row, i );
332             cvTsConvertFromCCS( &src0_row, &src1_row, &dst_row, 0 );
333         }
334
335         if( is_2d )
336         {
337             cvGetCol( _src0, &src0_row, 0 );
338             cvGetCol( _dst, &dst_row, 0 );
339             cvTsConvertFromCCS( &src0_row, &src0_row, &dst_row, 0 );
340             if( (len & 1) == 0 )
341             {
342                 cvGetCol( _src0, &src0_row, _src0->cols - 1 );
343                 cvGetCol( _dst, &dst_row, len/2 );
344                 cvTsConvertFromCCS( &src0_row, &src0_row, &dst_row, 0 );
345             }
346         }
347     }
348     else
349     {
350         int i, n = _dst->cols + _dst->rows - 1, n2 = (n+1) >> 1;
351         int cn = CV_MAT_CN(_src0->type);
352         int src_step = cn, dst_step = 1;
353
354         if( !CV_IS_MAT_CONT(_dst->type) )
355             dst_step = _dst->step/CV_ELEM_SIZE(_dst->type);
356
357         if( !CV_IS_MAT_CONT(_src0->type) )
358             src_step = _src0->step/CV_ELEM_SIZE(_src0->type & CV_MAT_DEPTH_MASK);
359
360         if( CV_MAT_DEPTH(_dst->type) == CV_32F )
361         {
362             CvTsComplex32f* dst = (CvTsComplex32f*)_dst->data.fl;
363             const float* src0 = _src0->data.fl;
364             const float* src1 = _src1->data.fl;
365             int delta0, delta1;
366
367             dst->re = src0[0];
368             dst->im = 0;
369
370             if( (n & 1) == 0 )
371             {
372                 dst[n2*dst_step].re = src0[(cn == 1 ? n-1 : n2)*src_step];
373                 dst[n2*dst_step].im = 0;
374             }
375
376             delta0 = src_step;
377             delta1 = delta0 + (cn == 1 ? src_step : 1);
378             if( cn == 1 )
379                 src_step *= 2;
380
381             for( i = 1; i < n2; i++, delta0 += src_step, delta1 += src_step )
382             {
383                 float t0 = src0[delta0];
384                 float t1 = src0[delta1];
385
386                 dst[i*dst_step].re = t0;
387                 dst[i*dst_step].im = t1;
388
389                 t0 = src1[delta0];
390                 t1 = -src1[delta1];
391
392                 dst[(n-i)*dst_step].re = t0;
393                 dst[(n-i)*dst_step].im = t1;
394             }
395         }
396         else
397         {
398             CvTsComplex64f* dst = (CvTsComplex64f*)_dst->data.db;
399             const double* src0 = _src0->data.db;
400             const double* src1 = _src1->data.db;
401             int delta0, delta1;
402
403             dst->re = src0[0];
404             dst->im = 0;
405
406             if( (n & 1) == 0 )
407             {
408                 dst[n2*dst_step].re = src0[(cn == 1 ? n-1 : n2)*src_step];
409                 dst[n2*dst_step].im = 0;
410             }
411
412             delta0 = src_step;
413             delta1 = delta0 + (cn == 1 ? src_step : 1);
414             if( cn == 1 )
415                 src_step *= 2;
416
417             for( i = 1; i < n2; i++, delta0 += src_step, delta1 += src_step )
418             {
419                 double t0 = src0[delta0];
420                 double t1 = src0[delta1];
421
422                 dst[i*dst_step].re = t0;
423                 dst[i*dst_step].im = t1;
424
425                 t0 = src1[delta0];
426                 t1 = -src1[delta1];
427
428                 dst[(n-i)*dst_step].re = t0;
429                 dst[(n-i)*dst_step].im = t1;
430             }
431         }
432     }
433 }
434
435
436 static void cvTsFixCCS( CvMat* mat, int cols, int flags )
437 {
438     int i, rows = mat->rows;
439     int rows2 = flags & CV_DXT_ROWS ? rows : rows/2 + 1, cols2 = cols/2 + 1;
440
441     assert( cols2 == mat->cols );
442
443     if( CV_MAT_TYPE(mat->type) == CV_32FC2 )
444     {
445         for( i = 0; i < rows2; i++ )
446         {
447             CvTsComplex32f* row = (CvTsComplex32f*)(mat->data.ptr + mat->step*i);
448             if( (flags & CV_DXT_ROWS) || i == 0 || (i == rows2 - 1 && rows % 2 == 0) )
449             {
450                 row[0].im = 0;
451                 if( cols % 2 == 0 )
452                     row[cols2-1].im = 0;
453             }
454             else
455             {
456                 CvTsComplex32f* row2 = (CvTsComplex32f*)(mat->data.ptr + mat->step*(rows-i));
457                 row2[0].re = row[0].re;
458                 row2[0].im = -row[0].im;
459
460                 if( cols % 2 == 0 )
461                 {
462                     row2[cols2-1].re = row[cols2-1].re;
463                     row2[cols2-1].im = -row[cols2-1].im;
464                 }
465             }
466         }
467     }
468     else if( CV_MAT_TYPE(mat->type) == CV_64FC2 )
469     {
470         for( i = 0; i < rows2; i++ )
471         {
472             CvTsComplex64f* row = (CvTsComplex64f*)(mat->data.ptr + mat->step*i);
473             if( (flags & CV_DXT_ROWS) || i == 0 || (i == rows2 - 1 && rows % 2 == 0) )
474             {
475                 row[0].im = 0;
476                 if( cols % 2 == 0 )
477                     row[cols2-1].im = 0;
478             }
479             else
480             {
481                 CvTsComplex64f* row2 = (CvTsComplex64f*)(mat->data.ptr + mat->step*(rows-i));
482                 row2[0].re = row[0].re;
483                 row2[0].im = -row[0].im;
484
485                 if( cols % 2 == 0 )
486                 {
487                     row2[cols2-1].re = row[cols2-1].re;
488                     row2[cols2-1].im = -row[cols2-1].im;
489                 }
490             }
491         }
492     }
493 }
494
495
496 static const CvSize dxt_sizes[] = {{16,1}, {256,1}, {1024,1}, {65536,1},
497     {10,1}, {100,1}, {1000,1}, {100000,1}, {256, 256}, {1024,1024}, {-1,-1}};
498 static const int dxt_depths[] = { CV_32F, CV_64F, -1 };
499 static const char* dxt_param_names[] = { "size", "depth", "transform_type", 0 };
500 static const char* dft_transforms[] = { "Fwd_CToC", "Inv_CToC", "Fwd_RToPack", "Inv_PackToR", 0 };
501 static const char* mulsp_transforms[] = { "Fwd_CToC", "Fwd_RToPack", 0 };
502 static const char* dct_transforms[] = { "Fwd", "Inv", 0 };
503
504 class CxCore_DXTBaseTestImpl : public CvArrTest
505 {
506 public:
507     CxCore_DXTBaseTestImpl( const char* test_name, const char* test_funcs,
508                         bool _allow_complex=false, bool _allow_odd=false,
509                         bool _spectrum_mode=false );
510 protected:
511     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
512     int prepare_test_case( int test_case_idx );
513     double get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ );
514     void get_timing_test_array_types_and_sizes( int test_case_idx,
515                                                 CvSize** sizes, int** types,
516                                                 CvSize** whole_sizes, bool* are_images );
517     void print_timing_params( int test_case_idx, char* ptr, int params_left );
518     int write_default_params( CvFileStorage* fs );
519     int flags; // transformation flags
520     bool allow_complex, // whether input/output may be complex or not:
521                         // true for DFT and MulSpectrums, false for DCT
522          allow_odd,     // whether input/output may be have odd (!=1) dimensions:
523                         // true for DFT and MulSpectrums, false for DCT
524          spectrum_mode, // (2 complex/ccs inputs, 1 complex/ccs output):
525                         // true for MulSpectrums, false for DFT and DCT
526          inplace,       // inplace operation (set for each individual test case)
527          temp_dst;      // use temporary destination (for real->ccs DFT and ccs MulSpectrums)
528     const char** transform_type_list;
529 };
530
531
532 CxCore_DXTBaseTestImpl::CxCore_DXTBaseTestImpl( const char* test_name, const char* test_funcs,
533                                         bool _allow_complex, bool _allow_odd, bool _spectrum_mode )
534     : CvArrTest( test_name, test_funcs, "" ),
535     flags(0), allow_complex(_allow_complex), allow_odd(_allow_odd),
536     spectrum_mode(_spectrum_mode), inplace(false), temp_dst(false)
537 {
538     test_array[INPUT].push(NULL);
539     if( spectrum_mode )
540         test_array[INPUT].push(NULL);
541     test_array[OUTPUT].push(NULL);
542     test_array[REF_OUTPUT].push(NULL);
543     test_array[TEMP].push(NULL);
544     test_array[TEMP].push(NULL);
545
546     element_wise_relative_error = spectrum_mode;
547
548     size_list = (CvSize*)dxt_sizes;
549     whole_size_list = 0;
550     depth_list = (int*)dxt_depths;
551     cn_list = 0;
552     transform_type_list = 0;
553 }
554
555
556 void CxCore_DXTBaseTestImpl::get_test_array_types_and_sizes( int test_case_idx,
557                                                 CvSize** sizes, int** types )
558 {
559     CvRNG* rng = ts->get_rng();
560     int bits = cvTsRandInt(rng);
561     int depth = cvTsRandInt(rng)%2 + CV_32F;
562     int cn = !allow_complex || !(bits & 256) ? 1 : 2;
563     CvSize size;
564     CvArrTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
565
566     flags = bits & (CV_DXT_INVERSE | CV_DXT_SCALE | CV_DXT_ROWS | CV_DXT_MUL_CONJ);
567     if( spectrum_mode )
568         flags &= ~CV_DXT_INVERSE;
569     types[TEMP][0] = types[TEMP][1] = types[INPUT][0] =
570         types[OUTPUT][0] = CV_MAKETYPE(depth, cn);
571     size = sizes[INPUT][0];
572
573     //size.width = size.width % 10 + 1;
574     //size.height = size.width % 10 + 1;
575     //size.width = 1;
576     //flags &= ~CV_DXT_ROWS;
577     temp_dst = false;
578
579     if( flags & CV_DXT_ROWS && (bits&1024) )
580     {
581         if( bits&16 )
582             size.width = 1;
583         else
584             size.height = 1;
585         flags &= ~CV_DXT_ROWS;
586     }
587
588     if( !allow_odd )
589     {
590         if( size.width > 1 && (size.width&1) != 0 )
591             size.width = (size.width + 1) & -2;
592
593         if( size.height > 1 && (size.height&1) != 0 && !(flags & CV_DXT_ROWS) )
594             size.height = (size.height + 1) & -2;
595     }
596
597     sizes[INPUT][0] = sizes[OUTPUT][0] = size;
598     sizes[TEMP][0] = sizes[TEMP][1] = cvSize(0,0);
599
600     if( spectrum_mode )
601     {
602         if( cn == 1 )
603         {
604             types[OUTPUT][0] = depth + 8;
605             sizes[TEMP][0] = size;
606         }
607         sizes[INPUT][0] = sizes[INPUT][1] = size;
608         types[INPUT][1] = types[INPUT][0];
609     }
610     else if( /*(cn == 2 && (bits&32)) ||*/ (cn == 1 && allow_complex) )
611     {
612         types[TEMP][0] = depth + 8; // CV_??FC2
613         sizes[TEMP][0] = size;
614         size = cvSize(size.width/2+1, size.height);
615
616         if( flags & CV_DXT_INVERSE )
617         {
618             if( cn == 2 )
619             {
620                 types[OUTPUT][0] = depth;
621                 sizes[INPUT][0] = size;
622             }
623             types[TEMP][1] = types[TEMP][0];
624             sizes[TEMP][1] = sizes[TEMP][0];
625         }
626         else
627         {
628             if( allow_complex )
629                 types[OUTPUT][0] = depth + 8;
630
631             if( cn == 2 )
632             {
633                 types[INPUT][0] = depth;
634                 types[TEMP][1] = types[TEMP][0];
635                 sizes[TEMP][1] = size;
636             }
637             else
638             {
639                 types[TEMP][1] = depth;
640                 sizes[TEMP][1] = sizes[TEMP][0];
641             }
642             temp_dst = true;
643         }
644     }
645
646     inplace = false;
647     if( spectrum_mode ||
648         (!temp_dst && types[INPUT][0] == types[OUTPUT][0]) ||
649         (temp_dst && types[INPUT][0] == types[TEMP][1]) )
650         inplace = (bits & 64) != 0;
651
652     types[REF_OUTPUT][0] = types[OUTPUT][0];
653     sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
654 }
655
656
657 void CxCore_DXTBaseTestImpl::get_timing_test_array_types_and_sizes( int test_case_idx,
658                                                     CvSize** sizes, int** types,
659                                                     CvSize** whole_sizes, bool* are_images )
660 {
661     CvArrTest::get_timing_test_array_types_and_sizes( test_case_idx,
662                             sizes, types, whole_sizes, are_images );
663     const char* transform_type = cvReadString( find_timing_param( "transform_type" ), "" );
664     int depth = CV_MAT_DEPTH(types[INPUT][0]);
665     int in_type = depth, out_type = depth;
666
667     if( strcmp( transform_type, "Fwd_CToC" ) == 0 || strcmp( transform_type, "Inv_CToC" ) == 0 )
668         in_type = out_type = CV_MAKETYPE(depth,2);
669
670     if( strncmp( transform_type, "Fwd", 3 ) == 0 )
671         flags = CV_DXT_FORWARD;
672     else
673         flags = CV_DXT_INV_SCALE;
674
675     types[INPUT][0] = in_type;
676     if( spectrum_mode )
677         types[INPUT][1] = in_type;
678     types[OUTPUT][0] = types[REF_OUTPUT][0] = out_type;
679     sizes[TEMP][0] = cvSize(0,0);
680
681     inplace = false;
682 }
683
684
685 int CxCore_DXTBaseTestImpl::write_default_params( CvFileStorage* fs )
686 {
687     int code = CvArrTest::write_default_params(fs);
688     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
689         return code;
690     write_string_list( fs, "transform_type", transform_type_list );
691     return code;
692 }
693
694
695 void CxCore_DXTBaseTestImpl::print_timing_params( int test_case_idx, char* ptr, int params_left )
696 {
697     sprintf( ptr, "%s,", cvReadString( find_timing_param("transform_type"), "" ) );
698     ptr += strlen(ptr);
699     params_left--;
700     CvArrTest::print_timing_params( test_case_idx, ptr, params_left );
701 }
702
703
704 double CxCore_DXTBaseTestImpl::get_success_error_level( int test_case_idx, int i, int j )
705 {
706     return CvArrTest::get_success_error_level( test_case_idx, i, j );
707 }
708
709
710 int CxCore_DXTBaseTestImpl::prepare_test_case( int test_case_idx )
711 {
712     int code = CvArrTest::prepare_test_case( test_case_idx );
713     if( code > 0 && ts->get_testing_mode() == CvTS::CORRECTNESS_CHECK_MODE )
714     {
715         int in_type = CV_MAT_TYPE(test_mat[INPUT][0].type);
716         int out_type = CV_MAT_TYPE(test_mat[OUTPUT][0].type);
717
718         if( CV_MAT_CN(in_type) == 2 && CV_MAT_CN(out_type) == 1 )
719             cvTsFixCCS( &test_mat[INPUT][0], test_mat[OUTPUT][0].cols, flags );
720
721         if( inplace )
722             cvTsCopy( &test_mat[INPUT][test_case_idx & (int)spectrum_mode],
723                 temp_dst ? &test_mat[TEMP][1] :
724                 in_type == out_type ? &test_mat[OUTPUT][0] :
725                 &test_mat[TEMP][0] );
726     }
727
728     return code;
729 }
730
731 CxCore_DXTBaseTestImpl dxt_test( "dxt", "" );
732
733
734 class CxCore_DXTBaseTest : public CxCore_DXTBaseTestImpl
735 {
736 public:
737     CxCore_DXTBaseTest( const char* test_name, const char* test_funcs,
738                         bool _allow_complex=false, bool _allow_odd=false,
739                         bool _spectrum_mode=false );
740 };
741
742 CxCore_DXTBaseTest::CxCore_DXTBaseTest( const char* test_name, const char* test_funcs,
743                                         bool _allow_complex, bool _allow_odd, bool _spectrum_mode )
744     : CxCore_DXTBaseTestImpl( test_name, test_funcs, _allow_complex, _allow_odd, _spectrum_mode )
745 {
746     size_list = 0;
747     depth_list = 0;
748     default_timing_param_names = dxt_param_names;
749     transform_type_list = dft_transforms;
750 }
751
752
753 ////////////////////// FFT ////////////////////////
754 class CxCore_DFTTest : public CxCore_DXTBaseTest
755 {
756 public:
757     CxCore_DFTTest();
758 protected:
759     void run_func();
760     void prepare_to_validation( int test_case_idx );
761 };
762
763
764 CxCore_DFTTest::CxCore_DFTTest() : CxCore_DXTBaseTest( "dxt-dft", "cvDFT", true, true, false )
765 {
766 }
767
768
769 void CxCore_DFTTest::run_func()
770 {
771     CvArr* dst = temp_dst ? test_array[TEMP][1] : test_array[OUTPUT][0];
772     CvArr* src = inplace ? dst : test_array[INPUT][0];
773
774     cvDFT( src, dst, flags );
775 }
776
777
778 void CxCore_DFTTest::prepare_to_validation( int /*test_case_idx*/ )
779 {
780     CvMat* src = &test_mat[INPUT][0];
781     CvMat* dst = &test_mat[REF_OUTPUT][0];
782     CvMat* tmp_src = src;
783     CvMat* tmp_dst = dst;
784     int src_cn = CV_MAT_CN( src->type );
785     int dst_cn = CV_MAT_CN( dst->type );
786
787     if( src_cn != 2 || dst_cn != 2 )
788     {
789         tmp_src = &test_mat[TEMP][0];
790
791         if( !(flags & CV_DXT_INVERSE ) )
792         {
793             CvMat* cvdft_dst = &test_mat[TEMP][1];
794             cvTsConvertFromCCS( cvdft_dst, cvdft_dst,
795                                 &test_mat[OUTPUT][0], flags );
796             cvTsZero( tmp_src );
797             cvTsInsert( src, tmp_src, 0 );
798         }
799         else
800         {
801             cvTsConvertFromCCS( src, src, tmp_src, flags );
802             tmp_dst = &test_mat[TEMP][1];
803         }
804     }
805
806     if( src->rows == 1 || (src->cols == 1 && !(flags & CV_DXT_ROWS)) )
807         cvTsDFT_1D( tmp_src, tmp_dst, flags );
808     else
809         cvTsDFT_2D( tmp_src, tmp_dst, flags );
810
811     if( tmp_dst != dst )
812         cvTsExtract( tmp_dst, dst, 0 );
813 }
814
815
816 CxCore_DFTTest dft_test;
817
818
819 ////////////////////// DCT ////////////////////////
820 class CxCore_DCTTest : public CxCore_DXTBaseTest
821 {
822 public:
823     CxCore_DCTTest();
824 protected:
825     void run_func();
826     void prepare_to_validation( int test_case_idx );
827 };
828
829
830 CxCore_DCTTest::CxCore_DCTTest() : CxCore_DXTBaseTest( "dxt-dct", "cvDCT", false, false, false )
831 {
832     transform_type_list = dct_transforms;
833 }
834
835
836 void CxCore_DCTTest::run_func()
837 {
838     CvArr* dst = test_array[OUTPUT][0];
839     CvArr* src = inplace ? dst : test_array[INPUT][0];
840
841     cvDCT( src, dst, flags );
842 }
843
844
845 void CxCore_DCTTest::prepare_to_validation( int /*test_case_idx*/ )
846 {
847     CvMat* src = &test_mat[INPUT][0];
848     CvMat* dst = &test_mat[REF_OUTPUT][0];
849
850     if( src->rows == 1 || (src->cols == 1 && !(flags & CV_DXT_ROWS)) )
851         cvTsDCT_1D( src, dst, flags );
852     else
853         cvTsDCT_2D( src, dst, flags );
854 }
855
856
857 CxCore_DCTTest dct_test;
858
859
860 ////////////////////// MulSpectrums ////////////////////////
861 class CxCore_MulSpectrumsTest : public CxCore_DXTBaseTest
862 {
863 public:
864     CxCore_MulSpectrumsTest();
865 protected:
866     void run_func();
867     void prepare_to_validation( int test_case_idx );
868 };
869
870
871 CxCore_MulSpectrumsTest::CxCore_MulSpectrumsTest() :
872     CxCore_DXTBaseTest( "dxt-mulspectrums", "cvMulSpectrums", true, true, true )
873 {
874     transform_type_list = mulsp_transforms;
875 }
876
877
878 void CxCore_MulSpectrumsTest::run_func()
879 {
880     CvArr* dst = test_array[TEMP].size() > 0 && test_array[TEMP][0] ?
881                  test_array[TEMP][0] : test_array[OUTPUT][0];
882     CvArr *src1 = test_array[INPUT][0], *src2 = test_array[INPUT][1];
883
884     if( inplace )
885     {
886         if( ts->get_current_test_info()->test_case_idx & 1 )
887             src2 = dst;
888         else
889             src1 = dst;
890     }
891
892     cvMulSpectrums( src1, src2, dst, flags );
893 }
894
895
896 static void cvTsMulComplex( const CvMat* A, const CvMat* B, CvMat* C, int flags )
897 {
898     int i, j, depth = CV_MAT_DEPTH(A->type), cols = A->cols*2;
899
900     assert( CV_ARE_SIZES_EQ(A,B) && CV_ARE_SIZES_EQ(B,C) &&
901             CV_ARE_TYPES_EQ(A,B) && CV_ARE_TYPES_EQ(B,C) &&
902             CV_MAT_CN(A->type) == 2 && CV_MAT_DEPTH(A->type) >= CV_32F );
903
904     for( i = 0; i < C->rows; i++ )
905     {
906         if( depth == CV_32F )
907         {
908             const float* a = (float*)(A->data.ptr + A->step*i);
909             const float* b = (float*)(B->data.ptr + B->step*i);
910             float* c = (float*)(C->data.ptr + C->step*i);
911
912             if( !(flags & CV_DXT_MUL_CONJ) )
913                 for( j = 0; j < cols; j += 2 )
914                 {
915                     double re = (double)a[j]*b[j] - (double)a[j+1]*b[j+1];
916                     double im = (double)a[j+1]*b[j] + (double)a[j]*b[j+1];
917
918                     c[j] = (float)re;
919                     c[j+1] = (float)im;
920                 }
921             else
922                 for( j = 0; j < cols; j += 2 )
923                 {
924                     double re = (double)a[j]*b[j] + (double)a[j+1]*b[j+1];
925                     double im = (double)a[j+1]*b[j] - (double)a[j]*b[j+1];
926
927                     c[j] = (float)re;
928                     c[j+1] = (float)im;
929                 }
930         }
931         else
932         {
933             const double* a = (double*)(A->data.ptr + A->step*i);
934             const double* b = (double*)(B->data.ptr + B->step*i);
935             double* c = (double*)(C->data.ptr + C->step*i);
936
937             if( !(flags & CV_DXT_MUL_CONJ) )
938                 for( j = 0; j < cols; j += 2 )
939                 {
940                     double re = a[j]*b[j] - a[j+1]*b[j+1];
941                     double im = a[j+1]*b[j] + a[j]*b[j+1];
942
943                     c[j] = re;
944                     c[j+1] = im;
945                 }
946             else
947                 for( j = 0; j < cols; j += 2 )
948                 {
949                     double re = a[j]*b[j] + a[j+1]*b[j+1];
950                     double im = a[j+1]*b[j] - a[j]*b[j+1];
951
952                     c[j] = re;
953                     c[j+1] = im;
954                 }
955         }
956     }
957 }
958
959
960 void CxCore_MulSpectrumsTest::prepare_to_validation( int /*test_case_idx*/ )
961 {
962     CvMat* src1 = &test_mat[INPUT][0];
963     CvMat* src2 = &test_mat[INPUT][1];
964     CvMat* dst = &test_mat[OUTPUT][0];
965     CvMat* dst0 = &test_mat[REF_OUTPUT][0];
966     CvMat* temp = test_array[TEMP].size() > 0 && test_array[TEMP][0] ? &test_mat[TEMP][0] : 0;
967     int cn = CV_MAT_CN(src1->type);
968
969     if( cn == 1 )
970     {
971         cvTsConvertFromCCS( src1, src1, dst, flags );
972         cvTsConvertFromCCS( src2, src2, dst0, flags );
973         src1 = dst;
974         src2 = dst0;
975     }
976
977     cvTsMulComplex( src1, src2, dst0, flags );
978     if( cn == 1 )
979     {
980         assert( temp != 0 );
981         cvTsConvertFromCCS( temp, temp, dst, flags );
982     }
983 }
984
985
986 CxCore_MulSpectrumsTest mulspectrums_test;
987
988
989 /* End of file. */