test_pc.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  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. // License Agreement
  11. // For Open Source Computer Vision Library
  12. //
  13. // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
  14. // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
  15. // Third party copyrights are property of their respective owners.
  16. //
  17. // Redistribution and use in source and binary forms, with or without modification,
  18. // are permitted provided that the following conditions are met:
  19. //
  20. // * Redistribution's of source code must retain the above copyright notice,
  21. // this list of conditions and the following disclaimer.
  22. //
  23. // * Redistribution's in binary form must reproduce the above copyright notice,
  24. // this list of conditions and the following disclaimer in the documentation
  25. // and/or other materials provided with the distribution.
  26. //
  27. // * The name of the copyright holders may not be used to endorse or promote products
  28. // derived from this software without specific prior written permission.
  29. //
  30. // This software is provided by the copyright holders and contributors "as is" and
  31. // any express or implied warranties, including, but not limited to, the implied
  32. // warranties of merchantability and fitness for a particular purpose are disclaimed.
  33. // In no event shall the Intel Corporation or contributors be liable for any direct,
  34. // indirect, incidental, special, exemplary, or consequential damages
  35. // (including, but not limited to, procurement of substitute goods or services;
  36. // loss of use, data, or profits; or business interruption) however caused
  37. // and on any theory of liability, whether in contract, strict liability,
  38. // or tort (including negligence or otherwise) arising in any way out of
  39. // the use of this software, even if advised of the possibility of such damage.
  40. //
  41. //M*/
  42. #include "test_precomp.hpp"
  43. namespace opencv_test { namespace {
  44. /// phase correlation
  45. class CV_PhaseCorrelatorTest : public cvtest::ArrayTest
  46. {
  47. public:
  48. CV_PhaseCorrelatorTest();
  49. protected:
  50. void run( int );
  51. };
  52. CV_PhaseCorrelatorTest::CV_PhaseCorrelatorTest() {}
  53. void CV_PhaseCorrelatorTest::run( int )
  54. {
  55. ts->set_failed_test_info(cvtest::TS::OK);
  56. Mat r1 = Mat::ones(Size(129, 128), CV_64F);
  57. Mat r2 = Mat::ones(Size(129, 128), CV_64F);
  58. double expectedShiftX = -10.0;
  59. double expectedShiftY = -20.0;
  60. // draw 10x10 rectangles @ (100, 100) and (90, 80) should see ~(-10, -20) shift here...
  61. cv::rectangle(r1, Point(100, 100), Point(110, 110), Scalar(0, 0, 0), CV_FILLED);
  62. cv::rectangle(r2, Point(90, 80), Point(100, 90), Scalar(0, 0, 0), CV_FILLED);
  63. Mat hann;
  64. createHanningWindow(hann, r1.size(), CV_64F);
  65. Point2d phaseShift = phaseCorrelate(r1, r2, hann);
  66. // test accuracy should be less than 1 pixel...
  67. if(std::abs(expectedShiftX - phaseShift.x) >= 1 || std::abs(expectedShiftY - phaseShift.y) >= 1)
  68. {
  69. ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
  70. }
  71. }
  72. TEST(Imgproc_PhaseCorrelatorTest, accuracy) { CV_PhaseCorrelatorTest test; test.safe_run(); }
  73. TEST(Imgproc_PhaseCorrelatorTest, accuracy_real_img)
  74. {
  75. Mat img = imread(cvtest::TS::ptr()->get_data_path() + "shared/airplane.png", IMREAD_GRAYSCALE);
  76. img.convertTo(img, CV_64FC1);
  77. const int xLen = 129;
  78. const int yLen = 129;
  79. const int xShift = 40;
  80. const int yShift = 14;
  81. Mat roi1 = img(Rect(xShift, yShift, xLen, yLen));
  82. Mat roi2 = img(Rect(0, 0, xLen, yLen));
  83. Mat hann;
  84. createHanningWindow(hann, roi1.size(), CV_64F);
  85. Point2d phaseShift = phaseCorrelate(roi1, roi2, hann);
  86. ASSERT_NEAR(phaseShift.x, (double)xShift, 1.);
  87. ASSERT_NEAR(phaseShift.y, (double)yShift, 1.);
  88. }
  89. TEST(Imgproc_PhaseCorrelatorTest, accuracy_1d_odd_fft) {
  90. Mat r1 = Mat::ones(Size(129, 1), CV_64F)*255; // 129 will be completed to 135 before FFT
  91. Mat r2 = Mat::ones(Size(129, 1), CV_64F)*255;
  92. const int xShift = 10;
  93. for(int i = 6; i < 20; i++)
  94. {
  95. r1.at<double>(i) = 1;
  96. r2.at<double>(i + xShift) = 1;
  97. }
  98. Point2d phaseShift = phaseCorrelate(r1, r2);
  99. ASSERT_NEAR(phaseShift.x, (double)xShift, 1.);
  100. }
  101. ////////////////////// DivSpectrums ////////////////////////
  102. class CV_DivSpectrumsTest : public cvtest::ArrayTest
  103. {
  104. public:
  105. CV_DivSpectrumsTest();
  106. protected:
  107. void run_func();
  108. void get_test_array_types_and_sizes( int, vector<vector<Size> >& sizes, vector<vector<int> >& types );
  109. void prepare_to_validation( int test_case_idx );
  110. int flags;
  111. };
  112. CV_DivSpectrumsTest::CV_DivSpectrumsTest() : flags(0)
  113. {
  114. // Allocate test matrices.
  115. test_array[INPUT].push_back(NULL); // first input DFT as a CCS-packed array or complex matrix.
  116. test_array[INPUT].push_back(NULL); // second input DFT as a CCS-packed array or complex matrix.
  117. test_array[OUTPUT].push_back(NULL); // output DFT as a complex matrix.
  118. test_array[REF_OUTPUT].push_back(NULL); // reference output DFT as a complex matrix.
  119. test_array[TEMP].push_back(NULL); // first input DFT converted to a complex matrix.
  120. test_array[TEMP].push_back(NULL); // second input DFT converted to a complex matrix.
  121. test_array[TEMP].push_back(NULL); // output DFT as a CCV-packed array.
  122. }
  123. void CV_DivSpectrumsTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
  124. {
  125. cvtest::ArrayTest::get_test_array_types_and_sizes(test_case_idx, sizes, types);
  126. RNG& rng = ts->get_rng();
  127. // Get the flag of the input.
  128. const int rand_int_flags = cvtest::randInt(rng);
  129. flags = rand_int_flags & (CV_DXT_MUL_CONJ | CV_DXT_ROWS);
  130. // Get input type.
  131. const int rand_int_type = cvtest::randInt(rng);
  132. int type;
  133. if (rand_int_type % 4)
  134. {
  135. type = CV_32FC1;
  136. }
  137. else if (rand_int_type % 4 == 1)
  138. {
  139. type = CV_32FC2;
  140. }
  141. else if (rand_int_type % 4 == 2)
  142. {
  143. type = CV_64FC1;
  144. }
  145. else
  146. {
  147. type = CV_64FC2;
  148. }
  149. for( size_t i = 0; i < types.size(); i++ )
  150. {
  151. for( size_t j = 0; j < types[i].size(); j++ )
  152. {
  153. types[i][j] = type;
  154. }
  155. }
  156. // Inputs are CCS-packed arrays. Prepare outputs and temporary inputs as complex matrices.
  157. if( type == CV_32FC1 || type == CV_64FC1 )
  158. {
  159. types[OUTPUT][0] += 8;
  160. types[REF_OUTPUT][0] += 8;
  161. types[TEMP][0] += 8;
  162. types[TEMP][1] += 8;
  163. }
  164. }
  165. /// Helper function to convert a ccs array of depth_t into a complex matrix.
  166. template<typename depth_t>
  167. static void convert_from_ccs_helper( const Mat& src0, const Mat& src1, Mat& dst )
  168. {
  169. const int cn = src0.channels();
  170. int srcstep = cn;
  171. int dststep = 1;
  172. if( !dst.isContinuous() )
  173. dststep = (int)(dst.step/dst.elemSize());
  174. if( !src0.isContinuous() )
  175. srcstep = (int)(src0.step/src0.elemSize1());
  176. Complex<depth_t> *dst_data = dst.ptr<Complex<depth_t> >();
  177. const depth_t* src0_data = src0.ptr<depth_t>();
  178. const depth_t* src1_data = src1.ptr<depth_t>();
  179. dst_data->re = src0_data[0];
  180. dst_data->im = 0;
  181. const int n = dst.cols + dst.rows - 1;
  182. const int n2 = (n+1) >> 1;
  183. if( (n & 1) == 0 )
  184. {
  185. dst_data[n2*dststep].re = src0_data[(cn == 1 ? n-1 : n2)*srcstep];
  186. dst_data[n2*dststep].im = 0;
  187. }
  188. int delta0 = srcstep;
  189. int delta1 = delta0 + (cn == 1 ? srcstep : 1);
  190. if( cn == 1 )
  191. srcstep *= 2;
  192. for( int i = 1; i < n2; i++, delta0 += srcstep, delta1 += srcstep )
  193. {
  194. depth_t t0 = src0_data[delta0];
  195. depth_t t1 = src0_data[delta1];
  196. dst_data[i*dststep].re = t0;
  197. dst_data[i*dststep].im = t1;
  198. t0 = src1_data[delta0];
  199. t1 = -src1_data[delta1];
  200. dst_data[(n-i)*dststep].re = t0;
  201. dst_data[(n-i)*dststep].im = t1;
  202. }
  203. }
  204. /// Helper function to convert a ccs array into a complex matrix.
  205. static void convert_from_ccs( const Mat& src0, const Mat& src1, Mat& dst, const int flags )
  206. {
  207. if( dst.rows > 1 && (dst.cols > 1 || (flags & DFT_ROWS)) )
  208. {
  209. const int count = dst.rows;
  210. const int len = dst.cols;
  211. const bool is2d = (flags & DFT_ROWS) == 0;
  212. for( int i = 0; i < count; i++ )
  213. {
  214. const int j = !is2d || i == 0 ? i : count - i;
  215. const Mat& src0row = src0.row(i);
  216. const Mat& src1row = src1.row(j);
  217. Mat dstrow = dst.row(i);
  218. convert_from_ccs( src0row, src1row, dstrow, 0 );
  219. }
  220. if( is2d )
  221. {
  222. const Mat& src0row = src0.col(0);
  223. Mat dstrow = dst.col(0);
  224. convert_from_ccs( src0row, src0row, dstrow, 0 );
  225. if( (len & 1) == 0 )
  226. {
  227. const Mat& src0row_even = src0.col(src0.cols - 1);
  228. Mat dstrow_even = dst.col(len/2);
  229. convert_from_ccs( src0row_even, src0row_even, dstrow_even, 0 );
  230. }
  231. }
  232. }
  233. else
  234. {
  235. if( dst.depth() == CV_32F )
  236. {
  237. convert_from_ccs_helper<float>( src0, src1, dst );
  238. }
  239. else
  240. {
  241. convert_from_ccs_helper<double>( src0, src1, dst );
  242. }
  243. }
  244. }
  245. /// Helper function to compute complex number (nu_re + nu_im * i) / (de_re + de_im * i).
  246. static std::pair<double, double> divide_complex_numbers( const double nu_re, const double nu_im,
  247. const double de_re, const double de_im,
  248. const bool conj_de )
  249. {
  250. if ( conj_de )
  251. {
  252. return divide_complex_numbers( nu_re, nu_im, de_re, -de_im, false /* conj_de */ );
  253. }
  254. const double result_de = de_re * de_re + de_im * de_im + DBL_EPSILON;
  255. const double result_re = nu_re * de_re + nu_im * de_im;
  256. const double result_im = nu_re * (-de_im) + nu_im * de_re;
  257. return std::pair<double, double>(result_re / result_de, result_im / result_de);
  258. };
  259. /// Helper function to divide a DFT in src1 by a DFT in src2 with depths depth_t. The DFTs are
  260. /// complex matrices.
  261. template <typename depth_t>
  262. static void div_complex_helper( const Mat& src1, const Mat& src2, Mat& dst, int flags )
  263. {
  264. CV_Assert( src1.size == src2.size && src1.type() == src2.type() );
  265. dst.create( src1.rows, src1.cols, src1.type() );
  266. const int cn = src1.channels();
  267. int cols = src1.cols * cn;
  268. for( int i = 0; i < dst.rows; i++ )
  269. {
  270. const depth_t *src1_data = src1.ptr<depth_t>(i);
  271. const depth_t *src2_data = src2.ptr<depth_t>(i);
  272. depth_t *dst_data = dst.ptr<depth_t>(i);
  273. for( int j = 0; j < cols; j += 2 )
  274. {
  275. std::pair<double, double> result =
  276. divide_complex_numbers( src1_data[j], src1_data[j + 1],
  277. src2_data[j], src2_data[j + 1],
  278. (flags & CV_DXT_MUL_CONJ) != 0 );
  279. dst_data[j] = (depth_t)result.first;
  280. dst_data[j + 1] = (depth_t)result.second;
  281. }
  282. }
  283. }
  284. /// Helper function to divide a DFT in src1 by a DFT in src2. The DFTs are complex matrices.
  285. static void div_complex( const Mat& src1, const Mat& src2, Mat& dst, const int flags )
  286. {
  287. const int type = src1.type();
  288. CV_Assert( type == CV_32FC2 || type == CV_64FC2 );
  289. if ( src1.depth() == CV_32F )
  290. {
  291. return div_complex_helper<float>( src1, src2, dst, flags );
  292. }
  293. else
  294. {
  295. return div_complex_helper<double>( src1, src2, dst, flags );
  296. }
  297. }
  298. void CV_DivSpectrumsTest::prepare_to_validation( int /* test_case_idx */ )
  299. {
  300. Mat &src1 = test_mat[INPUT][0];
  301. Mat &src2 = test_mat[INPUT][1];
  302. Mat &ref_dst = test_mat[REF_OUTPUT][0];
  303. const int cn = src1.channels();
  304. // Inputs are CCS-packed arrays. Convert them to complex matrices and get the expected output
  305. // as a complex matrix.
  306. if( cn == 1 )
  307. {
  308. Mat &converted_src1 = test_mat[TEMP][0];
  309. Mat &converted_src2 = test_mat[TEMP][1];
  310. convert_from_ccs( src1, src1, converted_src1, flags );
  311. convert_from_ccs( src2, src2, converted_src2, flags );
  312. div_complex( converted_src1, converted_src2, ref_dst, flags );
  313. }
  314. // Inputs are complex matrices. Get the expected output as a complex matrix.
  315. else
  316. {
  317. div_complex( src1, src2, ref_dst, flags );
  318. }
  319. }
  320. void CV_DivSpectrumsTest::run_func()
  321. {
  322. const Mat &src1 = test_mat[INPUT][0];
  323. const Mat &src2 = test_mat[INPUT][1];
  324. const int cn = src1.channels();
  325. // Inputs are CCS-packed arrays. Get the output as a CCS-packed array and convert it to a
  326. // complex matrix.
  327. if ( cn == 1 )
  328. {
  329. Mat &dst = test_mat[TEMP][2];
  330. cv::divSpectrums( src1, src2, dst, flags, (flags & CV_DXT_MUL_CONJ) != 0 );
  331. Mat &converted_dst = test_mat[OUTPUT][0];
  332. convert_from_ccs( dst, dst, converted_dst, flags );
  333. }
  334. // Inputs are complex matrices. Get the output as a complex matrix.
  335. else
  336. {
  337. Mat &dst = test_mat[OUTPUT][0];
  338. cv::divSpectrums( src1, src2, dst, flags, (flags & CV_DXT_MUL_CONJ) != 0 );
  339. }
  340. }
  341. TEST(Imgproc_DivSpectrums, accuracy) { CV_DivSpectrumsTest test; test.safe_run(); }
  342. }} // namespace