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