test_homography.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  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. // Copyright (C) 2015, Itseez Inc., all rights reserved.
  16. // Third party copyrights are property of their respective owners.
  17. //
  18. // Redistribution and use in source and binary forms, with or without modification,
  19. // are permitted provided that the following conditions are met:
  20. //
  21. // * Redistribution's of source code must retain the above copyright notice,
  22. // this list of conditions and the following disclaimer.
  23. //
  24. // * Redistribution's in binary form must reproduce the above copyright notice,
  25. // this list of conditions and the following disclaimer in the documentation
  26. // and/or other materials provided with the distribution.
  27. //
  28. // * The name of the copyright holders may not be used to endorse or promote products
  29. // derived from this software without specific prior written permission.
  30. //
  31. // This software is provided by the copyright holders and contributors "as is" and
  32. // any express or implied warranties, including, but not limited to, the implied
  33. // warranties of merchantability and fitness for a particular purpose are disclaimed.
  34. // In no event shall the Intel Corporation or contributors be liable for any direct,
  35. // indirect, incidental, special, exemplary, or consequential damages
  36. // (including, but not limited to, procurement of substitute goods or services;
  37. // loss of use, data, or profits; or business interruption) however caused
  38. // and on any theory of liability, whether in contract, strict liability,
  39. // or tort (including negligence or otherwise) arising in any way out of
  40. // the use of this software, even if advised of the possibility of such damage.
  41. //
  42. //M*/
  43. #include "test_precomp.hpp"
  44. namespace opencv_test { namespace {
  45. #define CALIB3D_HOMOGRAPHY_ERROR_MATRIX_SIZE 1
  46. #define CALIB3D_HOMOGRAPHY_ERROR_MATRIX_DIFF 2
  47. #define CALIB3D_HOMOGRAPHY_ERROR_REPROJ_DIFF 3
  48. #define CALIB3D_HOMOGRAPHY_ERROR_RANSAC_MASK 4
  49. #define CALIB3D_HOMOGRAPHY_ERROR_RANSAC_DIFF 5
  50. #define MESSAGE_MATRIX_SIZE "Homography matrix must have 3*3 sizes."
  51. #define MESSAGE_MATRIX_DIFF "Accuracy of homography transformation matrix less than required."
  52. #define MESSAGE_REPROJ_DIFF_1 "Reprojection error for current pair of points more than required."
  53. #define MESSAGE_REPROJ_DIFF_2 "Reprojection error is not optimal."
  54. #define MESSAGE_RANSAC_MASK_1 "Sizes of inliers/outliers mask are incorrect."
  55. #define MESSAGE_RANSAC_MASK_2 "Mask mustn't have any outliers."
  56. #define MESSAGE_RANSAC_MASK_3 "All values of mask must be 1 (true) or 0 (false)."
  57. #define MESSAGE_RANSAC_MASK_4 "Mask of inliers/outliers is incorrect."
  58. #define MESSAGE_RANSAC_MASK_5 "Inlier in original mask shouldn't be outlier in found mask."
  59. #define MESSAGE_RANSAC_DIFF "Reprojection error for current pair of points more than required."
  60. #define MAX_COUNT_OF_POINTS 303
  61. #define MIN_COUNT_OF_POINTS 4
  62. #define COUNT_NORM_TYPES 3
  63. #define METHODS_COUNT 4
  64. int NORM_TYPE[COUNT_NORM_TYPES] = {cv::NORM_L1, cv::NORM_L2, cv::NORM_INF};
  65. int METHOD[METHODS_COUNT] = {0, cv::RANSAC, cv::LMEDS, cv::RHO};
  66. using namespace cv;
  67. using namespace std;
  68. class CV_HomographyTest: public cvtest::ArrayTest
  69. {
  70. public:
  71. CV_HomographyTest();
  72. ~CV_HomographyTest();
  73. void run (int);
  74. protected:
  75. int method;
  76. int image_size;
  77. double reproj_threshold;
  78. double sigma;
  79. private:
  80. float max_diff, max_2diff;
  81. bool check_matrix_size(const cv::Mat& H);
  82. bool check_matrix_diff(const cv::Mat& original, const cv::Mat& found, const int norm_type, double &diff);
  83. int check_ransac_mask_1(const Mat& src, const Mat& mask);
  84. int check_ransac_mask_2(const Mat& original_mask, const Mat& found_mask);
  85. void print_information_1(int j, int N, int method, const Mat& H);
  86. void print_information_2(int j, int N, int method, const Mat& H, const Mat& H_res, int k, double diff);
  87. void print_information_3(int method, int j, int N, const Mat& mask);
  88. void print_information_4(int method, int j, int N, int k, int l, double diff);
  89. void print_information_5(int method, int j, int N, int l, double diff);
  90. void print_information_6(int method, int j, int N, int k, double diff, bool value);
  91. void print_information_7(int method, int j, int N, int k, double diff, bool original_value, bool found_value);
  92. void print_information_8(int method, int j, int N, int k, int l, double diff);
  93. };
  94. CV_HomographyTest::CV_HomographyTest() : max_diff(1e-2f), max_2diff(2e-2f)
  95. {
  96. method = 0;
  97. image_size = 100;
  98. reproj_threshold = 3.0;
  99. sigma = 0.01;
  100. }
  101. CV_HomographyTest::~CV_HomographyTest() {}
  102. bool CV_HomographyTest::check_matrix_size(const cv::Mat& H)
  103. {
  104. return (H.rows == 3) && (H.cols == 3);
  105. }
  106. bool CV_HomographyTest::check_matrix_diff(const cv::Mat& original, const cv::Mat& found, const int norm_type, double &diff)
  107. {
  108. diff = cvtest::norm(original, found, norm_type);
  109. return diff <= max_diff;
  110. }
  111. int CV_HomographyTest::check_ransac_mask_1(const Mat& src, const Mat& mask)
  112. {
  113. if (!(mask.cols == 1) && (mask.rows == src.cols)) return 1;
  114. if (countNonZero(mask) < mask.rows) return 2;
  115. for (int i = 0; i < mask.rows; ++i) if (mask.at<uchar>(i, 0) > 1) return 3;
  116. return 0;
  117. }
  118. int CV_HomographyTest::check_ransac_mask_2(const Mat& original_mask, const Mat& found_mask)
  119. {
  120. if (!(found_mask.cols == 1) && (found_mask.rows == original_mask.rows)) return 1;
  121. for (int i = 0; i < found_mask.rows; ++i) if (found_mask.at<uchar>(i, 0) > 1) return 2;
  122. return 0;
  123. }
  124. void CV_HomographyTest::print_information_1(int j, int N, int _method, const Mat& H)
  125. {
  126. cout << endl; cout << "Checking for homography matrix sizes..." << endl; cout << endl;
  127. cout << "Type of srcPoints: "; if ((j>-1) && (j<2)) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>";
  128. cout << " Type of dstPoints: "; if (j % 2 == 0) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>"; cout << endl;
  129. cout << "Count of points: " << N << endl; cout << endl;
  130. cout << "Method: "; if (_method == 0) cout << 0; else if (_method == 8) cout << "RANSAC"; else if (_method == cv::RHO) cout << "RHO"; else cout << "LMEDS"; cout << endl;
  131. cout << "Homography matrix:" << endl; cout << endl;
  132. cout << H << endl; cout << endl;
  133. cout << "Number of rows: " << H.rows << " Number of cols: " << H.cols << endl; cout << endl;
  134. }
  135. void CV_HomographyTest::print_information_2(int j, int N, int _method, const Mat& H, const Mat& H_res, int k, double diff)
  136. {
  137. cout << endl; cout << "Checking for accuracy of homography matrix computing..." << endl; cout << endl;
  138. cout << "Type of srcPoints: "; if ((j>-1) && (j<2)) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>";
  139. cout << " Type of dstPoints: "; if (j % 2 == 0) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>"; cout << endl;
  140. cout << "Count of points: " << N << endl; cout << endl;
  141. cout << "Method: "; if (_method == 0) cout << 0; else if (_method == 8) cout << "RANSAC"; else if (_method == cv::RHO) cout << "RHO"; else cout << "LMEDS"; cout << endl;
  142. cout << "Original matrix:" << endl; cout << endl;
  143. cout << H << endl; cout << endl;
  144. cout << "Found matrix:" << endl; cout << endl;
  145. cout << H_res << endl; cout << endl;
  146. cout << "Norm type using in criteria: "; if (NORM_TYPE[k] == 1) cout << "INF"; else if (NORM_TYPE[k] == 2) cout << "L1"; else cout << "L2"; cout << endl;
  147. cout << "Difference between matrices: " << diff << endl;
  148. cout << "Maximum allowed difference: " << max_diff << endl; cout << endl;
  149. }
  150. void CV_HomographyTest::print_information_3(int _method, int j, int N, const Mat& mask)
  151. {
  152. cout << endl; cout << "Checking for inliers/outliers mask..." << endl; cout << endl;
  153. cout << "Type of srcPoints: "; if ((j>-1) && (j<2)) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>";
  154. cout << " Type of dstPoints: "; if (j % 2 == 0) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>"; cout << endl;
  155. cout << "Count of points: " << N << endl; cout << endl;
  156. cout << "Method: "; if (_method == RANSAC) cout << "RANSAC" << endl; else if (_method == cv::RHO) cout << "RHO" << endl; else cout << _method << endl;
  157. cout << "Found mask:" << endl; cout << endl;
  158. cout << mask << endl; cout << endl;
  159. cout << "Number of rows: " << mask.rows << " Number of cols: " << mask.cols << endl; cout << endl;
  160. }
  161. void CV_HomographyTest::print_information_4(int _method, int j, int N, int k, int l, double diff)
  162. {
  163. cout << endl; cout << "Checking for accuracy of reprojection error computing..." << endl; cout << endl;
  164. cout << "Method: "; if (_method == 0) cout << 0 << endl; else cout << "CV_LMEDS" << endl;
  165. cout << "Type of srcPoints: "; if ((j>-1) && (j<2)) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>";
  166. cout << " Type of dstPoints: "; if (j % 2 == 0) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>"; cout << endl;
  167. cout << "Sigma of normal noise: " << sigma << endl;
  168. cout << "Count of points: " << N << endl;
  169. cout << "Number of point: " << k << endl;
  170. cout << "Norm type using in criteria: "; if (NORM_TYPE[l] == 1) cout << "INF"; else if (NORM_TYPE[l] == 2) cout << "L1"; else cout << "L2"; cout << endl;
  171. cout << "Difference with noise of point: " << diff << endl;
  172. cout << "Maximum allowed difference: " << max_2diff << endl; cout << endl;
  173. }
  174. void CV_HomographyTest::print_information_5(int _method, int j, int N, int l, double diff)
  175. {
  176. cout << endl; cout << "Checking for accuracy of reprojection error computing..." << endl; cout << endl;
  177. cout << "Method: "; if (_method == 0) cout << 0 << endl; else cout << "CV_LMEDS" << endl;
  178. cout << "Type of srcPoints: "; if ((j>-1) && (j<2)) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>";
  179. cout << " Type of dstPoints: "; if (j % 2 == 0) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>"; cout << endl;
  180. cout << "Sigma of normal noise: " << sigma << endl;
  181. cout << "Count of points: " << N << endl;
  182. cout << "Norm type using in criteria: "; if (NORM_TYPE[l] == 1) cout << "INF"; else if (NORM_TYPE[l] == 2) cout << "L1"; else cout << "L2"; cout << endl;
  183. cout << "Difference with noise of points: " << diff << endl;
  184. cout << "Maximum allowed difference: " << max_diff << endl; cout << endl;
  185. }
  186. void CV_HomographyTest::print_information_6(int _method, int j, int N, int k, double diff, bool value)
  187. {
  188. cout << endl; cout << "Checking for inliers/outliers mask..." << endl; cout << endl;
  189. cout << "Method: "; if (_method == RANSAC) cout << "RANSAC" << endl; else if (_method == cv::RHO) cout << "RHO" << endl; else cout << _method << endl;
  190. cout << "Type of srcPoints: "; if ((j>-1) && (j<2)) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>";
  191. cout << " Type of dstPoints: "; if (j % 2 == 0) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>"; cout << endl;
  192. cout << "Count of points: " << N << " " << endl;
  193. cout << "Number of point: " << k << " " << endl;
  194. cout << "Reprojection error for this point: " << diff << " " << endl;
  195. cout << "Reprojection error threshold: " << reproj_threshold << " " << endl;
  196. cout << "Value of found mask: "<< value << endl; cout << endl;
  197. }
  198. void CV_HomographyTest::print_information_7(int _method, int j, int N, int k, double diff, bool original_value, bool found_value)
  199. {
  200. cout << endl; cout << "Checking for inliers/outliers mask..." << endl; cout << endl;
  201. cout << "Method: "; if (_method == RANSAC) cout << "RANSAC" << endl; else if (_method == cv::RHO) cout << "RHO" << endl; else cout << _method << endl;
  202. cout << "Type of srcPoints: "; if ((j>-1) && (j<2)) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>";
  203. cout << " Type of dstPoints: "; if (j % 2 == 0) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>"; cout << endl;
  204. cout << "Count of points: " << N << " " << endl;
  205. cout << "Number of point: " << k << " " << endl;
  206. cout << "Reprojection error for this point: " << diff << " " << endl;
  207. cout << "Reprojection error threshold: " << reproj_threshold << " " << endl;
  208. cout << "Value of original mask: "<< original_value << " Value of found mask: " << found_value << endl; cout << endl;
  209. }
  210. void CV_HomographyTest::print_information_8(int _method, int j, int N, int k, int l, double diff)
  211. {
  212. cout << endl; cout << "Checking for reprojection error of inlier..." << endl; cout << endl;
  213. cout << "Method: "; if (_method == RANSAC) cout << "RANSAC" << endl; else if (_method == cv::RHO) cout << "RHO" << endl; else cout << _method << endl;
  214. cout << "Sigma of normal noise: " << sigma << endl;
  215. cout << "Type of srcPoints: "; if ((j>-1) && (j<2)) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>";
  216. cout << " Type of dstPoints: "; if (j % 2 == 0) cout << "Mat of CV_32FC2"; else cout << "vector <Point2f>"; cout << endl;
  217. cout << "Count of points: " << N << " " << endl;
  218. cout << "Number of point: " << k << " " << endl;
  219. cout << "Norm type using in criteria: "; if (NORM_TYPE[l] == 1) cout << "INF"; else if (NORM_TYPE[l] == 2) cout << "L1"; else cout << "L2"; cout << endl;
  220. cout << "Difference with noise of point: " << diff << endl;
  221. cout << "Maximum allowed difference: " << max_2diff << endl; cout << endl;
  222. }
  223. void CV_HomographyTest::run(int)
  224. {
  225. for (int N = MIN_COUNT_OF_POINTS; N <= MAX_COUNT_OF_POINTS; ++N)
  226. {
  227. RNG& rng = ts->get_rng();
  228. float *src_data = new float [2*N];
  229. for (int i = 0; i < N; ++i)
  230. {
  231. src_data[2*i] = (float)cvtest::randReal(rng)*image_size;
  232. src_data[2*i+1] = (float)cvtest::randReal(rng)*image_size;
  233. }
  234. cv::Mat src_mat_2f(1, N, CV_32FC2, src_data),
  235. src_mat_2d(2, N, CV_32F, src_data),
  236. src_mat_3d(3, N, CV_32F);
  237. cv::Mat dst_mat_2f, dst_mat_2d, dst_mat_3d;
  238. vector <Point2f> src_vec, dst_vec;
  239. for (int i = 0; i < N; ++i)
  240. {
  241. float *tmp = src_mat_2d.ptr<float>()+2*i;
  242. src_mat_3d.at<float>(0, i) = tmp[0];
  243. src_mat_3d.at<float>(1, i) = tmp[1];
  244. src_mat_3d.at<float>(2, i) = 1.0f;
  245. src_vec.push_back(Point2f(tmp[0], tmp[1]));
  246. }
  247. double fi = cvtest::randReal(rng)*2*CV_PI;
  248. double t_x = cvtest::randReal(rng)*sqrt(image_size*1.0),
  249. t_y = cvtest::randReal(rng)*sqrt(image_size*1.0);
  250. double Hdata[9] = { cos(fi), -sin(fi), t_x,
  251. sin(fi), cos(fi), t_y,
  252. 0.0f, 0.0f, 1.0f };
  253. cv::Mat H_64(3, 3, CV_64F, Hdata), H_32;
  254. H_64.convertTo(H_32, CV_32F);
  255. dst_mat_3d = H_32*src_mat_3d;
  256. dst_mat_2d.create(2, N, CV_32F); dst_mat_2f.create(1, N, CV_32FC2);
  257. for (int i = 0; i < N; ++i)
  258. {
  259. float *tmp_2f = dst_mat_2f.ptr<float>()+2*i;
  260. tmp_2f[0] = dst_mat_2d.at<float>(0, i) = dst_mat_3d.at<float>(0, i) /= dst_mat_3d.at<float>(2, i);
  261. tmp_2f[1] = dst_mat_2d.at<float>(1, i) = dst_mat_3d.at<float>(1, i) /= dst_mat_3d.at<float>(2, i);
  262. dst_mat_3d.at<float>(2, i) = 1.0f;
  263. dst_vec.push_back(Point2f(tmp_2f[0], tmp_2f[1]));
  264. }
  265. for (int i = 0; i < METHODS_COUNT; ++i)
  266. {
  267. method = METHOD[i];
  268. switch (method)
  269. {
  270. case 0:
  271. case LMEDS:
  272. {
  273. Mat H_res_64 [4] = { cv::findHomography(src_mat_2f, dst_mat_2f, method),
  274. cv::findHomography(src_mat_2f, dst_vec, method),
  275. cv::findHomography(src_vec, dst_mat_2f, method),
  276. cv::findHomography(src_vec, dst_vec, method) };
  277. for (int j = 0; j < 4; ++j)
  278. {
  279. if (!check_matrix_size(H_res_64[j]))
  280. {
  281. print_information_1(j, N, method, H_res_64[j]);
  282. CV_Error(CALIB3D_HOMOGRAPHY_ERROR_MATRIX_SIZE, MESSAGE_MATRIX_SIZE);
  283. return;
  284. }
  285. double diff;
  286. for (int k = 0; k < COUNT_NORM_TYPES; ++k)
  287. if (!check_matrix_diff(H_64, H_res_64[j], NORM_TYPE[k], diff))
  288. {
  289. print_information_2(j, N, method, H_64, H_res_64[j], k, diff);
  290. CV_Error(CALIB3D_HOMOGRAPHY_ERROR_MATRIX_DIFF, MESSAGE_MATRIX_DIFF);
  291. return;
  292. }
  293. }
  294. continue;
  295. }
  296. case cv::RHO:
  297. case RANSAC:
  298. {
  299. cv::Mat mask [4]; double diff;
  300. Mat H_res_64 [4] = { cv::findHomography(src_mat_2f, dst_mat_2f, method, reproj_threshold, mask[0]),
  301. cv::findHomography(src_mat_2f, dst_vec, method, reproj_threshold, mask[1]),
  302. cv::findHomography(src_vec, dst_mat_2f, method, reproj_threshold, mask[2]),
  303. cv::findHomography(src_vec, dst_vec, method, reproj_threshold, mask[3]) };
  304. for (int j = 0; j < 4; ++j)
  305. {
  306. if (!check_matrix_size(H_res_64[j]))
  307. {
  308. print_information_1(j, N, method, H_res_64[j]);
  309. CV_Error(CALIB3D_HOMOGRAPHY_ERROR_MATRIX_SIZE, MESSAGE_MATRIX_SIZE);
  310. return;
  311. }
  312. for (int k = 0; k < COUNT_NORM_TYPES; ++k)
  313. if (!check_matrix_diff(H_64, H_res_64[j], NORM_TYPE[k], diff))
  314. {
  315. print_information_2(j, N, method, H_64, H_res_64[j], k, diff);
  316. CV_Error(CALIB3D_HOMOGRAPHY_ERROR_MATRIX_DIFF, MESSAGE_MATRIX_DIFF);
  317. return;
  318. }
  319. int code = check_ransac_mask_1(src_mat_2f, mask[j]);
  320. if (code)
  321. {
  322. print_information_3(method, j, N, mask[j]);
  323. switch (code)
  324. {
  325. case 1: { CV_Error(CALIB3D_HOMOGRAPHY_ERROR_RANSAC_MASK, MESSAGE_RANSAC_MASK_1); break; }
  326. case 2: { CV_Error(CALIB3D_HOMOGRAPHY_ERROR_RANSAC_MASK, MESSAGE_RANSAC_MASK_2); break; }
  327. case 3: { CV_Error(CALIB3D_HOMOGRAPHY_ERROR_RANSAC_MASK, MESSAGE_RANSAC_MASK_3); break; }
  328. default: break;
  329. }
  330. return;
  331. }
  332. }
  333. continue;
  334. }
  335. default: continue;
  336. }
  337. }
  338. Mat noise_2f(1, N, CV_32FC2);
  339. rng.fill(noise_2f, RNG::NORMAL, Scalar::all(0), Scalar::all(sigma));
  340. cv::Mat mask(N, 1, CV_8UC1);
  341. for (int i = 0; i < N; ++i)
  342. {
  343. float *a = noise_2f.ptr<float>()+2*i, *_2f = dst_mat_2f.ptr<float>()+2*i;
  344. _2f[0] += a[0]; _2f[1] += a[1];
  345. mask.at<bool>(i, 0) = !(sqrt(a[0]*a[0]+a[1]*a[1]) > reproj_threshold);
  346. }
  347. for (int i = 0; i < METHODS_COUNT; ++i)
  348. {
  349. method = METHOD[i];
  350. switch (method)
  351. {
  352. case 0:
  353. case LMEDS:
  354. {
  355. Mat H_res_64 [4] = { cv::findHomography(src_mat_2f, dst_mat_2f),
  356. cv::findHomography(src_mat_2f, dst_vec),
  357. cv::findHomography(src_vec, dst_mat_2f),
  358. cv::findHomography(src_vec, dst_vec) };
  359. for (int j = 0; j < 4; ++j)
  360. {
  361. if (!check_matrix_size(H_res_64[j]))
  362. {
  363. print_information_1(j, N, method, H_res_64[j]);
  364. CV_Error(CALIB3D_HOMOGRAPHY_ERROR_MATRIX_SIZE, MESSAGE_MATRIX_SIZE);
  365. return;
  366. }
  367. Mat H_res_32; H_res_64[j].convertTo(H_res_32, CV_32F);
  368. cv::Mat dst_res_3d(3, N, CV_32F), noise_2d(2, N, CV_32F);
  369. for (int k = 0; k < N; ++k)
  370. {
  371. Mat tmp_mat_3d = H_res_32*src_mat_3d.col(k);
  372. dst_res_3d.at<float>(0, k) = tmp_mat_3d.at<float>(0, 0) /= tmp_mat_3d.at<float>(2, 0);
  373. dst_res_3d.at<float>(1, k) = tmp_mat_3d.at<float>(1, 0) /= tmp_mat_3d.at<float>(2, 0);
  374. dst_res_3d.at<float>(2, k) = tmp_mat_3d.at<float>(2, 0) = 1.0f;
  375. float *a = noise_2f.ptr<float>()+2*k;
  376. noise_2d.at<float>(0, k) = a[0]; noise_2d.at<float>(1, k) = a[1];
  377. for (int l = 0; l < COUNT_NORM_TYPES; ++l)
  378. if (cv::norm(tmp_mat_3d, dst_mat_3d.col(k), NORM_TYPE[l]) - cv::norm(noise_2d.col(k), NORM_TYPE[l]) > max_2diff)
  379. {
  380. print_information_4(method, j, N, k, l, cv::norm(tmp_mat_3d, dst_mat_3d.col(k), NORM_TYPE[l]) - cv::norm(noise_2d.col(k), NORM_TYPE[l]));
  381. CV_Error(CALIB3D_HOMOGRAPHY_ERROR_REPROJ_DIFF, MESSAGE_REPROJ_DIFF_1);
  382. return;
  383. }
  384. }
  385. for (int l = 0; l < COUNT_NORM_TYPES; ++l)
  386. if (cv::norm(dst_res_3d, dst_mat_3d, NORM_TYPE[l]) - cv::norm(noise_2d, NORM_TYPE[l]) > max_diff)
  387. {
  388. print_information_5(method, j, N, l, cv::norm(dst_res_3d, dst_mat_3d, NORM_TYPE[l]) - cv::norm(noise_2d, NORM_TYPE[l]));
  389. CV_Error(CALIB3D_HOMOGRAPHY_ERROR_REPROJ_DIFF, MESSAGE_REPROJ_DIFF_2);
  390. return;
  391. }
  392. }
  393. continue;
  394. }
  395. case cv::RHO:
  396. case RANSAC:
  397. {
  398. cv::Mat mask_res [4];
  399. Mat H_res_64 [4] = { cv::findHomography(src_mat_2f, dst_mat_2f, method, reproj_threshold, mask_res[0]),
  400. cv::findHomography(src_mat_2f, dst_vec, method, reproj_threshold, mask_res[1]),
  401. cv::findHomography(src_vec, dst_mat_2f, method, reproj_threshold, mask_res[2]),
  402. cv::findHomography(src_vec, dst_vec, method, reproj_threshold, mask_res[3]) };
  403. for (int j = 0; j < 4; ++j)
  404. {
  405. if (!check_matrix_size(H_res_64[j]))
  406. {
  407. print_information_1(j, N, method, H_res_64[j]);
  408. CV_Error(CALIB3D_HOMOGRAPHY_ERROR_MATRIX_SIZE, MESSAGE_MATRIX_SIZE);
  409. return;
  410. }
  411. int code = check_ransac_mask_2(mask, mask_res[j]);
  412. if (code)
  413. {
  414. print_information_3(method, j, N, mask_res[j]);
  415. switch (code)
  416. {
  417. case 1: { CV_Error(CALIB3D_HOMOGRAPHY_ERROR_RANSAC_MASK, MESSAGE_RANSAC_MASK_1); break; }
  418. case 2: { CV_Error(CALIB3D_HOMOGRAPHY_ERROR_RANSAC_MASK, MESSAGE_RANSAC_MASK_3); break; }
  419. default: break;
  420. }
  421. return;
  422. }
  423. cv::Mat H_res_32; H_res_64[j].convertTo(H_res_32, CV_32F);
  424. cv::Mat dst_res_3d = H_res_32*src_mat_3d;
  425. for (int k = 0; k < N; ++k)
  426. {
  427. dst_res_3d.at<float>(0, k) /= dst_res_3d.at<float>(2, k);
  428. dst_res_3d.at<float>(1, k) /= dst_res_3d.at<float>(2, k);
  429. dst_res_3d.at<float>(2, k) = 1.0f;
  430. float *p = dst_mat_2f.ptr<float>()+2*k;
  431. dst_mat_3d.at<float>(0, k) = p[0];
  432. dst_mat_3d.at<float>(1, k) = p[1];
  433. double diff = cv::norm(dst_res_3d.col(k), dst_mat_3d.col(k), NORM_L2);
  434. if (mask_res[j].at<bool>(k, 0) != (diff <= reproj_threshold))
  435. {
  436. print_information_6(method, j, N, k, diff, mask_res[j].at<bool>(k, 0));
  437. CV_Error(CALIB3D_HOMOGRAPHY_ERROR_RANSAC_MASK, MESSAGE_RANSAC_MASK_4);
  438. return;
  439. }
  440. if (mask.at<bool>(k, 0) && !mask_res[j].at<bool>(k, 0))
  441. {
  442. print_information_7(method, j, N, k, diff, mask.at<bool>(k, 0), mask_res[j].at<bool>(k, 0));
  443. CV_Error(CALIB3D_HOMOGRAPHY_ERROR_RANSAC_MASK, MESSAGE_RANSAC_MASK_5);
  444. return;
  445. }
  446. if (mask_res[j].at<bool>(k, 0))
  447. {
  448. float *a = noise_2f.ptr<float>()+2*k;
  449. dst_mat_3d.at<float>(0, k) -= a[0];
  450. dst_mat_3d.at<float>(1, k) -= a[1];
  451. cv::Mat noise_2d(2, 1, CV_32F);
  452. noise_2d.at<float>(0, 0) = a[0]; noise_2d.at<float>(1, 0) = a[1];
  453. for (int l = 0; l < COUNT_NORM_TYPES; ++l)
  454. {
  455. diff = cv::norm(dst_res_3d.col(k), dst_mat_3d.col(k), NORM_TYPE[l]);
  456. if (diff - cv::norm(noise_2d, NORM_TYPE[l]) > max_2diff)
  457. {
  458. print_information_8(method, j, N, k, l, diff - cv::norm(noise_2d, NORM_TYPE[l]));
  459. CV_Error(CALIB3D_HOMOGRAPHY_ERROR_RANSAC_DIFF, MESSAGE_RANSAC_DIFF);
  460. return;
  461. }
  462. }
  463. }
  464. }
  465. }
  466. continue;
  467. }
  468. default: continue;
  469. }
  470. }
  471. delete[]src_data;
  472. src_data = NULL;
  473. }
  474. }
  475. TEST(Calib3d_Homography, accuracy) { CV_HomographyTest test; test.safe_run(); }
  476. TEST(Calib3d_Homography, EKcase)
  477. {
  478. float pt1data[] =
  479. {
  480. 2.80073029e+002f, 2.39591217e+002f, 2.21912201e+002f, 2.59783997e+002f,
  481. 2.16053192e+002f, 2.78826569e+002f, 2.22782532e+002f, 2.82330383e+002f,
  482. 2.09924820e+002f, 2.89122559e+002f, 2.11077698e+002f, 2.89384674e+002f,
  483. 2.25287689e+002f, 2.88795532e+002f, 2.11180801e+002f, 2.89653503e+002f,
  484. 2.24126404e+002f, 2.90466064e+002f, 2.10914429e+002f, 2.90886963e+002f,
  485. 2.23439362e+002f, 2.91657715e+002f, 2.24809387e+002f, 2.91891602e+002f,
  486. 2.09809082e+002f, 2.92891113e+002f, 2.08771164e+002f, 2.93093231e+002f,
  487. 2.23160095e+002f, 2.93259460e+002f, 2.07874023e+002f, 2.93989990e+002f,
  488. 2.08963638e+002f, 2.94209839e+002f, 2.23963165e+002f, 2.94479645e+002f,
  489. 2.23241791e+002f, 2.94887817e+002f, 2.09438782e+002f, 2.95233337e+002f,
  490. 2.08901886e+002f, 2.95762878e+002f, 2.21867981e+002f, 2.95747711e+002f,
  491. 2.24195511e+002f, 2.98270905e+002f, 2.09331345e+002f, 3.05958191e+002f,
  492. 2.24727875e+002f, 3.07186035e+002f, 2.26718842e+002f, 3.08095795e+002f,
  493. 2.25363953e+002f, 3.08200226e+002f, 2.19897797e+002f, 3.13845093e+002f,
  494. 2.25013474e+002f, 3.15558777e+002f
  495. };
  496. float pt2data[] =
  497. {
  498. 1.84072723e+002f, 1.43591202e+002f, 1.25912483e+002f, 1.63783859e+002f,
  499. 2.06439407e+002f, 2.20573929e+002f, 1.43801437e+002f, 1.80703903e+002f,
  500. 9.77904129e+000f, 2.49660202e+002f, 1.38458405e+001f, 2.14502701e+002f,
  501. 1.50636337e+002f, 2.15597183e+002f, 6.43103180e+001f, 2.51667648e+002f,
  502. 1.54952499e+002f, 2.20780014e+002f, 1.26638412e+002f, 2.43040924e+002f,
  503. 3.67568909e+002f, 1.83624954e+001f, 1.60657944e+002f, 2.21794052e+002f,
  504. -1.29507828e+000f, 3.32472443e+002f, 8.51442242e+000f, 4.15561554e+002f,
  505. 1.27161377e+002f, 1.97260361e+002f, 5.40714645e+000f, 4.90978302e+002f,
  506. 2.25571690e+001f, 3.96912415e+002f, 2.95664978e+002f, 7.36064959e+000f,
  507. 1.27241104e+002f, 1.98887573e+002f, -1.25569367e+000f, 3.87713226e+002f,
  508. 1.04194012e+001f, 4.31495758e+002f, 1.25868874e+002f, 1.99751617e+002f,
  509. 1.28195480e+002f, 2.02270355e+002f, 2.23436356e+002f, 1.80489182e+002f,
  510. 1.28727692e+002f, 2.11185410e+002f, 2.03336639e+002f, 2.52182083e+002f,
  511. 1.29366486e+002f, 2.12201904e+002f, 1.23897598e+002f, 2.17847351e+002f,
  512. 1.29015259e+002f, 2.19560623e+002f
  513. };
  514. int npoints = (int)(sizeof(pt1data)/sizeof(pt1data[0])/2);
  515. Mat p1(1, npoints, CV_32FC2, pt1data);
  516. Mat p2(1, npoints, CV_32FC2, pt2data);
  517. Mat mask;
  518. Mat h = findHomography(p1, p2, RANSAC, 0.01, mask);
  519. ASSERT_TRUE(!h.empty());
  520. cv::transpose(mask, mask);
  521. Mat p3, mask2;
  522. int ninliers = countNonZero(mask);
  523. Mat nmask[] = { mask, mask };
  524. merge(nmask, 2, mask2);
  525. perspectiveTransform(p1, p3, h);
  526. mask2 = mask2.reshape(1);
  527. p2 = p2.reshape(1);
  528. p3 = p3.reshape(1);
  529. double err = cvtest::norm(p2, p3, NORM_INF, mask2);
  530. printf("ninliers: %d, inliers err: %.2g\n", ninliers, err);
  531. ASSERT_GE(ninliers, 10);
  532. ASSERT_LE(err, 0.01);
  533. }
  534. TEST(Calib3d_Homography, fromImages)
  535. {
  536. Mat img_1 = imread(cvtest::TS::ptr()->get_data_path() + "cv/optflow/image1.png", 0);
  537. Mat img_2 = imread(cvtest::TS::ptr()->get_data_path() + "cv/optflow/image2.png", 0);
  538. Ptr<ORB> orb = ORB::create();
  539. vector<KeyPoint> keypoints_1, keypoints_2;
  540. Mat descriptors_1, descriptors_2;
  541. orb->detectAndCompute( img_1, Mat(), keypoints_1, descriptors_1, false );
  542. orb->detectAndCompute( img_2, Mat(), keypoints_2, descriptors_2, false );
  543. //-- Step 3: Matching descriptor vectors using Brute Force matcher
  544. BFMatcher matcher(NORM_HAMMING,false);
  545. std::vector< DMatch > matches;
  546. matcher.match( descriptors_1, descriptors_2, matches );
  547. double max_dist = 0; double min_dist = 100;
  548. //-- Quick calculation of max and min distances between keypoints
  549. for( int i = 0; i < descriptors_1.rows; i++ )
  550. {
  551. double dist = matches[i].distance;
  552. if( dist < min_dist ) min_dist = dist;
  553. if( dist > max_dist ) max_dist = dist;
  554. }
  555. //-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
  556. std::vector< DMatch > good_matches;
  557. for( int i = 0; i < descriptors_1.rows; i++ )
  558. {
  559. if( matches[i].distance <= 100 )
  560. good_matches.push_back( matches[i]);
  561. }
  562. //-- Localize the model
  563. std::vector<Point2f> pointframe1;
  564. std::vector<Point2f> pointframe2;
  565. for( int i = 0; i < (int)good_matches.size(); i++ )
  566. {
  567. //-- Get the keypoints from the good matches
  568. pointframe1.push_back( keypoints_1[ good_matches[i].queryIdx ].pt );
  569. pointframe2.push_back( keypoints_2[ good_matches[i].trainIdx ].pt );
  570. }
  571. Mat H0, H1, inliers0, inliers1;
  572. double min_t0 = DBL_MAX, min_t1 = DBL_MAX;
  573. for( int i = 0; i < 10; i++ )
  574. {
  575. double t = (double)getTickCount();
  576. H0 = findHomography( pointframe1, pointframe2, RANSAC, 3.0, inliers0 );
  577. t = (double)getTickCount() - t;
  578. min_t0 = std::min(min_t0, t);
  579. }
  580. int ninliers0 = countNonZero(inliers0);
  581. for( int i = 0; i < 10; i++ )
  582. {
  583. double t = (double)getTickCount();
  584. H1 = findHomography( pointframe1, pointframe2, RHO, 3.0, inliers1 );
  585. t = (double)getTickCount() - t;
  586. min_t1 = std::min(min_t1, t);
  587. }
  588. int ninliers1 = countNonZero(inliers1);
  589. double freq = getTickFrequency();
  590. printf("nfeatures1 = %d, nfeatures2=%d, matches=%d, ninliers(RANSAC)=%d, "
  591. "time(RANSAC)=%.2fmsec, ninliers(RHO)=%d, time(RHO)=%.2fmsec\n",
  592. (int)keypoints_1.size(), (int)keypoints_2.size(),
  593. (int)good_matches.size(), ninliers0, min_t0*1000./freq, ninliers1, min_t1*1000./freq);
  594. ASSERT_TRUE(!H0.empty());
  595. ASSERT_GE(ninliers0, 80);
  596. ASSERT_TRUE(!H1.empty());
  597. ASSERT_GE(ninliers1, 80);
  598. }
  599. TEST(Calib3d_Homography, minPoints)
  600. {
  601. float pt1data[] =
  602. {
  603. 2.80073029e+002f, 2.39591217e+002f, 2.21912201e+002f, 2.59783997e+002f
  604. };
  605. float pt2data[] =
  606. {
  607. 1.84072723e+002f, 1.43591202e+002f, 1.25912483e+002f, 1.63783859e+002f
  608. };
  609. int npoints = (int)(sizeof(pt1data)/sizeof(pt1data[0])/2);
  610. printf("npoints = %d\n", npoints); // npoints = 2
  611. Mat p1(1, npoints, CV_32FC2, pt1data);
  612. Mat p2(1, npoints, CV_32FC2, pt2data);
  613. Mat mask;
  614. // findHomography should raise an error since npoints < MIN_COUNT_OF_POINTS
  615. EXPECT_THROW(findHomography(p1, p2, RANSAC, 0.01, mask), cv::Exception);
  616. }
  617. }} // namespace