/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to this license. // If you do not agree to this license, do not download, install, // copy or use the software. // // // Intel License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000, Intel Corporation, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of Intel Corporation may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. // //M*/ ////////////////////////////////////////////////////////////////////////////////////////// ////////////////// tests for arithmetic, logic and statistical functions ///////////////// ////////////////////////////////////////////////////////////////////////////////////////// #include "cxcoretest.h" #include #include using namespace cv; using namespace std; class CV_ArrayOpTest : public CvTest { public: CV_ArrayOpTest(); ~CV_ArrayOpTest(); protected: void run(int); }; CV_ArrayOpTest::CV_ArrayOpTest() : CvTest( "nd-array-ops", "?" ) { support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE; } CV_ArrayOpTest::~CV_ArrayOpTest() {} static string idx2string(const int* idx, int dims) { char buf[256]; char* ptr = buf; for( int k = 0; k < dims; k++ ) { sprintf(ptr, "%4d ", idx[k]); ptr += strlen(ptr); } ptr[-1] = '\0'; return string(buf); } static const int* string2idx(const string& s, int* idx, int dims) { const char* ptr = s.c_str(); for( int k = 0; k < dims; k++ ) { int n = 0; sscanf(ptr, "%d%n", idx + k, &n); ptr += n; } return idx; } static double getValue(SparseMat& M, const int* idx, RNG& rng) { int d = M.dims(); size_t hv = 0, *phv = 0; if( (unsigned)rng % 2 ) { hv = d == 2 ? M.hash(idx[0], idx[1]) : d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx); phv = &hv; } const uchar* ptr = d == 2 ? M.ptr(idx[0], idx[1], false, phv) : d == 3 ? M.ptr(idx[0], idx[1], idx[2], false, phv) : M.ptr(idx, false, phv); return !ptr ? 0 : M.type() == CV_32F ? *(float*)ptr : M.type() == CV_64F ? *(double*)ptr : 0; } static double getValue(const CvSparseMat* M, const int* idx) { int type = 0; const uchar* ptr = cvPtrND(M, idx, &type, 0); return !ptr ? 0 : type == CV_32F ? *(float*)ptr : type == CV_64F ? *(double*)ptr : 0; } static void eraseValue(SparseMat& M, const int* idx, RNG& rng) { int d = M.dims(); size_t hv = 0, *phv = 0; if( (unsigned)rng % 2 ) { hv = d == 2 ? M.hash(idx[0], idx[1]) : d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx); phv = &hv; } if( d == 2 ) M.erase(idx[0], idx[1], phv); else if( d == 3 ) M.erase(idx[0], idx[1], idx[2], phv); else M.erase(idx, phv); } static void eraseValue(CvSparseMat* M, const int* idx) { cvClearND(M, idx); } static void setValue(SparseMat& M, const int* idx, double value, RNG& rng) { int d = M.dims(); size_t hv = 0, *phv = 0; if( (unsigned)rng % 2 ) { hv = d == 2 ? M.hash(idx[0], idx[1]) : d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx); phv = &hv; } uchar* ptr = d == 2 ? M.ptr(idx[0], idx[1], true, phv) : d == 3 ? M.ptr(idx[0], idx[1], idx[2], true, phv) : M.ptr(idx, true, phv); if( M.type() == CV_32F ) *(float*)ptr = (float)value; else if( M.type() == CV_64F ) *(double*)ptr = value; else CV_Error(CV_StsUnsupportedFormat, ""); } void CV_ArrayOpTest::run( int /* start_from */) { int errcount = 0; // dense matrix operations { int sz3[] = {5, 10, 15}; MatND A(3, sz3, CV_32F), B(3, sz3, CV_16SC4); CvMatND matA = A, matB = B; RNG rng; rng.fill(A, CV_RAND_UNI, Scalar::all(-10), Scalar::all(10)); rng.fill(B, CV_RAND_UNI, Scalar::all(-10), Scalar::all(10)); int idx0[] = {3,4,5}, idx1[] = {0, 9, 7}; float val0 = 130; Scalar val1(-1000, 30, 3, 8); cvSetRealND(&matA, idx0, val0); cvSetReal3D(&matA, idx1[0], idx1[1], idx1[2], -val0); cvSetND(&matB, idx0, val1); cvSet3D(&matB, idx1[0], idx1[1], idx1[2], -val1); Ptr matC = cvCloneMatND(&matB); if( A.at(idx0[0], idx0[1], idx0[2]) != val0 || A.at(idx1[0], idx1[1], idx1[2]) != -val0 || cvGetReal3D(&matA, idx0[0], idx0[1], idx0[2]) != val0 || cvGetRealND(&matA, idx1) != -val0 || Scalar(B.at(idx0[0], idx0[1], idx0[2])) != val1 || Scalar(B.at(idx1[0], idx1[1], idx1[2])) != -val1 || Scalar(cvGet3D(matC, idx0[0], idx0[1], idx0[2])) != val1 || Scalar(cvGetND(matC, idx1)) != -val1 ) { ts->printf(CvTS::LOG, "one of cvSetReal3D, cvSetRealND, cvSet3D, cvSetND " "or the corresponding *Get* functions is not correct\n"); errcount++; } } RNG rng; const int MAX_DIM = 5, MAX_DIM_SZ = 10; // sparse matrix operations for( int si = 0; si < 10; si++ ) { int depth = (unsigned)rng % 2 == 0 ? CV_32F : CV_64F; int dims = ((unsigned)rng % MAX_DIM) + 1; int i, k, size[MAX_DIM]={0}, idx[MAX_DIM]={0}; vector all_idxs; vector all_vals; vector all_vals2; string sidx, min_sidx, max_sidx; double min_val=0, max_val=0; int p = 1; for( k = 0; k < dims; k++ ) { size[k] = ((unsigned)rng % MAX_DIM_SZ) + 1; p *= size[k]; } SparseMat M( dims, size, depth ); map M0; int nz0 = (unsigned)rng % max(p/5,10); nz0 = min(max(nz0, 1), p); all_vals.resize(nz0); all_vals2.resize(nz0); Mat_ _all_vals(all_vals), _all_vals2(all_vals2); rng.fill(_all_vals, CV_RAND_UNI, Scalar(-1000), Scalar(1000)); if( depth == CV_32F ) { Mat _all_vals_f; _all_vals.convertTo(_all_vals_f, CV_32F); _all_vals_f.convertTo(_all_vals, CV_64F); } _all_vals.convertTo(_all_vals2, _all_vals2.type(), 2); if( depth == CV_32F ) { Mat _all_vals2_f; _all_vals2.convertTo(_all_vals2_f, CV_32F); _all_vals2_f.convertTo(_all_vals2, CV_64F); } minMaxLoc(_all_vals, &min_val, &max_val); double _norm0 = norm(_all_vals, CV_C); double _norm1 = norm(_all_vals, CV_L1); double _norm2 = norm(_all_vals, CV_L2); for( i = 0; i < nz0; i++ ) { for(;;) { for( k = 0; k < dims; k++ ) idx[k] = (unsigned)rng % size[k]; sidx = idx2string(idx, dims); if( M0.count(sidx) == 0 ) break; } all_idxs.push_back(sidx); M0[sidx] = all_vals[i]; if( all_vals[i] == min_val ) min_sidx = sidx; if( all_vals[i] == max_val ) max_sidx = sidx; setValue(M, idx, all_vals[i], rng); double v = getValue(M, idx, rng); if( v != all_vals[i] ) { ts->printf(CvTS::LOG, "%d. immediately after SparseMat[%s]=%.20g the current value is %.20g\n", i, sidx.c_str(), all_vals[i], v); errcount++; break; } } Ptr M2 = (CvSparseMat*)M; MatND Md; M.copyTo(Md); SparseMat M3; SparseMat(Md).convertTo(M3, Md.type(), 2); int nz1 = (int)M.nzcount(), nz2 = (int)M3.nzcount(); double norm0 = norm(M, CV_C); double norm1 = norm(M, CV_L1); double norm2 = norm(M, CV_L2); double eps = depth == CV_32F ? FLT_EPSILON*100 : DBL_EPSILON*1000; if( nz1 != nz0 || nz2 != nz0) { errcount++; ts->printf(CvTS::LOG, "%d: The number of non-zero elements before/after converting to/from dense matrix is not correct: %d/%d (while it should be %d)\n", si, nz1, nz2, nz0 ); break; } if( fabs(norm0 - _norm0) > fabs(_norm0)*eps || fabs(norm1 - _norm1) > fabs(_norm1)*eps || fabs(norm2 - _norm2) > fabs(_norm2)*eps ) { errcount++; ts->printf(CvTS::LOG, "%d: The norms are different: %.20g/%.20g/%.20g vs %.20g/%.20g/%.20g\n", si, norm0, norm1, norm2, _norm0, _norm1, _norm2 ); break; } int n = (unsigned)rng % max(p/5,10); n = min(max(n, 1), p) + nz0; for( i = 0; i < n; i++ ) { double val1, val2, val3, val0; if(i < nz0) { sidx = all_idxs[i]; string2idx(sidx, idx, dims); val0 = all_vals[i]; } else { for( k = 0; k < dims; k++ ) idx[k] = (unsigned)rng % size[k]; sidx = idx2string(idx, dims); val0 = M0[sidx]; } val1 = getValue(M, idx, rng); val2 = getValue(M2, idx); val3 = getValue(M3, idx, rng); if( val1 != val0 || val2 != val0 || fabs(val3 - val0*2) > fabs(val0*2)*FLT_EPSILON ) { errcount++; ts->printf(CvTS::LOG, "SparseMat M[%s] = %g/%g/%g (while it should be %g)\n", sidx.c_str(), val1, val2, val3, val0 ); break; } } for( i = 0; i < n; i++ ) { double val1, val2; if(i < nz0) { sidx = all_idxs[i]; string2idx(sidx, idx, dims); } else { for( k = 0; k < dims; k++ ) idx[k] = (unsigned)rng % size[k]; sidx = idx2string(idx, dims); } eraseValue(M, idx, rng); eraseValue(M2, idx); val1 = getValue(M, idx, rng); val2 = getValue(M2, idx); if( val1 != 0 || val2 != 0 ) { errcount++; ts->printf(CvTS::LOG, "SparseMat: after deleting M[%s], it is =%g/%g (while it should be 0)\n", sidx.c_str(), val1, val2 ); break; } } int nz = (int)M.nzcount(); if( nz != 0 ) { errcount++; ts->printf(CvTS::LOG, "The number of non-zero elements after removing all the elements = %d (while it should be 0)\n", nz ); break; } int idx1[MAX_DIM], idx2[MAX_DIM]; double val1 = 0, val2 = 0; M3 = SparseMat(Md); minMaxLoc(M3, &val1, &val2, idx1, idx2); string s1 = idx2string(idx1, dims), s2 = idx2string(idx2, dims); if( val1 != min_val || val2 != max_val || s1 != min_sidx || s2 != max_sidx ) { errcount++; ts->printf(CvTS::LOG, "%d. Sparse: The value and positions of minimum/maximum elements are different from the reference values and positions:\n\t" "(%g, %g, %s, %s) vs (%g, %g, %s, %s)\n", si, val1, val2, s1.c_str(), s2.c_str(), min_val, max_val, min_sidx.c_str(), max_sidx.c_str()); break; } minMaxLoc(Md, &val1, &val2, idx1, idx2); s1 = idx2string(idx1, dims), s2 = idx2string(idx2, dims); if( (min_val < 0 && (val1 != min_val || s1 != min_sidx)) || (max_val > 0 && (val2 != max_val || s2 != max_sidx)) ) { errcount++; ts->printf(CvTS::LOG, "%d. Dense: The value and positions of minimum/maximum elements are different from the reference values and positions:\n\t" "(%g, %g, %s, %s) vs (%g, %g, %s, %s)\n", si, val1, val2, s1.c_str(), s2.c_str(), min_val, max_val, min_sidx.c_str(), max_sidx.c_str()); break; } } ts->set_failed_test_info(errcount == 0 ? CvTS::OK : CvTS::FAIL_INVALID_OUTPUT); } CV_ArrayOpTest cv_ArrayOp_test;