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