Completed findHomography test (source data has type CV_32FC2). In plans add the same...
authorAlexander Reshetnikov <no@email>
Mon, 16 Jan 2012 21:13:03 +0000 (21:13 +0000)
committerAlexander Reshetnikov <no@email>
Mon, 16 Jan 2012 21:13:03 +0000 (21:13 +0000)
modules/calib3d/test/test_homography.cpp

index c264c47..71ebbff 100644 (file)
 #include "test_precomp.hpp"\r
+#include <time.h>\r
+\r
+#define CALIB3D_HOMOGRAPHY_ERROR_MATRIX_SIZE 1\r
+#define CALIB3D_HOMOGRAPHY_ERROR_MATRIX_DIFF 2\r
+#define CALIB3D_HOMOGRAPHY_ERROR_REPROJ_DIFF 3\r
+#define CALIB3D_HOMOGRAPHY_ERROR_RANSAC_MASK 4\r
+#define CALIB3D_HOMOGRAPHY_ERROR_RANSAC_DIFF 5\r
+\r
+#define MESSAGE_MATRIX_SIZE "Homography matrix must have 3*3 sizes."\r
+#define MESSAGE_MATRIX_DIFF "Accuracy of homography transformation matrix less than required."\r
+#define MESSAGE_REPROJ_DIFF_1 "Reprojection error for current pair of points more than required."\r
+#define MESSAGE_REPROJ_DIFF_2 "Reprojection error is not optimal."\r
+#define MESSAGE_RANSAC_MASK_1 "Sizes of inliers/outliers mask are incorrect."\r
+#define MESSAGE_RANSAC_MASK_2 "Mask mustn't have any outliers."\r
+#define MESSAGE_RANSAC_MASK_3 "Mask of inliers/outliers is incorrect."\r
+#define MESSAGE_RANSAC_MASK_4 "Inlier in original mask shouldn't be outlier in found mask."\r
+#define MESSAGE_RANSAC_DIFF "Reprojection error for current pair of points more than required."\r
+\r
+#define MAX_COUNT_OF_POINTS 500\r
+#define COUNT_NORM_TYPES 3\r
+#define METHODS_COUNT 3\r
+\r
+size_t NORM_TYPE[COUNT_NORM_TYPES] = {cv::NORM_L1, cv::NORM_L2, cv::NORM_INF};\r
+size_t METHOD[METHODS_COUNT] = {0, CV_RANSAC, CV_LMEDS};\r
 \r
 using namespace cv;\r
 using namespace std;\r
 \r
-class CV_HomographyTest: public cvtest::BaseTest\r
+class CV_HomographyTest: public cvtest::ArrayTest\r
 {\r
  public:\r
             \r
            CV_HomographyTest();\r
                ~CV_HomographyTest();\r
 \r
- protected:\r
+               int read_params( CvFileStorage* fs );\r
+               void fill_array( int test_case_idx, int i, int j, Mat& arr );\r
+               int prepare_test_case( int test_case_idx );\r
+               void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );\r
+        void run (int);\r
+\r
+               bool check_matrix (const Mat& H);\r
+               bool check_transform (const Mat& src, const Mat& dst, const Mat& H);\r
+           \r
 \r
-               void run (int);\r
+               void prepare_to_validation( int test_case_idx );\r
 \r
+ protected:\r
+\r
+           int method;\r
+               int image_size;\r
+               int square_size;\r
+               double reproj_threshold;\r
+        double sigma;\r
+        bool test_cpp;\r
+                \r
+               double get_success_error_level( int test_case_idx, int i, int j );\r
+               void test_projectPoints(Mat& src_2d, Mat& dst_2d, const Mat& H, RNG* rng, double sigma);  // checking for quality of perpective transformation\r
+               \r
  private:\r
-       float max_diff;\r
-       void check_matrix_size(const cv::Mat& H);\r
-       void check_matrix_diff(const cv::Mat& original, const cv::Mat& found, const int norm_type = NORM_L2);\r
+       float max_diff, max_2diff;\r
+       bool check_matrix_size(const cv::Mat& H);\r
+       bool check_matrix_diff(const cv::Mat& original, const cv::Mat& found, const int norm_type, double &diff);\r
+       // bool check_reproj_error(const cv::Mat& src_3d, const cv::Mat& dst_3d, const int norm_type = NORM_L2);\r
+       bool check_ransac_mask_1(const Mat& src, const Mat& mask);\r
+       bool check_ransac_mask_2(const Mat& original_mask, const Mat& found_mask);\r
+       \r
        void check_transform_quality(cv::InputArray src_points, cv::InputArray dst_poits, const cv::Mat& H, const int norm_type = NORM_L2);\r
        void check_transform_quality(const cv::InputArray src_points, const vector <cv::Point2f> dst_points, const cv::Mat& H, const int norm_type = NORM_L2);\r
        void check_transform_quality(const vector <cv::Point2f> src_points, const cv::InputArray dst_points, const cv::Mat& H, const int norm_type = NORM_L2); \r
        void check_transform_quality(const vector <cv::Point2f> src_points, const vector <cv::Point2f> dst_points, const cv::Mat& H, const int norm_type = NORM_L2);\r
 };\r
 \r
-CV_HomographyTest::CV_HomographyTest(): max_diff(1e-5) {}\r
+/* void CV_HomographyTest::run_func () {} */\r
+\r
+CV_HomographyTest::CV_HomographyTest() : max_diff(1e-2), max_2diff(2e-2)\r
+{\r
+ test_array[INPUT].push_back(NULL);\r
+ test_array[INPUT].push_back(NULL);\r
+ test_array[INPUT].push_back(NULL);\r
+ test_array[INPUT].push_back(NULL);\r
+ test_array[INPUT].push_back(NULL);\r
+ test_array[INPUT].push_back(NULL);\r
+ test_array[TEMP].push_back(NULL);\r
+ test_array[TEMP].push_back(NULL);\r
+ test_array[OUTPUT].push_back(NULL);\r
+ test_array[OUTPUT].push_back(NULL);\r
+ test_array[REF_OUTPUT].push_back(NULL);\r
+ test_array[REF_OUTPUT].push_back(NULL);\r
+\r
+ element_wise_relative_error = false;\r
+\r
+ method = 0;\r
+ image_size = 1e+2;\r
+ reproj_threshold = 3.0;\r
+ sigma = 0.01;\r
+\r
+ test_cpp = false;\r
+}\r
+\r
 CV_HomographyTest::~CV_HomographyTest() {}\r
 \r
