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