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