-void CV_HomographyTest::check_matrix_size(const cv::Mat& H) \r
+void CV_HomographyTest::get_test_array_types_and_sizes( int /*test_case_idx*/, vector<vector<Size> >& sizes, vector<vector<int> >& types )\r
 {\r
- CV_Assert ( H.rows == 3 && H.cols == 3);\r
+    RNG& rng = ts->get_rng();\r
+    int pt_depth = CV_32F;\r
+    double pt_count_exp = cvtest::randReal(rng)*6 + 1;\r
+    int pt_count = cvRound(exp(pt_count_exp));\r
+\r
+    /* dims = cvtest::randInt(rng) % 2 + 2;\r
+    method = 1 << (cvtest::randInt(rng) % 4);\r
+\r
+    if( method == CV_FM_7POINT )\r
+        pt_count = 7;\r
+    else\r
+    {\r
+        pt_count = MAX( pt_count, 8 + (method == CV_FM_8POINT) );\r
+        if( pt_count >= 8 && cvtest::randInt(rng) % 2 )\r
+            method |= CV_FM_8POINT;\r
+    } */\r
+\r
+       types[INPUT][0] = CV_MAKETYPE(pt_depth, 2);\r
+       \r
+       types[INPUT][1] = types[INPUT][0];\r
+\r
+       types[OUTPUT][0] = CV_MAKETYPE(pt_depth, 1);\r
+       \r
+    /* if( cvtest::randInt(rng) % 2 )\r
+        sizes[INPUT][0] = cvSize(pt_count, dims);\r
+    else\r
+    {\r
+        sizes[INPUT][0] = cvSize(dims, pt_count);\r
+        if( cvtest::randInt(rng) % 2 )\r
+        {\r
+            types[INPUT][0] = CV_MAKETYPE(pt_depth, dims);\r
+            if( cvtest::randInt(rng) % 2 )\r
+                sizes[INPUT][0] = cvSize(pt_count, 1);\r
+            else\r
+                sizes[INPUT][0] = cvSize(1, pt_count);\r
+        }\r
+    }\r
+\r
+    sizes[INPUT][1] = sizes[INPUT][0];\r
+    types[INPUT][1] = types[INPUT][0];\r
+\r
+    sizes[INPUT][2] = cvSize(pt_count, 1 );\r
+    types[INPUT][2] = CV_64FC3;\r
+\r
+    sizes[INPUT][3] = cvSize(4,3);\r
+    types[INPUT][3] = CV_64FC1;\r
+\r
+    sizes[INPUT][4] = sizes[INPUT][5] = cvSize(3,3);\r
+    types[INPUT][4] = types[INPUT][5] = CV_MAKETYPE(CV_64F, 1);\r
+\r
+    sizes[TEMP][0] = cvSize(3,3);\r
+    types[TEMP][0] = CV_64FC1;\r
+    sizes[TEMP][1] = cvSize(pt_count,1);\r
+    types[TEMP][1] = CV_8UC1;\r
+\r
+    sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(3,1);\r
+    types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;\r
+    sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] = cvSize(pt_count,1);\r
+    types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_8UC1;\r
+    \r
+    test_cpp = (cvtest::randInt(rng) & 256) == 0;\r
+       */\r
+}\r
+\r
+int CV_HomographyTest::read_params(CvFileStorage *fs)\r
+{\r
+ int code = cvtest::ArrayTest::read_params(fs);\r
+ return code;\r
+}\r
+\r
+double CV_HomographyTest::get_success_error_level(int test_case_idx, int i, int j) \r
+{\r
+ return max_diff;\r
 }\r
 \r
