test_pc.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  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. #define CV_DXT_MUL_CONJ 8
  44. namespace opencv_test { namespace {
  45. /// phase correlation
  46. class CV_PhaseCorrelatorTest : public cvtest::ArrayTest
  47. {
  48. public:
  49. CV_PhaseCorrelatorTest();
  50. protected:
  51. void run( int );
  52. };
  53. CV_PhaseCorrelatorTest::CV_PhaseCorrelatorTest() {}
  54. void CV_PhaseCorrelatorTest::run( int )
  55. {
  56. ts->set_failed_test_info(cvtest::TS::OK);
  57. Mat r1 = Mat::ones(Size(129, 128), CV_64F);
  58. Mat r2 = Mat::ones(Size(129, 128), CV_64F);
  59. double expectedShiftX = -10.0;
  60. double expectedShiftY = -20.0;
  61. // draw 10x10 rectangles @ (100, 100) and (90, 80) should see ~(-10, -20) shift here...
  62. cv::rectangle(r1, Point(100, 100), Point(110, 110), Scalar(0, 0, 0), cv::FILLED);
  63. cv::rectangle(r2, Point(90, 80), Point(100, 90), Scalar(0, 0, 0), cv::FILLED);
  64. Mat hann;
  65. createHanningWindow(hann, r1.size(), CV_64F);
  66. Point2d phaseShift = phaseCorrelate(r1, r2, hann);
  67. // test accuracy should be less than 1 pixel...
  68. if(std::abs(expectedShiftX - phaseShift.x) >= 1 || std::abs(expectedShiftY - phaseShift.y) >= 1)
  69. {
  70. ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
  71. }
  72. }
  73. TEST(Imgproc_PhaseCorrelatorTest, accuracy) { CV_PhaseCorrelatorTest test; test.safe_run(); }
  74. TEST(Imgproc_PhaseCorrelatorTest, accuracy_real_img)
  75. {
  76. Mat img = imread(cvtest::TS::ptr()->get_data_path() + "shared/airplane.png", IMREAD_GRAYSCALE);
  77. img.convertTo(img, CV_64FC1);
  78. const int xLen = 129;
  79. const int yLen = 129;
  80. const int xShift = 40;
  81. const int yShift = 14;
  82. Mat roi1 = img(Rect(xShift, yShift, xLen, yLen));
  83. Mat roi2 = img(Rect(0, 0, xLen, yLen));
  84. Mat hann;
  85. createHanningWindow(hann, roi1.size(), CV_64F);
  86. Point2d phaseShift = phaseCorrelate(roi1, roi2, hann);
  87. ASSERT_NEAR(phaseShift.x, (double)xShift, 1.);
  88. ASSERT_NEAR(phaseShift.y, (double)yShift, 1.);
  89. }
  90. TEST(Imgproc_PhaseCorrelatorTest, accuracy_1d_odd_fft) {
  91. Mat r1 = Mat::ones(Size(129, 1), CV_64F)*255; // 129 will be completed to 135 before FFT
  92. Mat r2 = Mat::ones(Size(129, 1), CV_64F)*255;
  93. const int xShift = 10;
  94. for(int i = 6; i < 20; i++)
  95. {
  96. r1.at<double>(i) = 1;
  97. r2.at<double>(i + xShift) = 1;
  98. }
  99. Point2d phaseShift = phaseCorrelate(r1, r2);
  100. ASSERT_NEAR(phaseShift.x, (double)xShift, 1.);
  101. }
  102. TEST(Imgproc_PhaseCorrelatorTest, float32_overflow) {
  103. // load
  104. Mat im = imread(cvtest::TS::ptr()->get_data_path() + "shared/baboon.png", IMREAD_GRAYSCALE);
  105. ASSERT_EQ(im.type(), CV_8UC1);
  106. // convert to 32F, scale values as if original image was 16U
  107. constexpr auto u8Max = std::numeric_limits<std::uint8_t>::max();
  108. constexpr auto u16Max = std::numeric_limits<std::uint16_t>::max();
  109. im.convertTo(im, CV_32FC1, double(u16Max) / double(u8Max));
  110. // enlarge and create ROIs
  111. const auto w = im.cols * 5;
  112. const auto h = im.rows * 5;
  113. const auto roiW = (w * 2) / 3; // 50% overlap
  114. Mat imLarge;
  115. resize(im, imLarge, { w, h });
  116. const auto roiLeft = imLarge(Rect(0, 0, roiW, h));
  117. const auto roiRight = imLarge(Rect(w - roiW, 0, roiW, h));
  118. // correlate
  119. double response = 0.0;
  120. Point2d phaseShift = phaseCorrelate(roiLeft, roiRight, cv::noArray(), &response);
  121. ASSERT_TRUE(std::isnormal(phaseShift.x) || 0.0 == phaseShift.x);
  122. ASSERT_TRUE(std::isnormal(phaseShift.y) || 0.0 == phaseShift.y);
  123. ASSERT_TRUE(std::isnormal(response) || 0.0 == response);
  124. EXPECT_NEAR(std::abs(phaseShift.x), w / 3.0, 1.0);
  125. EXPECT_NEAR(std::abs(phaseShift.y), 0.0, 1.0);
  126. }
  127. ////////////////////// DivSpectrums ////////////////////////
  128. class CV_DivSpectrumsTest : public cvtest::ArrayTest
  129. {
  130. public:
  131. CV_DivSpectrumsTest();
  132. protected:
  133. void run_func();
  134. void get_test_array_types_and_sizes( int, vector<vector<Size> >& sizes, vector<vector<int> >& types );
  135. void prepare_to_validation( int test_case_idx );
  136. int flags;
  137. };
  138. CV_DivSpectrumsTest::CV_DivSpectrumsTest() : flags(0)
  139. {
  140. // Allocate test matrices.
  141. test_array[INPUT].push_back(NULL); // first input DFT as a CCS-packed array or complex matrix.
  142. test_array[INPUT].push_back(NULL); // second input DFT as a CCS-packed array or complex matrix.
  143. test_array[OUTPUT].push_back(NULL); // output DFT as a complex matrix.
  144. test_array[REF_OUTPUT].push_back(NULL); // reference output DFT as a complex matrix.
  145. test_array[TEMP].push_back(NULL); // first input DFT converted to a complex matrix.
  146. test_array[TEMP].push_back(NULL); // second input DFT converted to a complex matrix.
  147. test_array[TEMP].push_back(NULL); // output DFT as a CCV-packed array.
  148. }
  149. void CV_DivSpectrumsTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
  150. {
  151. cvtest::ArrayTest::get_test_array_types_and_sizes(test_case_idx, sizes, types);
  152. RNG& rng = ts->get_rng();
  153. // Get the flag of the input.
  154. const int rand_int_flags = cvtest::randInt(rng);
  155. flags = rand_int_flags & (CV_DXT_MUL_CONJ | DFT_ROWS);
  156. // Get input type.
  157. const int rand_int_type = cvtest::randInt(rng);
  158. int type;
  159. if (rand_int_type % 4)
  160. {
  161. type = CV_32FC1;
  162. }
  163. else if (rand_int_type % 4 == 1)
  164. {
  165. type = CV_32FC2;
  166. }
  167. else if (rand_int_type % 4 == 2)
  168. {
  169. type = CV_64FC1;
  170. }
  171. else
  172. {
  173. type = CV_64FC2;
  174. }
  175. for( size_t i = 0; i < types.size(); i++ )
  176. {
  177. for( size_t j = 0; j < types[i].size(); j++ )
  178. {
  179. types[i][j] = type;
  180. }
  181. }
  182. // Inputs are CCS-packed arrays. Prepare outputs and temporary inputs as complex matrices.
  183. if( type == CV_32FC1 || type == CV_64FC1 )
  184. {
  185. types[OUTPUT][0] += 8;
  186. types[REF_OUTPUT][0] += 8;
  187. types[TEMP][0] += 8;
  188. types[TEMP][1] += 8;
  189. }
  190. }
  191. /// Helper function to convert a ccs array of depth_t into a complex matrix.
  192. template<typename depth_t>
  193. static void convert_from_ccs_helper( const Mat& src0, const Mat& src1, Mat& dst )
  194. {
  195. const int cn = src0.channels();
  196. int srcstep = cn;
  197. int dststep = 1;
  198. if( !dst.isContinuous() )
  199. dststep = (int)(dst.step/dst.elemSize());
  200. if( !src0.isContinuous() )
  201. srcstep = (int)(src0.step/src0.elemSize1());
  202. Complex<depth_t> *dst_data = dst.ptr<Complex<depth_t> >();
  203. const depth_t* src0_data = src0.ptr<depth_t>();
  204. const depth_t* src1_data = src1.ptr<depth_t>();
  205. dst_data->re = src0_data[0];
  206. dst_data->im = 0;
  207. const int n = dst.cols + dst.rows - 1;
  208. const int n2 = (n+1) >> 1;
  209. if( (n & 1) == 0 )
  210. {
  211. dst_data[n2*dststep].re = src0_data[(cn == 1 ? n-1 : n2)*srcstep];
  212. dst_data[n2*dststep].im = 0;
  213. }
  214. int delta0 = srcstep;
  215. int delta1 = delta0 + (cn == 1 ? srcstep : 1);
  216. if( cn == 1 )
  217. srcstep *= 2;
  218. for( int i = 1; i < n2; i++, delta0 += srcstep, delta1 += srcstep )
  219. {
  220. depth_t t0 = src0_data[delta0];
  221. depth_t t1 = src0_data[delta1];
  222. dst_data[i*dststep].re = t0;
  223. dst_data[i*dststep].im = t1;
  224. t0 = src1_data[delta0];
  225. t1 = -src1_data[delta1];
  226. dst_data[(n-i)*dststep].re = t0;
  227. dst_data[(n-i)*dststep].im = t1;
  228. }
  229. }
  230. /// Helper function to convert a ccs array into a complex matrix.
  231. static void convert_from_ccs( const Mat& src0, const Mat& src1, Mat& dst, const int flags )
  232. {
  233. if( dst.rows > 1 && (dst.cols > 1 || (flags & DFT_ROWS)) )
  234. {
  235. const int count = dst.rows;
  236. const int len = dst.cols;
  237. const bool is2d = (flags & DFT_ROWS) == 0;
  238. for( int i = 0; i < count; i++ )
  239. {
  240. const int j = !is2d || i == 0 ? i : count - i;
  241. const Mat& src0row = src0.row(i);
  242. const Mat& src1row = src1.row(j);
  243. Mat dstrow = dst.row(i);
  244. convert_from_ccs( src0row, src1row, dstrow, 0 );
  245. }
  246. if( is2d )
  247. {
  248. const Mat& src0row = src0.col(0);
  249. Mat dstrow = dst.col(0);
  250. convert_from_ccs( src0row, src0row, dstrow, 0 );
  251. if( (len & 1) == 0 )
  252. {
  253. const Mat& src0row_even = src0.col(src0.cols - 1);
  254. Mat dstrow_even = dst.col(len/2);
  255. convert_from_ccs( src0row_even, src0row_even, dstrow_even, 0 );
  256. }
  257. }
  258. }
  259. else
  260. {
  261. if( dst.depth() == CV_32F )
  262. {
  263. convert_from_ccs_helper<float>( src0, src1, dst );
  264. }
  265. else
  266. {
  267. convert_from_ccs_helper<double>( src0, src1, dst );
  268. }
  269. }
  270. }
  271. /// Helper function to compute complex number (nu_re + nu_im * i) / (de_re + de_im * i).
  272. static std::pair<double, double> divide_complex_numbers( const double nu_re, const double nu_im,
  273. const double de_re, const double de_im,
  274. const bool conj_de )
  275. {
  276. if ( conj_de )
  277. {
  278. return divide_complex_numbers( nu_re, nu_im, de_re, -de_im, false /* conj_de */ );
  279. }
  280. const double result_de = de_re * de_re + de_im * de_im + DBL_EPSILON;
  281. const double result_re = nu_re * de_re + nu_im * de_im;
  282. const double result_im = nu_re * (-de_im) + nu_im * de_re;
  283. return std::pair<double, double>(result_re / result_de, result_im / result_de);
  284. }
  285. /// Helper function to divide a DFT in src1 by a DFT in src2 with depths depth_t. The DFTs are
  286. /// complex matrices.
  287. template <typename depth_t>
  288. static void div_complex_helper( const Mat& src1, const Mat& src2, Mat& dst, int flags )
  289. {
  290. CV_Assert( src1.size == src2.size && src1.type() == src2.type() );
  291. dst.create( src1.rows, src1.cols, src1.type() );
  292. const int cn = src1.channels();
  293. int cols = src1.cols * cn;
  294. for( int i = 0; i < dst.rows; i++ )
  295. {
  296. const depth_t *src1_data = src1.ptr<depth_t>(i);
  297. const depth_t *src2_data = src2.ptr<depth_t>(i);
  298. depth_t *dst_data = dst.ptr<depth_t>(i);
  299. for( int j = 0; j < cols; j += 2 )
  300. {
  301. std::pair<double, double> result =
  302. divide_complex_numbers( src1_data[j], src1_data[j + 1],
  303. src2_data[j], src2_data[j + 1],
  304. (flags & CV_DXT_MUL_CONJ) != 0 );
  305. dst_data[j] = (depth_t)result.first;
  306. dst_data[j + 1] = (depth_t)result.second;
  307. }
  308. }
  309. }
  310. /// Helper function to divide a DFT in src1 by a DFT in src2. The DFTs are complex matrices.
  311. static void div_complex( const Mat& src1, const Mat& src2, Mat& dst, const int flags )
  312. {
  313. const int type = src1.type();
  314. CV_Assert( type == CV_32FC2 || type == CV_64FC2 );
  315. if ( src1.depth() == CV_32F )
  316. {
  317. return div_complex_helper<float>( src1, src2, dst, flags );
  318. }
  319. else
  320. {
  321. return div_complex_helper<double>( src1, src2, dst, flags );
  322. }
  323. }
  324. void CV_DivSpectrumsTest::prepare_to_validation( int /* test_case_idx */ )
  325. {
  326. Mat &src1 = test_mat[INPUT][0];
  327. Mat &src2 = test_mat[INPUT][1];
  328. Mat &ref_dst = test_mat[REF_OUTPUT][0];
  329. const int cn = src1.channels();
  330. // Inputs are CCS-packed arrays. Convert them to complex matrices and get the expected output
  331. // as a complex matrix.
  332. if( cn == 1 )
  333. {
  334. Mat &converted_src1 = test_mat[TEMP][0];
  335. Mat &converted_src2 = test_mat[TEMP][1];
  336. convert_from_ccs( src1, src1, converted_src1, flags );
  337. convert_from_ccs( src2, src2, converted_src2, flags );
  338. div_complex( converted_src1, converted_src2, ref_dst, flags );
  339. }
  340. // Inputs are complex matrices. Get the expected output as a complex matrix.
  341. else
  342. {
  343. div_complex( src1, src2, ref_dst, flags );
  344. }
  345. }
  346. void CV_DivSpectrumsTest::run_func()
  347. {
  348. const Mat &src1 = test_mat[INPUT][0];
  349. const Mat &src2 = test_mat[INPUT][1];
  350. const int cn = src1.channels();
  351. // Inputs are CCS-packed arrays. Get the output as a CCS-packed array and convert it to a
  352. // complex matrix.
  353. if ( cn == 1 )
  354. {
  355. Mat &dst = test_mat[TEMP][2];
  356. cv::divSpectrums( src1, src2, dst, flags, (flags & CV_DXT_MUL_CONJ) != 0 );
  357. Mat &converted_dst = test_mat[OUTPUT][0];
  358. convert_from_ccs( dst, dst, converted_dst, flags );
  359. }
  360. // Inputs are complex matrices. Get the output as a complex matrix.
  361. else
  362. {
  363. Mat &dst = test_mat[OUTPUT][0];
  364. cv::divSpectrums( src1, src2, dst, flags, (flags & CV_DXT_MUL_CONJ) != 0 );
  365. }
  366. }
  367. TEST(Imgproc_DivSpectrums, accuracy) { CV_DivSpectrumsTest test; test.safe_run(); }
  368. }} // namespace