test_dxt.cpp 28 KB

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