-void CV_HomographyTest::check_matrix_diff(const cv::Mat& original, const cv::Mat& found, const int norm_type)\r
+void CV_HomographyTest::fill_array( int test_case_idx, int i, int j, Mat& arr )\r
 {\r
- double diff = cv::norm(original, found, norm_type);\r
- CV_Assert ( diff <= max_diff );\r
+ double t[9]={0};\r
+ RNG& rng = ts->get_rng();\r
+\r
+ if ( i != INPUT )\r
+ {\r
+  cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );\r
+  return;\r
+ }\r
+\r
+ switch( j )\r
+    {\r
+    case 0:\r
+    case 1:\r
+        return; // fill them later in prepare_test_case\r
+    case 2:\r
+        {\r
+         double* p = arr.ptr<double>();\r
+         for( i = 0; i < arr.cols*3; i += 3 )\r
+         {\r
+          /* p[i] = cvtest::randReal(rng)*square_size;\r
+          p[i+1] = cvtest::randReal(rng)*square_size;\r
+          p[i+2] = cvtest::randReal(rng)*square_size + square_size; */\r
+         }\r
+        }\r
+        break;\r
+    case 3:\r
+        {\r
+         double r[3];\r
+         Mat rot_vec( 3, 1, CV_64F, r );\r
+         Mat rot_mat( 3, 3, CV_64F, t, 4*sizeof(t[0]) );\r
+         r[0] = cvtest::randReal(rng)*CV_PI*2;\r
+         r[1] = cvtest::randReal(rng)*CV_PI*2;\r
+         r[2] = cvtest::randReal(rng)*CV_PI*2;\r
+\r
+         cvtest::Rodrigues( rot_vec, rot_mat );\r
+         /* t[3] = cvtest::randReal(rng)*square_size;\r
+         t[7] = cvtest::randReal(rng)*square_size;\r
+         t[11] = cvtest::randReal(rng)*square_size; */\r
+         Mat( 3, 4, CV_64F, t ).convertTo(arr, arr.type());\r
+        }\r
+        break;\r
+    case 4:\r
+    case 5:\r
+               {\r
+         /* t[0] = t[4] = cvtest::randReal(rng)*(max_f - min_f) + min_f;\r
+            t[2] = (img_size*0.5 + cvtest::randReal(rng)*4. - 2.)*t[0];\r
+            t[5] = (img_size*0.5 + cvtest::randReal(rng)*4. - 2.)*t[4];\r
+            t[8] = 1.0f;\r
+            Mat( 3, 3, CV_64F, t ).convertTo( arr, arr.type() ); */\r
+         break;\r
+               }\r
+    }\r
+}\r
+\r
+int CV_HomographyTest::prepare_test_case(int test_case_idx)\r
+{\r
+ int code = cvtest::ArrayTest::prepare_test_case(test_case_idx);\r
+\r
+ if (code > 0)  \r
+ {\r
+  Mat& src = test_mat[INPUT][0];\r
+  RNG& rng = ts->get_rng();\r
+\r
+  float Hdata[] = { sqrt(2.0f)/2, -sqrt(2.0f)/2, 0.0f, \r
+                       sqrt(2.0f)/2,  sqrt(2.0f)/2, 0.0f, \r
+                                       0.0f,              0.0f,                 1.0f };\r
+  \r
+  Mat H( 3, 3, CV_32F, Hdata );\r
+\r
+  cv::Mat dst(1, src.cols, CV_32FC2);\r
+  \r
+  int k;\r
+\r
+  for( k = 0; k < 2; k++ )\r
+  {\r
+   const Mat& H = test_mat[OUTPUT][0];\r
+   Mat& dst = test_mat[INPUT][k == 0 ? 1 : 2];\r
+\r
+   for (int i = 0; i < src.cols; ++i)\r
+   {\r
+       float *s = src.ptr<float>()+2*i;\r
+    float *d = dst.ptr<float>()+2*i;\r
+\r
+    d[0] = Hdata[0]*s[0] + Hdata[1]*s[1] + Hdata[2];\r
+       d[1] = Hdata[3]*s[0] + Hdata[4]*s[1] + Hdata[5];\r
+   }\r
+\r
+   test_projectPoints( src, dst, H, &rng, sigma );\r
+  }\r
+ }\r
+\r
+ return code;\r
+}\r
+\r
+static void test_convertHomogeneous( const Mat& _src, Mat& _dst )\r
+{\r
+ Mat src = _src, dst = _dst;\r
\r
+ int i, count, sdims, ddims;\r
+ int sstep1, sstep2, dstep1, dstep2;\r
+\r
+ if( src.depth() != CV_64F ) _src.convertTo(src, CV_64F);\r
+    \r
+ if( dst.depth() != CV_64F ) dst.create(dst.size(), CV_MAKETYPE(CV_64F, _dst.channels()));\r
+\r
+ if( src.rows > src.cols )\r
+ {\r
+  count = src.rows;\r
+  sdims = src.channels()*src.cols;\r
+  sstep1 = (int)(src.step/sizeof(double));\r
+  sstep2 = 1;\r
+ }\r
\r
+ else\r
+ {\r
+  count = src.cols;\r
+  sdims = src.channels()*src.rows;\r
+  if( src.rows == 1 )\r
+  {\r
+   sstep1 = sdims;\r
+   sstep2 = 1;\r
+  }\r
+  \r
+  else\r
+  {\r
+   sstep1 = 1;\r
+   sstep2 = (int)(src.step/sizeof(double));\r
+  }\r
+ }\r
+\r
+ if( dst.rows > dst.cols )\r
+ {\r
+        if (count != dst.rows) ;  // CV_Error should be here\r
+  CV_Assert( count == dst.rows );\r
+  ddims = dst.channels()*dst.cols;\r
+        dstep1 = (int)(dst.step/sizeof(double));\r
+        dstep2 = 1;\r
+    }\r
+    else\r
+    {\r
+        assert( count == dst.cols );\r
+        ddims = dst.channels()*dst.rows;\r
+        if( dst.rows == 1 )\r
+        {\r
+            dstep1 = ddims;\r
+            dstep2 = 1;\r
+        }\r
+        else\r
+        {\r
+            dstep1 = 1;\r
+            dstep2 = (int)(dst.step/sizeof(double));\r
+        }\r
+    }\r
+\r
+    double* s = src.ptr<double>();\r
+    double* d = dst.ptr<double>();\r
+\r
+    if( sdims <= ddims )\r
+    {\r
+        int wstep = dstep2*(ddims - 1);\r
+\r
+        for( i = 0; i < count; i++, s += sstep1, d += dstep1 )\r
+        {\r
+            double x = s[0];\r
+            double y = s[sstep2];\r
+\r
+            d[wstep] = 1;\r
+            d[0] = x;\r
+            d[dstep2] = y;\r
+\r
+            if( sdims >= 3 )\r
+            {\r
+                d[dstep2*2] = s[sstep2*2];\r
+                if( sdims == 4 )\r
+                    d[dstep2*3] = s[sstep2*3];\r
+            }\r
+        }\r
+    }\r
+    else\r
+    {\r
+        int wstep = sstep2*(sdims - 1);\r
+\r
+        for( i = 0; i < count; i++, s += sstep1, d += dstep1 )\r
+        {\r
+            double w = s[wstep];\r
+            double x = s[0];\r
+            double y = s[sstep2];\r
+\r
+            w = w ? 1./w : 1;\r
+\r
+            d[0] = x*w;\r
+            d[dstep2] = y*w;\r
+\r
+            if( ddims == 3 )\r
+                d[dstep2*2] = s[sstep2*2]*w;\r
+        }\r
+    }\r
+\r
+    if( dst.data != _dst.data )\r
+        dst.convertTo(_dst, _dst.depth());\r
+}\r
+\r
+void CV_HomographyTest::test_projectPoints( Mat& src_2d, Mat& dst, const Mat& H, RNG* rng, double sigma )\r
+{\r
+ if (!src_2d.isContinuous()) \r
+ {\r
+  CV_Error(-1, "");\r
+  return;\r
+ }\r
+\r
+ cv::Mat src_3d(1, src_2d.cols, CV_32FC3);\r
\r
+ for (int i = 0; i < src_2d.cols; ++i)\r
+ { \r
+  float *c_3d = src_3d.ptr<float>()+3*i;\r
+  float *c_2d = src_2d.ptr<float>()+2*i;\r
+\r
+  c_3d[0] = c_2d[0]; c_3d[1] = c_2d[1]; c_3d[2] = 1.0f;\r
+ }\r
+\r
+ cv::Mat dst_3d; gemm(H, src_3d, 1, Mat(), 0, dst_3d);\r
+    \r
+ int i, count = src_2d.cols;\r
+\r
+ Mat noise;\r
+\r
+ if ( rng )\r
+ {\r
+  if( sigma == 0 ) rng = 0;\r
+  else\r
+  {\r
+   noise.create( 1, count, CV_32FC2 );\r
+   rng->fill(noise, RNG::NORMAL, Scalar::all(0), Scalar::all(sigma) );\r
+  }\r
+ }\r
+\r
+ cv::Mat dst_2d(1, count, CV_32FC2); \r
\r
+ for (size_t i = 0; i < count; ++i)\r
+ {\r
+  float *c_3d = dst_3d.ptr<float>()+3*i;\r
+  float *c_2d = dst_2d.ptr<float>()+2*i;\r
+\r
+  c_2d[0] = c_3d[0]/c_3d[2];\r
+  c_2d[1] = c_3d[1]/c_3d[2];\r
+ }\r
+\r
+ Mat temp( 1, count, CV_32FC2 );\r
+\r
+ for( i = 0; i < count; i++ )\r
+ {\r
+  const double* M = src_2d.ptr<double>() + 2*i;\r
+  double* m = temp.ptr<double>() + 2*i;\r
+  double X = M[0], Y = M[1], Z = M[2];\r
+  double u = H.at<float>(0, 0)*X + H.at<float>(0, 1)*Y + H.at<float>(0, 2);\r
+  double v = H.at<float>(1, 0)*X + H.at<float>(1, 1)*Y + H.at<float>(1, 2);\r
+  double s = H.at<float>(2, 0)*X + H.at<float>(2, 1)*Y + H.at<float>(2, 2);\r
+\r
+  if( !noise.empty() )\r
+  {\r
+   u += noise.at<Point2f>(i).x*s;\r
+   v += noise.at<Point2f>(i).y*s;\r
+  }\r
+\r
+  m[0] = u;\r
+  m[1] = v;\r
+  m[2] = s;\r
+ }\r
+\r
+ test_convertHomogeneous( dst_2d, dst );\r
+}\r
+\r
+void CV_HomographyTest::prepare_to_validation(int test_case_idx)\r
+{\r
+    const Mat& H = test_mat[INPUT][3];\r
+   \r
+       const Mat& A1 = test_mat[INPUT][4];\r
+    const Mat& A2 = test_mat[INPUT][5];\r
+    \r
+       double h0[9], h[9];\r
+    Mat H0(3, 3, CV_32FC1, h0);\r
+\r
+    Mat invA1, invA2, T;\r
+\r
+    cv::invert(A1, invA1, CV_SVD);\r
+    cv::invert(A2, invA2, CV_SVD);\r
+\r
+    double tx = H.at<double>(0, 2);\r
+    double ty = H.at<double>(1, 2);\r
+    double tz = H.at<double>(2, 2);\r
+\r
+    // double _t_x[] = { 0, -tz, ty, tz, 0, -tx, -ty, tx, 0 };\r
+\r
+    // F = (A2^-T)*[t]_x*R*(A1^-1)\r
+    /* cv::gemm( invA2, Mat( 3, 3, CV_64F, _t_x ), 1, Mat(), 0, T, CV_GEMM_A_T );\r
+    cv::gemm( R, invA1, 1, Mat(), 0, invA2 );\r
+    cv::gemm( T, invA2, 1, Mat(), 0, F0 ); */\r
+    H0 *= 1./h0[8];\r
+\r
+    uchar* status = test_mat[TEMP][1].data;\r
+    double err_level = get_success_error_level( test_case_idx, OUTPUT, 1 );\r
+    uchar* mtfm1 = test_mat[REF_OUTPUT][1].data;\r
+    uchar* mtfm2 = test_mat[OUTPUT][1].data;\r
+    double* f_prop1 = (double*)test_mat[REF_OUTPUT][0].data;\r
+    double* f_prop2 = (double*)test_mat[OUTPUT][0].data;\r
+\r
+    int i, pt_count = test_mat[INPUT][2].cols;\r
+    Mat p1( 1, pt_count, CV_64FC2 );\r
+    Mat p2( 1, pt_count, CV_64FC2 );\r
+\r
+    test_convertHomogeneous( test_mat[INPUT][0], p1 );\r
+    test_convertHomogeneous( test_mat[INPUT][1], p2 );\r
+\r
+    cvtest::convert(test_mat[TEMP][0], H0, H.type());\r
+\r
+    if( method <= CV_FM_8POINT )\r
+        memset( status, 1, pt_count );\r
+\r
+    for( i = 0; i < pt_count; i++ )\r
+    {\r
+        double x1 = p1.at<Point2f>(i).x;\r
+        double y1 = p1.at<Point2f>(i).y;\r
+        double x2 = p2.at<Point2f>(i).x;\r
+        double y2 = p2.at<Point2f>(i).y;\r
+        double n1 = 1./sqrt(x1*x1 + y1*y1 + 1);\r
+        double n2 = 1./sqrt(x2*x2 + y2*y2 + 1);\r
+        double t0 = fabs(h0[0]*x2*x1 + h0[1]*x2*y1 + h0[2]*x2 +\r
+                   h0[3]*y2*x1 + h0[4]*y2*y1 + h0[5]*y2 +\r
+                   h0[6]*x1 + h0[7]*y1 + h0[8])*n1*n2;\r
+        double t = fabs(h[0]*x2*x1 + h[1]*x2*y1 + h[2]*x2 +\r
+                   h[3]*y2*x1 + h[4]*y2*y1 + h[5]*y2 +\r
+                   h[6]*x1 + h[7]*y1 + h[8])*n1*n2;\r
+        mtfm1[i] = 1;\r
+        mtfm2[i] = !status[i] || t0 > err_level || t < err_level;\r
+    }\r
+\r
+    f_prop1[0] = 1;\r
+    f_prop1[1] = 1;\r
+    f_prop1[2] = 0;\r
+\r
+   // f_prop2[0] = f_result != 0;\r
+    f_prop2[1] = h[8];\r
+    f_prop2[2] = cv::determinant( H );\r
+}\r
+\r
+bool CV_HomographyTest::check_matrix_size(const cv::Mat& H) \r
+{\r
+ return (H.rows == 3) && (H.cols == 3);\r
+}\r
+\r
+bool CV_HomographyTest::check_matrix_diff(const cv::Mat& original, const cv::Mat& found, const int norm_type, double &diff)\r
+{\r
+ diff = cv::norm(original, found, norm_type);\r
+ return diff <= max_diff;\r
+}\r
+\r
+bool CV_HomographyTest::check_ransac_mask_1(const Mat& src, const Mat& mask)\r
+{\r
+ if (!(mask.cols == 1) && (mask.rows == src.cols))\r
+ {\r
+  CV_Error(CALIB3D_HOMOGRAPHY_ERROR_RANSAC_MASK, MESSAGE_RANSAC_MASK_1);\r
+  return false;\r
+ }\r
+ if (countNonZero(mask) < mask.rows)\r
+ {\r
+  CV_Error(CALIB3D_HOMOGRAPHY_ERROR_RANSAC_MASK, MESSAGE_RANSAC_MASK_2);\r
+  return false;\r
+ }\r
+ return true;\r
+}\r
+\r
+bool CV_HomographyTest::check_ransac_mask_2(const Mat& original_mask, const Mat& found_mask)\r
+{\r
+ if (!(found_mask.cols == 1) && (found_mask.rows == original_mask.rows))\r
+ {\r
+  CV_Error(CALIB3D_HOMOGRAPHY_ERROR_RANSAC_MASK, MESSAGE_RANSAC_MASK_1);\r
+  return false;\r
+ } \r
 }\r
 \r
 void CV_HomographyTest::check_transform_quality(cv::InputArray src_points, cv::InputArray dst_points, const cv::Mat& H, const int norm_type)\r
