From c53313b06f6e55fe5997f873d041b04f275772af Mon Sep 17 00:00:00 2001 From: Alexander Reshetnikov Date: Tue, 3 Jan 2012 19:06:56 +0000 Subject: [PATCH] Complex eigen test was modified. Fixed some bugs with checking for CV_64FC1 type. Added eigen tests for 1*1 source matrix. --- modules/core/test/test_eigen.cpp | 377 ++++++++++++++++++++++++--------------- 1 file changed, 237 insertions(+), 140 deletions(-) diff --git a/modules/core/test/test_eigen.cpp b/modules/core/test/test_eigen.cpp index f982199..f1d2033 100644 --- a/modules/core/test/test_eigen.cpp +++ b/modules/core/test/test_eigen.cpp @@ -5,211 +5,308 @@ using namespace std; #define sign(a) a > 0 ? 1 : a == 0 ? 0 : -1 +#define CORE_EIGEN_ERROR_COUNT 1 +#define CORE_EIGEN_ERROR_SIZE 2 +#define CORE_EIGEN_ERROR_DIFF 3 +#define CORE_EIGEN_ERROR_ORTHO 4 +#define CORE_EIGEN_ERROR_ORDER 5 + +// #define CORE_EIGEN_ERROR_DIFF + class Core_EigenTest: public cvtest::BaseTest { public: - Core_EigenTest(); + + Core_EigenTest(); ~Core_EigenTest(); - + protected: - void run (int); + + bool test_values(const cv::Mat& src); // complex test for eigen without vectors + bool check_full(int type); // compex test for symmetric matrix + virtual void run (int) = 0; // main testing method private: float eps_val_32, eps_vec_32; - double eps_val_64, eps_vec_64; - void check_pair_count(const cv::Mat& src, const cv::Mat& evalues, int low_index = -1, int high_index = -1); - void check_pair_count(const cv::Mat& src, const cv::Mat& evalues, const cv::Mat& evectors, int low_index = -1, int high_index = -1); - bool check_diff(const cv::Mat& original_values, const cv::Mat& original_vectors, - const cv::Mat& found_values, const cv::Mat& found_vectors, - const bool compute_eigen_vectors, const int values_type, const int norm_type); + float eps_val_64, eps_vec_64; + bool check_pair_count(const cv::Mat& src, const cv::Mat& evalues, int low_index = -1, int high_index = -1); + bool check_pair_count(const cv::Mat& src, const cv::Mat& evalues, const cv::Mat& evectors, int low_index = -1, int high_index = -1); + bool check_pairs_order(const cv::Mat& eigen_values); // checking order of eigen values & vectors (it should be none up) + bool check_orthogonality(const cv::Mat& U); // checking is matrix of eigen vectors orthogonal + bool test_pairs(const cv::Mat& src); // complex test for eigen with vectors +}; + +class Core_EigenTest_Scalar : public Core_EigenTest +{ + public: + Core_EigenTest_Scalar() : Core_EigenTest() {} + ~Core_EigenTest_Scalar(); + virtual void run(int) = 0; +}; + +class Core_EigenTest_Scalar_32 : public Core_EigenTest_Scalar +{ + public: + Core_EigenTest_Scalar_32() : Core_EigenTest_Scalar() {} + ~Core_EigenTest_Scalar_32(); + + void run(int); +}; + +class Core_EigenTest_Scalar_64 : public Core_EigenTest_Scalar +{ + public: + Core_EigenTest_Scalar_64() : Core_EigenTest_Scalar() {} + ~Core_EigenTest_Scalar_64(); + void run(int); +}; + +class Core_EigenTest_32 : public Core_EigenTest +{ + public: + Core_EigenTest_32(): Core_EigenTest() {} + ~Core_EigenTest_32() {} + void run(int); }; -Core_EigenTest::Core_EigenTest() : eps_val_32(1e-3), eps_vec_32(1e-2), eps_val_64(1e-5), eps_vec_64(1e-4) {} +class Core_EigenTest_64 : public Core_EigenTest +{ + public: + Core_EigenTest_64(): Core_EigenTest() {} + ~Core_EigenTest_64() {} + void run(int); +}; + +Core_EigenTest_Scalar::~Core_EigenTest_Scalar() {} +Core_EigenTest_Scalar_32::~Core_EigenTest_Scalar_32() {} +Core_EigenTest_Scalar_64::~Core_EigenTest_Scalar_64() {} + +void Core_EigenTest_Scalar_32::run(int) +{ + float value = cv::randu(); + cv::Mat src(1, 1, CV_32FC1, Scalar::all((float)value)); + test_values(src); + src.~Mat(); +} + +void Core_EigenTest_Scalar_64::run(int) +{ + float value = cv::randu(); + cv::Mat src(1, 1, CV_64FC1, Scalar::all((double)value)); + test_values(src); + src.~Mat(); +} + +void Core_EigenTest_32::run(int) { check_full(CV_32FC1); } +void Core_EigenTest_64::run(int) { check_full(CV_64FC1); } + +Core_EigenTest::Core_EigenTest() : eps_val_32(1e-3), eps_vec_32(1e-2), eps_val_64(1e-4), eps_vec_64(1e-3) {} Core_EigenTest::~Core_EigenTest() {} -void Core_EigenTest::check_pair_count(const cv::Mat& src, const cv::Mat& evalues, int low_index, int high_index) +bool Core_EigenTest::check_pair_count(const cv::Mat& src, const cv::Mat& evalues, int low_index, int high_index) { int n = src.rows, s = sign(high_index); - CV_Assert ( evalues.rows == n - max(0, low_index) - ((int)((n/2.0)*(s*s-s)) + (1+s-s*s)*(n - (high_index+1))) && evalues.cols == 1); + if (!( (evalues.rows == n - max(0, low_index) - ((int)((n/2.0)*(s*s-s)) + (1+s-s*s)*(n - (high_index+1)))) && (evalues.cols == 1))) + { + std::cout << "Checking sizes of eigen values matrix " << evalues << "..." << endl; + CV_Error(CORE_EIGEN_ERROR_COUNT, "Matrix of eigen values must have the same rows as source matrix and 1 column."); + return false; + } + return true; } -void Core_EigenTest::check_pair_count(const cv::Mat& src, const cv::Mat& evalues, const cv::Mat& evectors, int low_index, int high_index) +bool Core_EigenTest::check_pair_count(const cv::Mat& src, const cv::Mat& evalues, const cv::Mat& evectors, int low_index, int high_index) { int n = src.rows, s = sign(high_index); int right_eigen_pair_count = n - max(0, low_index) - ((int)((n/2.0)*(s*s-s)) + (1+s-s*s)*(n - (high_index+1))); - CV_Assert ( evectors.rows == right_eigen_pair_count && - evectors.cols == right_eigen_pair_count && - evalues.rows == right_eigen_pair_count && - evalues.cols == 1 ); -} -bool Core_EigenTest::check_diff(const cv::Mat& original_values, const cv::Mat& original_vectors, - const cv::Mat& found_values, const cv::Mat& found_vectors, - const bool compute_eigen_vectors, const int values_type, const int norm_type) -{ - double eps_val = values_type == CV_32FC1 ? eps_val_32 : eps_val_64; - double eps_vec = values_type == CV_32FC1 ? eps_vec_32 : eps_vec_64; + if (!((evectors.rows == right_eigen_pair_count) && (evectors.cols == right_eigen_pair_count))) + { + std::cout << "Checking sizes of eigen vectors matrix " << evectors << "..." << endl; + CV_Error (CORE_EIGEN_ERROR_SIZE, "Source matrix and matrix of eigen vectors must have the same sizes."); + return false; + } - switch (compute_eigen_vectors) + if (!((evalues.rows == right_eigen_pair_count) && (evalues.cols == 1))) { - case true: - { - double diff_val = cv::norm(original_values, found_values, norm_type); - double diff_vec = cv::norm(original_vectors, found_vectors, norm_type); - - if (diff_val > eps_val) { ts->printf(cvtest::TS::LOG, "Accuracy of eigen values computing less than requered."); return false; } - if (diff_vec > eps_vec) { ts->printf(cvtest::TS::LOG, "Accuracy of eigen vectors computing less than requered."); return false; } - - break; - } - - case false: - { - double diff_val = cv::norm(original_values, found_values, norm_type); - - if (diff_val > eps_val) { ts->printf(cvtest::TS::LOG, "Accuracy of eigen values computing less than requered."); return false; } - - break; - } - - default:; + std::cout << "Checking sizes of eigen values matrix " << evalues << "..." << endl; + CV_Error (CORE_EIGEN_ERROR_COUNT, "Matrix of eigen values must have the same rows as source matrix and 1 column."); + return false; } return true; } -void Core_EigenTest::run(int) +bool Core_EigenTest::check_orthogonality(const cv::Mat& U) { - const int DIM = 3; - - // tests data + int type = U.type(); + double eps_vec = type == CV_32FC1 ? eps_vec_32 : eps_vec_64; + cv::Mat UUt; cv::mulTransposed(U, UUt, false); - float sym_matrix[DIM*DIM] = { 0.0f, 1.0f, 0.0f, - 1.0f, 0.0f, 1.0f, - 0.0f, 1.0f, 0.0f }; // source symmerical matrix + cv::Mat E = Mat::eye(U.rows, U.cols, type); + + double diff_L1 = cv::norm(UUt, E, NORM_L1); + double diff_L2 = cv::norm(UUt, E, NORM_L2); + double diff_INF = cv::norm(UUt, E, NORM_INF); - float _eval[DIM] = { sqrt(2.0f), 0.0f, -sqrt(2.0f) }; // eigen values of 3*3 matrix + if (diff_L1 > eps_vec) { std::cout << "Checking orthogonality of matrix " << U << "..." << endl; CV_Error(CORE_EIGEN_ERROR_ORTHO, "Matrix of eigen vectors is not orthogonal."); return false; } + if (diff_L2 > eps_vec) { std::cout << "Checking orthogonality of matrix " << U << "..." << endl; CV_Error(CORE_EIGEN_ERROR_ORTHO, "Matrix of eigen vectors is not orthogonal."); return false; } + if (diff_INF > eps_vec) { std::cout << "Checking orthogonality of matrix " << U << "..." << endl; CV_Error(CORE_EIGEN_ERROR_ORTHO, "Matrix of eigen vectors is not orthogonal."); return false; } - float _evec[DIM*DIM] = { 0.5f, 0.5f*sqrt(2.0f), 0.5f, - -0.5f*sqrt(2.0f), 0.0f, 0.5f*sqrt(2.0f), - 0.5f, -0.5f*sqrt(2.0f), 0.5f }; // eigen vectors of source matrix + return true; +} - // initializing Mat-objects - - cv::Mat eigen_values, eigen_vectors; +bool Core_EigenTest::check_pairs_order(const cv::Mat& eigen_values) +{ + switch (eigen_values.type()) + { + case CV_32FC1: + { + for (int i = 0; i < eigen_values.total() - 1; ++i) + if (!(eigen_values.at(i, 0) > eigen_values.at(i+1, 0))) + { + std::cout << "Checking order of eigen values vector " << eigen_values << "..." << endl; + CV_Error(CORE_EIGEN_ERROR_ORDER, "Eigen values are not sorted in ascending order."); + return false; + } + + break; + } - cv::Mat src_32(DIM, DIM, CV_32FC1, sym_matrix); - cv::Mat eval_32(DIM, 1, CV_32FC1, _eval); - cv::Mat evec_32(DIM, DIM, CV_32FC1, _evec); + case CV_64FC1: + { + for (int i = 0; i < eigen_values.total() - 1; ++i) + if (!(eigen_values.at(i, 0) > eigen_values.at(i+1, 0))) + { + std::cout << "Checking order of eigen values vector " << eigen_values << "..." << endl; + CV_Error(CORE_EIGEN_ERROR_ORDER, "Eigen values are not sorted in ascending order."); + return false; + } + + break; + } - cv::eigen(src_32, true, eigen_values, eigen_vectors); + default:; + } - check_pair_count(src_32, eigen_values, eigen_vectors); + return true; +} - if (!check_diff(eval_32, evec_32, eigen_values, eigen_vectors, true, CV_32FC1, NORM_L1)) return; - if (!check_diff(eval_32, evec_32, eigen_values, eigen_vectors, true, CV_32FC1, NORM_L2)) return; - if (!check_diff(eval_32, evec_32, eigen_values, eigen_vectors, true, CV_32FC1, NORM_INF)) return; +bool Core_EigenTest::test_pairs(const cv::Mat& src) +{ + int type = src.type(); + double eps_vec = type == CV_32FC1 ? eps_vec_32 : eps_vec_64; - cv::eigen(src_32, false, eigen_values, eigen_vectors); + cv::Mat eigen_values, eigen_vectors; + + cv::eigen(src, true, eigen_values, eigen_vectors); - check_pair_count(src_32, eigen_values); + if (!check_pair_count(src, eigen_values, eigen_vectors)) return false; - if (!check_diff(eval_32, evec_32, eigen_values, eigen_vectors, false, CV_32FC1, NORM_L1)) return; - if (!check_diff(eval_32, evec_32, eigen_values, eigen_vectors, false, CV_32FC1, NORM_L2)) return; - if (!check_diff(eval_32, evec_32, eigen_values, eigen_vectors, false, CV_32FC1, NORM_INF)) return; - - cv::eigen(src_32, eigen_values, eigen_vectors); + if (!check_orthogonality (eigen_vectors)) return false; - check_pair_count(src_32, eigen_values, eigen_vectors); + if (!check_pairs_order(eigen_values)) return false; - if (!check_diff(eval_32, evec_32, eigen_values, eigen_vectors, true, CV_32FC1, NORM_L1)) return; - if (!check_diff(eval_32, evec_32, eigen_values, eigen_vectors, true, CV_32FC1, NORM_L2)) return; - if (!check_diff(eval_32, evec_32, eigen_values, eigen_vectors, true, CV_32FC1, NORM_INF)) return; + cv::Mat eigen_vectors_t; cv::transpose(eigen_vectors, eigen_vectors_t); - cv::eigen(src_32, eigen_values); - - check_pair_count(src_32, eigen_values); + cv::Mat src_evec(src.rows, src.cols, type); + src_evec = src*eigen_vectors_t; - if (!check_diff(eval_32, evec_32, eigen_values, eigen_vectors, false, CV_32FC1, NORM_L1)) return; - if (!check_diff(eval_32, evec_32, eigen_values, eigen_vectors, false, CV_32FC1, NORM_L2)) return; - if (!check_diff(eval_32, evec_32, eigen_values, eigen_vectors, false, CV_32FC1, NORM_INF)) return; + cv::Mat eval_evec(src.rows, src.cols, type); - cv::Mat src_64(DIM, DIM, CV_64FC1, sym_matrix); - cv::Mat eval_64(DIM, 1, CV_64FC1, _eval); - cv::Mat evec_64(DIM, DIM, CV_64FC1, _evec); + switch (type) + { + case CV_32FC1: + { + for (size_t i = 0; i < src.cols; ++i) + { + cv::Mat tmp = eigen_values.at(i, 0) * eigen_vectors_t.col(i); + for (size_t j = 0; j < src.rows; ++j) eval_evec.at(j, i) = tmp.at(j, 0); + } - cv::eigen(src_64, true, eigen_values, eigen_vectors); + break; + } + + case CV_64FC1: + { + for (size_t i = 0; i < src.cols; ++i) + { + cv::Mat tmp = eigen_values.at(i, 0) * eigen_vectors_t.col(i); + for (size_t j = 0; j < src.rows; ++j) eval_evec.at(j, i) = tmp.at(j, 0); + } - check_pair_count(src_64, eigen_values, eigen_vectors); + break; + } - if (!check_diff(eval_64, evec_64, eigen_values, eigen_vectors, true, CV_64FC1, NORM_L1)) return; - if (!check_diff(eval_64, evec_64, eigen_values, eigen_vectors, true, CV_64FC1, NORM_L2)) return; - if (!check_diff(eval_64, evec_64, eigen_values, eigen_vectors, true, CV_64FC1, NORM_INF)) return; + default:; + } - cv::eigen(src_64, false, eigen_values, eigen_vectors); + cv::Mat disparity = src_evec - eval_evec; - check_pair_count(src_64, eigen_values); + double diff_L1 = cv::norm(disparity, NORM_L1); + double diff_L2 = cv::norm(disparity, NORM_L2); + double diff_INF = cv::norm(disparity, NORM_INF); - if (!check_diff(eval_64, evec_64, eigen_values, eigen_vectors, false, CV_64FC1, NORM_L1)) return; - if (!check_diff(eval_64, evec_64, eigen_values, eigen_vectors, false, CV_64FC1, NORM_L2)) return; - if (!check_diff(eval_64, evec_64, eigen_values, eigen_vectors, false, CV_64FC1, NORM_INF)) return; - - cv::eigen(src_64, eigen_values, eigen_vectors); + if (diff_L1 > eps_vec) { std::cout << "Checking accuracy of eigen vectors computing for matrix " << src << ": L1-criteria..." << endl; CV_Error(CORE_EIGEN_ERROR_DIFF, "Accuracy of eigen vectors computing less than required."); return false; } + if (diff_L2 > eps_vec) { std::cout << "Checking accuracy of eigen vectors computing for matrix " << src << ": L2-criteria..." << endl; CV_Error(CORE_EIGEN_ERROR_DIFF, "Accuracy of eigen vectors computing less than required."); return false; } + if (diff_INF > eps_vec) { std::cout << "Checking accuracy of eigen vectors computing for matrix " << src << ": INF-criteria..." << endl; CV_Error(CORE_EIGEN_ERROR_DIFF, "Accuracy of eigen vectors computing less than required."); return false; } - check_pair_count(src_64, eigen_values, eigen_vectors); + return true; +} - if (!check_diff(eval_64, evec_64, eigen_values, eigen_vectors, true, CV_64FC1, NORM_L1)) return; - if (!check_diff(eval_64, evec_64, eigen_values, eigen_vectors, true, CV_64FC1, NORM_L2)) return; - if (!check_diff(eval_64, evec_64, eigen_values, eigen_vectors, true, CV_64FC1, NORM_INF)) return; +bool Core_EigenTest::test_values(const cv::Mat& src) +{ + int type = src.type(); + double eps_val = type == CV_32FC1 ? eps_val_32 : eps_val_64; - cv::eigen(src_64, eigen_values); - - check_pair_count(src_64, eigen_values); + cv::Mat eigen_values_1, eigen_values_2, eigen_vectors; - if (!check_diff(eval_64, evec_64, eigen_values, eigen_vectors, false, CV_64FC1, NORM_L1)) return; - if (!check_diff(eval_64, evec_64, eigen_values, eigen_vectors, false, CV_64FC1, NORM_L2)) return; - if (!check_diff(eval_64, evec_64, eigen_values, eigen_vectors, false, CV_64FC1, NORM_INF)) return; + if (!test_pairs(src)) return false; - const int low_index = 1, high_index = 2; - cv::Mat submat_val_32(eval_32.rowRange(low_index, high_index)); - cv::Mat submat_vec_32(evec_32.rowRange(low_index, high_index)); + cv::eigen(src, true, eigen_values_1, eigen_vectors); + cv::eigen(src, false, eigen_values_2, eigen_vectors); - cv::eigen(src_32, eigen_values, low_index, high_index); + if (!check_pair_count(src, eigen_values_2)) return false; + + double diff_L1 = cv::norm(eigen_values_1, eigen_values_2, NORM_L1); + double diff_L2 = cv::norm(eigen_values_1, eigen_values_2, NORM_L2); + double diff_INF = cv::norm(eigen_values_1, eigen_values_2, NORM_INF); - check_pair_count(src_32, eigen_values, eigen_vectors, low_index, high_index); + if (diff_L1 > eps_val) { std::cout << "Checking accuracy of eigen values computing for matrix " << src << ": L1-criteria..." << endl; CV_Error(CORE_EIGEN_ERROR_DIFF, "Accuracy of eigen values computing less than required."); return false; } + if (diff_L2 > eps_val) { std::cout << "Checking accuracy of eigen values computing for matrix " << src << ": L2-criteria..." << endl; CV_Error(CORE_EIGEN_ERROR_DIFF, "Accuracy of eigen vectors computing less than required."); return false; } + if (diff_INF > eps_val) { std::cout << "Checking accuracy of eigen values computing for matrix " << src << ": INF-criteria..." << endl; CV_Error(CORE_EIGEN_ERROR_DIFF, "Accuracy of eigen vectors computing less than required."); return false; } - if (!check_diff(submat_val_32, submat_vec_32, eigen_values, eigen_vectors, false, CV_32FC1, NORM_L1)) return; - if (!check_diff(submat_val_32, submat_vec_32, eigen_values, eigen_vectors, false, CV_32FC1, NORM_L2)) return; - if (!check_diff(submat_val_32, submat_vec_32, eigen_values, eigen_vectors, false, CV_32FC1, NORM_INF)) return; + return true; +} - cv::eigen(src_32, eigen_values, eigen_vectors, low_index, high_index); +bool Core_EigenTest::check_full(int type) +{ + const int MATRIX_COUNT = 500; + const int MAX_DEGREE = 7; - check_pair_count(src_32, eigen_values, eigen_vectors, low_index, high_index); + srand(time(0)); - if (!check_diff(submat_val_32, submat_vec_32, eigen_values, eigen_vectors, true, CV_32FC1, NORM_L1)) return; - if (!check_diff(submat_val_32, submat_vec_32, eigen_values, eigen_vectors, true, CV_32FC1, NORM_L2)) return; - if (!check_diff(submat_val_32, submat_vec_32, eigen_values, eigen_vectors, true, CV_32FC1, NORM_INF)) return; + for (size_t i = 1; i <= MATRIX_COUNT; ++i) + { + size_t src_size = (int)(std::pow(2.0, (rand()%MAX_DEGREE+1)*1.0)); - cv::Mat submat_val_64(eval_64.rowRange(low_index, high_index)); - cv::Mat submat_vec_64(evec_64.rowRange(low_index, high_index)); - - cv::eigen(src_64, eigen_values, low_index, high_index); - - check_pair_count(src_64, eigen_values, low_index, high_index); - - if (!check_diff(submat_val_64, submat_vec_64, eigen_values, eigen_vectors, false, CV_64FC1, NORM_L1)) return; - if (!check_diff(submat_val_64, submat_vec_64, eigen_values, eigen_vectors, false, CV_64FC1, NORM_L2)) return; - if (!check_diff(submat_val_64, submat_vec_64, eigen_values, eigen_vectors, false, CV_64FC1, NORM_INF)) return; + cv::Mat src(src_size, src_size, type); - cv::eigen(src_64, eigen_values, eigen_vectors, low_index, high_index); + for (int j = 0; j < src.rows; ++j) + for (int k = j; k < src.cols; ++k) + if (type == CV_32FC1) src.at(k, j) = src.at(j, k) = cv::randu(); + else src.at(k, j) = src.at(j, k) = cv::randu(); + + if (!test_values(src)) return false; - check_pair_count(src_64, eigen_values, low_index, high_index); + src.~Mat(); + } - if (!check_diff(submat_val_64, submat_vec_64, eigen_values, eigen_vectors, true, CV_64FC1, NORM_L1)) return; - if (!check_diff(submat_val_64, submat_vec_64, eigen_values, eigen_vectors, true, CV_64FC1, NORM_L2)) return; - if (!check_diff(submat_val_64, submat_vec_64, eigen_values, eigen_vectors, true, CV_64FC1, NORM_INF)) return; + return true; } -TEST(Core_Eigen, accuracy) { Core_EigenTest test; test.safe_run(); } - +TEST(Core_Eigen_Scalar_32, single_complex) {Core_EigenTest_Scalar_32 test; test.safe_run(); } +TEST(Core_Eigen_Scalar_64, single_complex) {Core_EigenTest_Scalar_64 test; test.safe_run(); } +TEST(Core_Eigen_32, complex) { Core_EigenTest_32 test; test.safe_run(); } +TEST(Core_Eigen_64, complex) { Core_EigenTest_64 test; test.safe_run(); } \ No newline at end of file -- 2.7.4