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 using namespace cv;
     47 using namespace std;
     48 
     49 #define sign(a) a > 0 ? 1 : a == 0 ? 0 : -1
     50 
     51 #define CORE_EIGEN_ERROR_COUNT 1
     52 #define CORE_EIGEN_ERROR_SIZE  2
     53 #define CORE_EIGEN_ERROR_DIFF  3
     54 #define CORE_EIGEN_ERROR_ORTHO 4
     55 #define CORE_EIGEN_ERROR_ORDER 5
     56 
     57 #define MESSAGE_ERROR_COUNT "Matrix of eigen values must have the same rows as source matrix and 1 column."
     58 #define MESSAGE_ERROR_SIZE "Source matrix and matrix of eigen vectors must have the same sizes."
     59 #define MESSAGE_ERROR_DIFF_1 "Accurasy of eigen values computing less than required."
     60 #define MESSAGE_ERROR_DIFF_2 "Accuracy of eigen vectors computing less than required."
     61 #define MESSAGE_ERROR_ORTHO "Matrix of eigen vectors is not orthogonal."
     62 #define MESSAGE_ERROR_ORDER "Eigen values are not sorted in ascending order."
     63 
     64 const int COUNT_NORM_TYPES = 3;
     65 const int NORM_TYPE[COUNT_NORM_TYPES] = {cv::NORM_L1, cv::NORM_L2, cv::NORM_INF};
     66 
     67 enum TASK_TYPE_EIGEN {VALUES, VECTORS};
     68 
     69 class Core_EigenTest: public cvtest::BaseTest
     70 {
     71 public:
     72 
     73     Core_EigenTest();
     74     ~Core_EigenTest();
     75 
     76 protected:
     77 
     78     bool test_values(const cv::Mat& src);												// complex test for eigen without vectors
     79     bool check_full(int type);													// compex test for symmetric matrix
     80     virtual void run (int) = 0;													// main testing method
     81 
     82 protected:
     83 
     84     float eps_val_32, eps_vec_32;
     85     float eps_val_64, eps_vec_64;
     86     int ntests;
     87 
     88     bool check_pair_count(const cv::Mat& src, const cv::Mat& evalues, int low_index = -1, int high_index = -1);
     89     bool check_pair_count(const cv::Mat& src, const cv::Mat& evalues, const cv::Mat& evectors, int low_index = -1, int high_index = -1);
     90     bool check_pairs_order(const cv::Mat& eigen_values);											// checking order of eigen values & vectors (it should be none up)
     91     bool check_orthogonality(const cv::Mat& U);												// checking is matrix of eigen vectors orthogonal
     92     bool test_pairs(const cv::Mat& src);													// complex test for eigen with vectors
     93 
     94     void print_information(const size_t norm_idx, const cv::Mat& src, double diff, double max_diff);
     95 };
     96 
     97 class Core_EigenTest_Scalar : public Core_EigenTest
     98 {
     99 public:
    100     Core_EigenTest_Scalar() : Core_EigenTest() {}
    101     ~Core_EigenTest_Scalar();
    102 
    103     virtual void run(int) = 0;
    104 };
    105 
    106 class Core_EigenTest_Scalar_32 : public Core_EigenTest_Scalar
    107 {
    108 public:
    109     Core_EigenTest_Scalar_32() : Core_EigenTest_Scalar() {}
    110     ~Core_EigenTest_Scalar_32();
    111 
    112     void run(int);
    113 };
    114 
    115 class Core_EigenTest_Scalar_64 : public Core_EigenTest_Scalar
    116 {
    117 public:
    118     Core_EigenTest_Scalar_64() : Core_EigenTest_Scalar() {}
    119     ~Core_EigenTest_Scalar_64();
    120     void run(int);
    121 };
    122 
    123 class Core_EigenTest_32 : public Core_EigenTest
    124 {
    125 public:
    126     Core_EigenTest_32(): Core_EigenTest() {}
    127     ~Core_EigenTest_32() {}
    128     void run(int);
    129 };
    130 
    131 class Core_EigenTest_64 : public Core_EigenTest
    132 {
    133 public:
    134     Core_EigenTest_64(): Core_EigenTest() {}
    135     ~Core_EigenTest_64() {}
    136     void run(int);
    137 };
    138 
    139 Core_EigenTest_Scalar::~Core_EigenTest_Scalar() {}
    140 Core_EigenTest_Scalar_32::~Core_EigenTest_Scalar_32() {}
    141 Core_EigenTest_Scalar_64::~Core_EigenTest_Scalar_64() {}
    142 
    143 void Core_EigenTest_Scalar_32::run(int)
    144 {
    145     for (int i = 0; i < ntests; ++i)
    146     {
    147         float value = cv::randu<float>();
    148         cv::Mat src(1, 1, CV_32FC1, Scalar::all((float)value));
    149         test_values(src);
    150     }
    151 }
    152 
    153 void Core_EigenTest_Scalar_64::run(int)
    154 {
    155     for (int i = 0; i < ntests; ++i)
    156     {
    157         float value = cv::randu<float>();
    158         cv::Mat src(1, 1, CV_64FC1, Scalar::all((double)value));
    159         test_values(src);
    160     }
    161 }
    162 
    163 void Core_EigenTest_32::run(int) { check_full(CV_32FC1); }
    164 void Core_EigenTest_64::run(int) { check_full(CV_64FC1); }
    165 
    166 Core_EigenTest::Core_EigenTest()
    167 : eps_val_32(1e-3f), eps_vec_32(12e-3f),
    168   eps_val_64(1e-4f), eps_vec_64(1e-3f), ntests(100) {}
    169 Core_EigenTest::~Core_EigenTest() {}
    170 
    171 bool Core_EigenTest::check_pair_count(const cv::Mat& src, const cv::Mat& evalues, int low_index, int high_index)
    172 {
    173     int n = src.rows, s = sign(high_index);
    174     if (!( (evalues.rows == n - max<int>(0, low_index) - ((int)((n/2.0)*(s*s-s)) + (1+s-s*s)*(n - (high_index+1)))) && (evalues.cols == 1)))
    175     {
    176         std::cout << endl; std::cout << "Checking sizes of eigen values matrix " << evalues << "..." << endl;
    177         std::cout << "Number of rows: " << evalues.rows << "   Number of cols: " << evalues.cols << endl;
    178         std::cout << "Size of src symmetric matrix: " << src.rows << " * " << src.cols << endl; std::cout << endl;
    179         CV_Error(CORE_EIGEN_ERROR_COUNT, MESSAGE_ERROR_COUNT);
    180         return false;
    181     }
    182     return true;
    183 }
    184 
    185 bool Core_EigenTest::check_pair_count(const cv::Mat& src, const cv::Mat& evalues, const cv::Mat& evectors, int low_index, int high_index)
    186 {
    187     int n = src.rows, s = sign(high_index);
    188     int right_eigen_pair_count = n - max<int>(0, low_index) - ((int)((n/2.0)*(s*s-s)) + (1+s-s*s)*(n - (high_index+1)));
    189 
    190     if (!(evectors.rows == right_eigen_pair_count && evectors.cols == right_eigen_pair_count))
    191     {
    192         std::cout << endl; std::cout << "Checking sizes of eigen vectors matrix " << evectors << "..." << endl;
    193         std::cout << "Number of rows: " << evectors.rows << "   Number of cols: " << evectors.cols << endl;
    194         std:: cout << "Size of src symmetric matrix: " << src.rows << " * " << src.cols << endl; std::cout << endl;
    195         CV_Error (CORE_EIGEN_ERROR_SIZE, MESSAGE_ERROR_SIZE);
    196         return false;
    197     }
    198 
    199     if (!(evalues.rows == right_eigen_pair_count && evalues.cols == 1))
    200     {
    201         std::cout << endl; std::cout << "Checking sizes of eigen values matrix " << evalues << "..." << endl;
    202         std::cout << "Number of rows: " << evalues.rows << "   Number of cols: " << evalues.cols << endl;
    203         std:: cout << "Size of src symmetric matrix: " << src.rows << " * " << src.cols << endl; std::cout << endl;
    204         CV_Error (CORE_EIGEN_ERROR_COUNT, MESSAGE_ERROR_COUNT);
    205         return false;
    206     }
    207 
    208     return true;
    209 }
    210 
    211 void Core_EigenTest::print_information(const size_t norm_idx, const cv::Mat& src, double diff, double max_diff)
    212 {
    213     switch (NORM_TYPE[norm_idx])
    214     {
    215     case cv::NORM_L1: std::cout << "L1"; break;
    216     case cv::NORM_L2: std::cout << "L2"; break;
    217     case cv::NORM_INF: std::cout << "INF"; break;
    218     default: break;
    219     }
    220 
    221     cout << "-criteria... " << endl;
    222     cout << "Source size: " << src.rows << " * " << src.cols << endl;
    223     cout << "Difference between original eigen vectors matrix and result: " << diff << endl;
    224     cout << "Maximum allowed difference: " << max_diff << endl; cout << endl;
    225 }
    226 
    227 bool Core_EigenTest::check_orthogonality(const cv::Mat& U)
    228 {
    229     int type = U.type();
    230     double eps_vec = type == CV_32FC1 ? eps_vec_32 : eps_vec_64;
    231     cv::Mat UUt; cv::mulTransposed(U, UUt, false);
    232 
    233     cv::Mat E = Mat::eye(U.rows, U.cols, type);
    234 
    235     for (int i = 0; i < COUNT_NORM_TYPES; ++i)
    236     {
    237         double diff = cvtest::norm(UUt, E, NORM_TYPE[i]);
    238         if (diff > eps_vec)
    239         {
    240             std::cout << endl; std::cout << "Checking orthogonality of matrix " << U << ": ";
    241             print_information(i, U, diff, eps_vec);
    242             CV_Error(CORE_EIGEN_ERROR_ORTHO, MESSAGE_ERROR_ORTHO);
    243             return false;
    244         }
    245     }
    246 
    247     return true;
    248 }
    249 
    250 bool Core_EigenTest::check_pairs_order(const cv::Mat& eigen_values)
    251 {
    252     switch (eigen_values.type())
    253     {
    254     case CV_32FC1:
    255         {
    256             for (int i = 0; i < (int)(eigen_values.total() - 1); ++i)
    257                 if (!(eigen_values.at<float>(i, 0) > eigen_values.at<float>(i+1, 0)))
    258                 {
    259                 std::cout << endl; std::cout << "Checking order of eigen values vector " << eigen_values << "..." << endl;
    260                 std::cout << "Pair of indexes with non ascending of eigen values: (" << i << ", " << i+1 << ")." << endl;
    261                 std::cout << endl;
    262                 CV_Error(CORE_EIGEN_ERROR_ORDER, MESSAGE_ERROR_ORDER);
    263                 return false;
    264             }
    265 
    266             break;
    267         }
    268 
    269     case CV_64FC1:
    270         {
    271             for (int i = 0; i < (int)(eigen_values.total() - 1); ++i)
    272                 if (!(eigen_values.at<double>(i, 0) > eigen_values.at<double>(i+1, 0)))
    273                 {
    274                     std::cout << endl; std::cout << "Checking order of eigen values vector " << eigen_values << "..." << endl;
    275                     std::cout << "Pair of indexes with non ascending of eigen values: (" << i << ", " << i+1 << ")." << endl;
    276                     std::cout << endl;
    277                     CV_Error(CORE_EIGEN_ERROR_ORDER, "Eigen values are not sorted in ascending order.");
    278                     return false;
    279                 }
    280 
    281             break;
    282         }
    283 
    284     default:;
    285     }
    286 
    287     return true;
    288 }
    289 
    290 bool Core_EigenTest::test_pairs(const cv::Mat& src)
    291 {
    292     int type = src.type();
    293     double eps_vec = type == CV_32FC1 ? eps_vec_32 : eps_vec_64;
    294 
    295     cv::Mat eigen_values, eigen_vectors;
    296 
    297     cv::eigen(src, eigen_values, eigen_vectors);
    298 
    299     if (!check_pair_count(src, eigen_values, eigen_vectors))
    300         return false;
    301 
    302     if (!check_orthogonality (eigen_vectors))
    303         return false;
    304 
    305     if (!check_pairs_order(eigen_values))
    306         return false;
    307 
    308     cv::Mat eigen_vectors_t; cv::transpose(eigen_vectors, eigen_vectors_t);
    309 
    310     cv::Mat src_evec(src.rows, src.cols, type);
    311     src_evec = src*eigen_vectors_t;
    312 
    313     cv::Mat eval_evec(src.rows, src.cols, type);
    314 
    315     switch (type)
    316     {
    317     case CV_32FC1:
    318         {
    319             for (int i = 0; i < src.cols; ++i)
    320             {
    321                 cv::Mat tmp = eigen_values.at<float>(i, 0) * eigen_vectors_t.col(i);
    322                 for (int j = 0; j < src.rows; ++j) eval_evec.at<float>(j, i) = tmp.at<float>(j, 0);
    323             }
    324 
    325             break;
    326         }
    327 
    328     case CV_64FC1:
    329         {
    330             for (int i = 0; i < src.cols; ++i)
    331             {
    332                 cv::Mat tmp = eigen_values.at<double>(i, 0) * eigen_vectors_t.col(i);
    333                 for (int j = 0; j < src.rows; ++j) eval_evec.at<double>(j, i) = tmp.at<double>(j, 0);
    334             }
    335 
    336             break;
    337         }
    338 
    339     default:;
    340     }
    341 
    342     cv::Mat disparity = src_evec - eval_evec;
    343 
    344     for (int i = 0; i < COUNT_NORM_TYPES; ++i)
    345     {
    346         double diff = cvtest::norm(disparity, NORM_TYPE[i]);
    347         if (diff > eps_vec)
    348         {
    349             std::cout << endl; std::cout << "Checking accuracy of eigen vectors computing for matrix " << src << ": ";
    350             print_information(i, src, diff, eps_vec);
    351             CV_Error(CORE_EIGEN_ERROR_DIFF, MESSAGE_ERROR_DIFF_2);
    352             return false;
    353         }
    354     }
    355 
    356     return true;
    357 }
    358 
    359 bool Core_EigenTest::test_values(const cv::Mat& src)
    360 {
    361     int type = src.type();
    362     double eps_val = type == CV_32FC1 ? eps_val_32 : eps_val_64;
    363 
    364     cv::Mat eigen_values_1, eigen_values_2, eigen_vectors;
    365 
    366     if (!test_pairs(src)) return false;
    367 
    368     cv::eigen(src, eigen_values_1, eigen_vectors);
    369     cv::eigen(src, eigen_values_2);
    370 
    371     if (!check_pair_count(src, eigen_values_2)) return false;
    372 
    373     for (int i = 0; i < COUNT_NORM_TYPES; ++i)
    374     {
    375         double diff = cvtest::norm(eigen_values_1, eigen_values_2, NORM_TYPE[i]);
    376         if (diff > eps_val)
    377         {
    378             std::cout << endl; std::cout << "Checking accuracy of eigen values computing for matrix " << src << ": ";
    379             print_information(i, src, diff, eps_val);
    380             CV_Error(CORE_EIGEN_ERROR_DIFF, MESSAGE_ERROR_DIFF_1);
    381             return false;
    382         }
    383     }
    384 
    385     return true;
    386 }
    387 
    388 bool Core_EigenTest::check_full(int type)
    389 {
    390     const int MAX_DEGREE = 7;
    391 
    392     srand((unsigned int)time(0));
    393 
    394     for (int i = 0; i < ntests; ++i)
    395     {
    396         int src_size = (int)(std::pow(2.0, (rand()%MAX_DEGREE)+1.));
    397 
    398         cv::Mat src(src_size, src_size, type);
    399 
    400         for (int j = 0; j < src.rows; ++j)
    401             for (int k = j; k < src.cols; ++k)
    402                 if (type == CV_32FC1)  src.at<float>(k, j) = src.at<float>(j, k) = cv::randu<float>();
    403         else	src.at<double>(k, j) = src.at<double>(j, k) = cv::randu<double>();
    404 
    405         if (!test_values(src)) return false;
    406     }
    407 
    408     return true;
    409 }
    410 
    411 TEST(Core_Eigen, scalar_32) {Core_EigenTest_Scalar_32 test; test.safe_run(); }
    412 TEST(Core_Eigen, scalar_64) {Core_EigenTest_Scalar_64 test; test.safe_run(); }
    413 TEST(Core_Eigen, vector_32) { Core_EigenTest_32 test; test.safe_run(); }
    414 TEST(Core_Eigen, vector_64) { Core_EigenTest_64 test; test.safe_run(); }
    415