@@ -55,34 +577,314 @@ void CV_HomographyTest::check_transform_quality(cv::InputArray src_points, cv::I
 \r
 void CV_HomographyTest::run(int)\r
 {\r
- // test data without outliers\r
- cv::Vec3f n_src(1.0f, 1.0f, 1.0f), n_dst(1.0f, -1.0f, 0.0f); \r
- const float d_src = 1.0f, d_dst = 0.0f;\r
- const int n_points = 100;\r
+ for (size_t N = 4; N <= MAX_COUNT_OF_POINTS; ++N)\r
+ {\r
+  RNG& rng = ts->get_rng();\r
 \r
float P[2*n_points], Q[2*n_points];\r
 float *src_data = new float [2*N];\r
 \r
for (size_t i = 0; i < 2*n_points; i += 2)\r
- {\r
-  float u1 = cv::randu<float>(), v1 = cv::randu<float>();\r
-  float w1 = 1.0f/(d_src - n_src[0]*u1 - n_src[1]*v1);\r
-  P[i] = u1*w1;  P[i+1] = v1*w1; \r
 for (int i = 0; i < N; ++i)\r
 {\r
+   src_data[2*i] = (float)cvtest::randReal(rng)*image_size;\r
+   src_data[2*i+1] = (float)cvtest::randReal(rng)*image_size;\r
+  }\r
   \r
-  float u2 = cv::randu<float>(), v2 = cv::randu<float>();\r
-  float w2 =  1.0f/(d_src - n_src[0]*u1 - n_src[1]*v1);\r
-  Q[i] = u2*w2; Q[i+1] = v2*w2;\r
- }\r
+  cv::Mat src_mat_2f(1, N, CV_32FC2, src_data), \r
+             src_mat_2d(2, N, CV_32F, src_data), \r
+                 src_mat_3d(3, N, CV_32F);\r
+  cv::Mat dst_mat_2f, dst_mat_2d, dst_mat_3d;\r
 \r
- cv::Mat src(n_points, 1, CV_32FC2, P);\r
- cv::Mat dst(n_points, 1, CV_32FC2, Q);\r
\r
- cv::Mat H = cv::findHomography(src, dst);\r
\r
- check_matrix_size(H);\r
+  for (size_t i = 0; i < N; ++i)\r
+  {\r
+   float *tmp = src_mat_2d.ptr<float>()+2*i;\r
+   src_mat_3d.at<float>(0, i) = tmp[0];\r
+   src_mat_3d.at<float>(1, i) = tmp[1];\r
+   src_mat_3d.at<float>(2, i) = 1.0f;\r
+  }\r
+\r
+  double fi = cvtest::randReal(rng)*2*CV_PI;\r
+\r
+  double t_x = cvtest::randReal(rng)*sqrt(image_size*1.0), \r
+            t_y = cvtest::randReal(rng)*sqrt(image_size*1.0);\r
+\r
+  double Hdata[9] = { cos(fi), -sin(fi), t_x, \r
+                                         sin(fi),  cos(fi), t_y,\r
+                                            0.0f,     0.0f, 1.0f };\r
+\r
+  cv::Mat H_64(3, 3, CV_64F, Hdata), H_32;\r
+\r
+  H_64.convertTo(H_32, CV_32F);\r
+\r
+  dst_mat_3d = H_32*src_mat_3d;\r
+\r
+  dst_mat_2d.create(2, N, CV_32F); dst_mat_2f.create(1, N, CV_32FC2);\r
+\r
+  for (size_t i = 0; i < N; ++i)\r
+  {\r
+   float *tmp_2f = dst_mat_2f.ptr<float>()+2*i;\r
+   tmp_2f[0] = dst_mat_2d.at<float>(0, i) = dst_mat_3d.at<float>(0, i) /= dst_mat_3d.at<float>(2, i);\r
+   tmp_2f[1] = dst_mat_2d.at<float>(1, i) = dst_mat_3d.at<float>(1, i) /= dst_mat_3d.at<float>(2, i);\r
+  }\r
+\r
+  for (size_t i = 0; i < METHODS_COUNT; ++i)\r
+  {\r
+   method = METHOD[i];\r
+   switch (method)\r
+   {\r
+    case 0:\r
+       case CV_LMEDS:\r
+               {\r
+                Mat H_res_64 = cv::findHomography(src_mat_2f, dst_mat_2f, method);\r
+                if (!check_matrix_size(H_res_64))\r
+                {\r
+             cout << endl; cout << "Checking for homography matrix sizes..." << endl; cout << endl;\r
+                                               cout << "Count of points: " << N << endl; cout << endl;\r
+                                               cout << "Homography matrix:" << endl; cout << endl;\r
+                                               cout << H_res_64 << endl; cout << endl;\r
+                                               cout << "Number of rows: " << H_res_64.rows << "   Number of cols: " << H_res_64.cols << endl; cout << endl;\r
+                                               CV_Error(CALIB3D_HOMOGRAPHY_ERROR_MATRIX_SIZE, MESSAGE_MATRIX_SIZE);\r
+                                               return;\r
+                }\r
+\r
+                double diff;\r
+\r
+                for (size_t j = 0; j < COUNT_NORM_TYPES; ++j)\r
+                if (!check_matrix_diff(H_64, H_res_64, NORM_TYPE[j], diff)) \r
+                {\r
+                 cout << endl; cout << "Checking for accuracy of homography matrix computing..." << endl; cout << endl;\r
+                                               cout << "Count of points: " << N << endl; cout << endl;\r
+                                               cout << "Original matrix:" << endl; cout << endl;\r
+                                               cout << H_64 << endl; cout << endl;\r
+                                               cout << "Found matrix:" << endl; cout << endl;\r
+                                               cout << H_res_64 << endl; cout << endl;\r
+                                               cout << "Norm type using in criteria: "; if (NORM_TYPE[j] == 1) cout << "INF"; else if (NORM_TYPE[j] == 2) cout << "L1"; else cout << "L2"; cout << endl;\r
+                                               cout << "Difference between matrix: " << diff << endl;\r
+                                               cout << "Maximum allowed difference: " << max_diff << endl; cout << endl;\r
+                                               CV_Error(CALIB3D_HOMOGRAPHY_ERROR_MATRIX_DIFF, MESSAGE_MATRIX_DIFF);\r
+                                               return;\r
+                }\r
+                continue;\r
+               }\r
+       case CV_RANSAC:\r
+               {\r
+                cv::Mat mask; double diff; \r
+                Mat H_res_64 = cv::findHomography(src_mat_2f, dst_mat_2f, CV_RANSAC, reproj_threshold, mask);\r
+                if (!check_matrix_size(H_res_64)) \r
+                {\r
+                 cout << endl; cout << "Checking for homography matrix sizes..." << endl; cout << endl;\r
+                                               cout << "Count of points: " << N << endl; cout << endl;\r
+                                               cout << "Homography matrix:" << endl; cout << endl;\r
+                                               cout << H_res_64 << endl; cout << endl;\r
+                                               cout << "Number of rows: " << H_res_64.rows << "   Number of cols: " << H_res_64.cols << endl; cout << endl;\r
+                                               CV_Error(CALIB3D_HOMOGRAPHY_ERROR_MATRIX_SIZE, MESSAGE_MATRIX_SIZE);\r
+                                               return;\r
+                }\r
+                for (size_t j = 0; j < COUNT_NORM_TYPES; ++j)\r
+                if (!check_matrix_diff(H_64, H_res_64, NORM_TYPE[j], diff)) \r
+                {\r
+                 cout << endl; cout << "Checking for accuracy of homography matrix computing..." << endl; cout << endl;\r
+                                               cout << "Count of points: " << N << endl; cout << endl;\r
+                                               cout << "Original matrix:" << endl; cout << endl;\r
+                                               cout << H_64 << endl; cout << endl;\r
+                                               cout << "Found matrix:" << endl; cout << endl;\r
+                                               cout << H_res_64 << endl; cout << endl;\r
+                                               cout << "Norm type using in criteria: "; if (NORM_TYPE[j] == 1) cout << "INF"; else if (NORM_TYPE[j] == 2) cout << "L1"; else cout << "L2"; cout << endl;\r
+                                               cout << "Difference between matrix: " << diff << endl;\r
+                                               cout << "Maximum allowed difference: " << max_diff << endl; cout << endl;\r
+                                               CV_Error(CALIB3D_HOMOGRAPHY_ERROR_MATRIX_DIFF, MESSAGE_MATRIX_DIFF);\r
+                                               return;\r
+                }\r
+                if (!check_ransac_mask_1(src_mat_2f, mask)) return;\r
+                continue;\r
+               }\r
+       \r
+    default: continue;\r
+   } \r
+  }\r
+\r
+  Mat noise_2f(1, N, CV_32FC2);\r
+  rng.fill(noise_2f, RNG::NORMAL, Scalar::all(0), Scalar::all(sigma));\r
 \r
// check_transform_quality(src, dst, H, NORM_L1);\r
 cv::Mat mask(N, 1, CV_8UC1);\r
 \r
- // check_matrix_diff(_H, H, NORM_L1);\r
+  for (int i = 0; i < N; ++i)\r
+  {\r
+   float *a = noise_2f.ptr<float>()+2*i, *_2f = dst_mat_2f.ptr<float>()+2*i;\r
+   _2f[0] /* = dst_mat_2d.at<float>(0, i) = dst_mat_3d.at<float>(0, i) */ += a[0];\r
+   _2f[1] /* = dst_mat_2d.at<float>(1, i) = dst_mat_3d.at<float>(1, i) */ += a[1];\r
+   mask.at<uchar>(i, 0) = sqrt(a[0]*a[0]+a[1]*a[1]) > reproj_threshold ? 0 : 1;\r
+  }\r
+\r
+  for (size_t i = 0; i < METHODS_COUNT; ++i)\r
+  {\r
+   method = METHOD[i];\r
+   switch (method)\r
+   {\r
+    case 0:\r
+    case CV_LMEDS:\r
+                               {\r
+                                Mat H_res_64 = cv::findHomography(src_mat_2f, dst_mat_2f, mask);\r
+                                \r
+                                if (!check_matrix_size(H_res_64))\r
+                                {\r
+                                 cout << endl; cout << "Checking for homography matrix sizes..." << endl; cout << endl;\r
+                                                               cout << "Count of points: " << N << endl; cout << endl;\r
+                                                               cout << "Homography matrix:" << endl; cout << endl;\r
+                                                               cout << H_res_64 << endl; cout << endl;\r
+                                                               cout << "Number of rows: " << H_res_64.rows << "   Number of cols: " << H_res_64.cols << endl; cout << endl;\r
+                                                               CV_Error(CALIB3D_HOMOGRAPHY_ERROR_MATRIX_SIZE, MESSAGE_MATRIX_SIZE);\r
+                                                               return;\r
+                                }\r
+\r
+                                Mat H_res_32; H_res_64.convertTo(H_res_32, CV_32F);\r
+\r
+                                cv::Mat dst_res_3d(3, N, CV_32F), noise_2d(2, N, CV_32F);\r
+\r
+                                for (size_t k = 0; k < N; ++k)\r
+                                {\r
+\r
+                                 Mat tmp_mat_3d = H_res_32*src_mat_3d.col(k);\r
+\r
+                                 dst_res_3d.at<float>(0, k) = tmp_mat_3d.at<float>(0, 0) /= tmp_mat_3d.at<float>(2, 0);\r
+                                 dst_res_3d.at<float>(1, k) = tmp_mat_3d.at<float>(1, 0) /= tmp_mat_3d.at<float>(2, 0);\r
+                                 dst_res_3d.at<float>(2, k) = tmp_mat_3d.at<float>(2, 0) = 1.0f;\r
+\r
+                                 float *a = noise_2f.ptr<float>()+2*k;\r
+                                 noise_2d.at<float>(0, k) = a[0]; noise_2d.at<float>(1, k) = a[1];\r
+         \r
+                                 for (size_t j = 0; j < METHODS_COUNT; ++j) \r
+                                 if (cv::norm(tmp_mat_3d, dst_mat_3d.col(k), NORM_TYPE[j]) - cv::norm(noise_2d.col(k), NORM_TYPE[j]) > max_2diff) \r
+                                 {\r
+                                  cout << endl; cout << "Checking for accuracy of reprojection error computing..." << endl; cout << endl;\r
+                                                            cout << "Method: "; if (method == 0) cout << 0 << endl; else cout << "CV_LMEDS" << endl;\r
+                                                            cout << "Sigma of normal noise: " << sigma << endl;\r
+                                                            cout << "Count of points: " << N << endl;\r
+                                                            cout << "Number of point: " << k << endl;\r
+                                                            cout << "Norm type using in criteria: "; if (NORM_TYPE[j] == 1) cout << "INF"; else if (NORM_TYPE[j] == 2) cout << "L1"; else cout << "L2"; cout << endl;\r
+                                                            cout << "Difference with noise of point: " << cv::norm(tmp_mat_3d, dst_mat_3d.col(k), NORM_TYPE[j]) - cv::norm(noise_2d.col(k), NORM_TYPE[j]) << endl; \r
+                                                            cout << "Maxumum allowed difference: " << max_2diff << endl; cout << endl;\r
+                                                            CV_Error(CALIB3D_HOMOGRAPHY_ERROR_REPROJ_DIFF, MESSAGE_REPROJ_DIFF_1);\r
+                                                            return;\r
+                                 } \r
+               \r
+                                }\r
+                \r
+                                Mat tmp_mat_3d = H_res_32*src_mat_3d;\r
+                \r
+                                for (size_t j = 0; j < METHODS_COUNT; ++j)\r
+                                if (cv::norm(dst_res_3d, dst_mat_3d, NORM_TYPE[j]) - cv::norm(noise_2d, NORM_TYPE[j]) > max_diff) \r
+                                {\r
+                                 cout << endl; cout << "Checking for accuracy of reprojection error computing..." << endl; cout << endl;\r
+                                                           cout << "Method: "; if (method == 0) cout << 0 << endl; else cout << "CV_LMEDS" << endl;\r
+                                                           cout << "Sigma of normal noise: " << sigma << endl;\r
+                                                           cout << "Count of points: " << N << endl;\r
+                                                           cout << "Norm type using in criteria: "; if (NORM_TYPE[j] == 1) cout << "INF"; else if (NORM_TYPE[j] == 2) cout << "L1"; else cout << "L2"; cout << endl; \r
+                                                               cout << "Difference with noise of points: " << cv::norm(dst_res_3d, dst_mat_3d, NORM_TYPE[j]) - cv::norm(noise_2d, NORM_TYPE[j]) << endl; \r
+                                                               cout << "Maxumum allowed difference: " << max_diff << endl; cout << endl; \r
+                                                               CV_Error(CALIB3D_HOMOGRAPHY_ERROR_REPROJ_DIFF, MESSAGE_REPROJ_DIFF_2);\r
+                                                               return;\r
+                                } \r
+                \r
+                                continue;\r
+                               }\r
+       case CV_RANSAC:\r
+                                       {\r
+                                        cv::Mat mask_res; \r
+                                        Mat H_res_64 = cv::findHomography(src_mat_2f, dst_mat_2f, CV_RANSAC, reproj_threshold, mask_res);\r
+\r
+                                        if (!check_matrix_size(H_res_64)) \r
+                                        {\r
+                                         cout << endl; cout << "Checking for homography matrix sizes..." << endl; cout << endl;\r
+                                                                       cout << "Count of points: " << N << endl; cout << endl;\r
+                                                                       cout << "Homography matrix:" << endl; cout << endl;\r
+                                                                       cout << H_res_64 << endl; cout << endl;\r
+                                                                       cout << "Number of rows: " << H_res_64.rows << "   Number of cols: " << H_res_64.cols << endl; cout << endl;\r
+                                                                       CV_Error(CALIB3D_HOMOGRAPHY_ERROR_MATRIX_SIZE, MESSAGE_MATRIX_SIZE);\r
+                                                                       return;\r
+                                        }\r
+               \r
+                                        if (!check_ransac_mask_2(mask, mask_res)) return;\r
+\r
+                                        cv::Mat H_res_32; H_res_64.convertTo(H_res_32, CV_32F);\r
+\r
+                                        cv::Mat dst_res_3d = H_res_32*src_mat_3d;\r
+\r
+                                        for (size_t k = 0; k < N; ++k)\r
+                                        {\r
+                                         dst_res_3d.at<float>(0, k) /= dst_res_3d.at<float>(2, k);\r
+                                         dst_res_3d.at<float>(1, k) /= dst_res_3d.at<float>(2, k);\r
+                                     dst_res_3d.at<float>(2, k) = 1.0f;\r
+                                                \r
+                                         float *p = dst_mat_2f.ptr<float>()+2*k;\r
+\r
+                                         dst_mat_3d.at<float>(0, k) = p[0];\r
+                                         dst_mat_3d.at<float>(1, k) = p[1];\r
+\r
+                                         double diff = cv::norm(dst_res_3d.col(k), dst_mat_3d.col(k), NORM_L2); \r
+\r
+                                         if (mask_res.at<bool>(k, 0) != (diff <= reproj_threshold))\r
+                                         {\r
+                                          cout << endl; cout << "Checking for inliers/outliers mask..." << endl; cout << endl;\r
+                                                                        cout << "Count of points: " << N << "   " << endl; \r
+                                                                        cout << "Number of point: " << k << "   " << endl;\r
+                                                                        cout << "Reprojection error for this point: " << diff << "   " << endl;\r
+                                                                        cout << "Reprojection error threshold: " << reproj_threshold << "   " << endl;\r
+                                                                        cout << "Value of found mask: "<< mask_res.at<bool>(k, 0) << endl; cout << endl;\r
+                                                                        CV_Error(CALIB3D_HOMOGRAPHY_ERROR_RANSAC_MASK, MESSAGE_RANSAC_MASK_3);\r
+                                                                        return; \r
+                                         } \r
+\r
+                                         \r
+\r
+                                         if (mask.at<bool>(k, 0) && !mask_res.at<bool>(k, 0))\r
+                                         {\r
+                                          cout << endl; cout << "Checking for inliers/outliers mask..." << endl; cout << endl;\r
+                                                                        cout << "Count of points: " << N << "   " << endl; \r
+                                                                        cout << "Number of point: " << k << "   " << endl;\r
+                                                                        cout << "Reprojection error for this point: " << diff << "   " << endl;\r
+                                                                        cout << "Reprojection error threshold: " << reproj_threshold << "   " << endl;\r
+                                                                        cout << "Value of original mask: "<< mask.at<bool>(k, 0) << "   Value of found mask: " << mask_res.at<bool>(k, 0) << endl; cout << endl;\r
+                                                                        CV_Error(CALIB3D_HOMOGRAPHY_ERROR_RANSAC_MASK, MESSAGE_RANSAC_MASK_4);\r
+                                                                        return;\r
+                                         }\r
+\r
+                                         if (mask_res.at<bool>(k, 0))\r
+                                         {\r
+                                          float *a = noise_2f.ptr<float>()+2*k;\r
+                                          dst_mat_3d.at<float>(0, k) -= a[0];\r
+                                          dst_mat_3d.at<float>(1, k) -= a[1];\r
+\r
+                                          cv::Mat noise_2d(2, 1, CV_32F);\r
+                                          noise_2d.at<float>(0, 0) = a[0]; noise_2d.at<float>(1, 0) = a[1];\r
+\r
+                                          for (size_t j = 0; j < METHODS_COUNT; ++j)\r
+                                          {\r
+                                               diff = cv::norm(dst_res_3d.col(k), dst_mat_3d.col(k), NORM_TYPE[j]);\r
+                                           \r
+                                               if (diff - cv::norm(noise_2d, NORM_TYPE[j]) > max_2diff)\r
+                                           {\r
+                                          \r
+                                            cout << endl; cout << "Checking for reprojection error of inlier..." << endl; cout << endl;\r
+                                                                          cout << "Count of points: " << N << "   " << endl; \r
+                                                                          cout << "Number of point: " << k << "   " << endl;\r
+                                                                          cout << "Reprojection error for this point: " << diff << "   " << endl;\r
+                                                                          CV_Error(CALIB3D_HOMOGRAPHY_ERROR_RANSAC_DIFF, MESSAGE_RANSAC_DIFF);\r
+                                                                          return; \r
+                                           }\r
+                                          }\r
+                                         }\r
+                                        }\r
+\r
+                                       \r
+                                       // Checking of reprojection error for any points pair.\r
+\r
+                                        continue;\r
+                                       }\r
+               \r
+       default: continue;\r
+   } \r
+  }\r
+ }\r
 }\r
 \r
-TEST(Core_Homography, complex_test) { CV_HomographyTest test; test.safe_run(); }
\ No newline at end of file
+TEST(Calib3d_Homography, complex_test) { CV_HomographyTest test; test.safe_run(); }
\ No newline at end of file