6b5d09f1557081c1f6c2943df78ef01b54efbaab
[profile/ivi/opencv.git] / modules / core / test / test_mat.cpp
1 #include "test_precomp.hpp"
2
3 using namespace cv;
4 using namespace std;
5
6
7 class Core_ReduceTest : public cvtest::BaseTest
8 {
9 public:
10     Core_ReduceTest() {};
11 protected:
12     void run( int);
13     int checkOp( const Mat& src, int dstType, int opType, const Mat& opRes, int dim );
14     int checkCase( int srcType, int dstType, int dim, Size sz );
15     int checkDim( int dim, Size sz );
16     int checkSize( Size sz );
17 };
18
19 template<class Type>
20 void testReduce( const Mat& src, Mat& sum, Mat& avg, Mat& max, Mat& min, int dim )
21 {
22     assert( src.channels() == 1 );
23     if( dim == 0 ) // row
24     {
25         sum.create( 1, src.cols, CV_64FC1 );
26         max.create( 1, src.cols, CV_64FC1 );
27         min.create( 1, src.cols, CV_64FC1 );
28     }
29     else
30     {
31         sum.create( src.rows, 1, CV_64FC1 );
32         max.create( src.rows, 1, CV_64FC1 );
33         min.create( src.rows, 1, CV_64FC1 );
34     }
35     sum.setTo(Scalar(0));
36     max.setTo(Scalar(-DBL_MAX));
37     min.setTo(Scalar(DBL_MAX));
38
39     const Mat_<Type>& src_ = src;
40     Mat_<double>& sum_ = (Mat_<double>&)sum;
41     Mat_<double>& min_ = (Mat_<double>&)min;
42     Mat_<double>& max_ = (Mat_<double>&)max;
43
44     if( dim == 0 )
45     {
46         for( int ri = 0; ri < src.rows; ri++ )
47         {
48             for( int ci = 0; ci < src.cols; ci++ )
49             {
50                 sum_(0, ci) += src_(ri, ci);
51                 max_(0, ci) = std::max( max_(0, ci), (double)src_(ri, ci) );
52                 min_(0, ci) = std::min( min_(0, ci), (double)src_(ri, ci) );
53             }
54         }
55     }
56     else
57     {
58         for( int ci = 0; ci < src.cols; ci++ )
59         {
60             for( int ri = 0; ri < src.rows; ri++ )
61             {
62                 sum_(ri, 0) += src_(ri, ci);
63                 max_(ri, 0) = std::max( max_(ri, 0), (double)src_(ri, ci) );
64                 min_(ri, 0) = std::min( min_(ri, 0), (double)src_(ri, ci) );
65             }
66         }
67     }
68     sum.convertTo( avg, CV_64FC1 );
69     avg = avg * (1.0 / (dim==0 ? (double)src.rows : (double)src.cols));
70 }
71
72 void getMatTypeStr( int type, string& str)
73 {
74     str = type == CV_8UC1 ? "CV_8UC1" :
75     type == CV_8SC1 ? "CV_8SC1" :
76     type == CV_16UC1 ? "CV_16UC1" :
77     type == CV_16SC1 ? "CV_16SC1" :
78     type == CV_32SC1 ? "CV_32SC1" :
79     type == CV_32FC1 ? "CV_32FC1" :
80     type == CV_64FC1 ? "CV_64FC1" : "unsupported matrix type";
81 }
82
83 int Core_ReduceTest::checkOp( const Mat& src, int dstType, int opType, const Mat& opRes, int dim )
84 {
85     int srcType = src.type();
86     bool support = false;
87     if( opType == CV_REDUCE_SUM || opType == CV_REDUCE_AVG )
88     {
89         if( srcType == CV_8U && (dstType == CV_32S || dstType == CV_32F || dstType == CV_64F) )
90             support = true;
91         if( srcType == CV_16U && (dstType == CV_32F || dstType == CV_64F) )
92             support = true;
93         if( srcType == CV_16S && (dstType == CV_32F || dstType == CV_64F) )
94             support = true;
95         if( srcType == CV_32F && (dstType == CV_32F || dstType == CV_64F) )
96             support = true;
97         if( srcType == CV_64F && dstType == CV_64F)
98             support = true;
99     }
100     else if( opType == CV_REDUCE_MAX )
101     {
102         if( srcType == CV_8U && dstType == CV_8U )
103             support = true;
104         if( srcType == CV_32F && dstType == CV_32F )
105             support = true;
106         if( srcType == CV_64F && dstType == CV_64F )
107             support = true;
108     }
109     else if( opType == CV_REDUCE_MIN )
110     {
111         if( srcType == CV_8U && dstType == CV_8U)
112             support = true;
113         if( srcType == CV_32F && dstType == CV_32F)
114             support = true;
115         if( srcType == CV_64F && dstType == CV_64F)
116             support = true;
117     }
118     if( !support )
119         return cvtest::TS::OK;
120
121     double eps = 0.0;
122     if ( opType == CV_REDUCE_SUM || opType == CV_REDUCE_AVG )
123     {
124         if ( dstType == CV_32F )
125             eps = 1.e-5;
126         else if( dstType == CV_64F )
127             eps = 1.e-8;
128         else if ( dstType == CV_32S )
129             eps = 0.6;
130     }
131
132     assert( opRes.type() == CV_64FC1 );
133     Mat _dst, dst, diff;
134     reduce( src, _dst, dim, opType, dstType );
135     _dst.convertTo( dst, CV_64FC1 );
136
137     absdiff( opRes,dst,diff );
138     bool check = false;
139     if (dstType == CV_32F || dstType == CV_64F)
140         check = countNonZero(diff>eps*dst) > 0;
141     else
142         check = countNonZero(diff>eps) > 0;
143     if( check )
144     {
145         char msg[100];
146         const char* opTypeStr = opType == CV_REDUCE_SUM ? "CV_REDUCE_SUM" :
147         opType == CV_REDUCE_AVG ? "CV_REDUCE_AVG" :
148         opType == CV_REDUCE_MAX ? "CV_REDUCE_MAX" :
149         opType == CV_REDUCE_MIN ? "CV_REDUCE_MIN" : "unknown operation type";
150         string srcTypeStr, dstTypeStr;
151         getMatTypeStr( src.type(), srcTypeStr );
152         getMatTypeStr( dstType, dstTypeStr );
153         const char* dimStr = dim == 0 ? "ROWS" : "COLS";
154
155         sprintf( msg, "bad accuracy with srcType = %s, dstType = %s, opType = %s, dim = %s",
156                 srcTypeStr.c_str(), dstTypeStr.c_str(), opTypeStr, dimStr );
157         ts->printf( cvtest::TS::LOG, msg );
158         return cvtest::TS::FAIL_BAD_ACCURACY;
159     }
160     return cvtest::TS::OK;
161 }
162
163 int Core_ReduceTest::checkCase( int srcType, int dstType, int dim, Size sz )
164 {
165     int code = cvtest::TS::OK, tempCode;
166     Mat src, sum, avg, max, min;
167
168     src.create( sz, srcType );
169     randu( src, Scalar(0), Scalar(100) );
170
171     if( srcType == CV_8UC1 )
172         testReduce<uchar>( src, sum, avg, max, min, dim );
173     else if( srcType == CV_8SC1 )
174         testReduce<char>( src, sum, avg, max, min, dim );
175     else if( srcType == CV_16UC1 )
176         testReduce<unsigned short int>( src, sum, avg, max, min, dim );
177     else if( srcType == CV_16SC1 )
178         testReduce<short int>( src, sum, avg, max, min, dim );
179     else if( srcType == CV_32SC1 )
180         testReduce<int>( src, sum, avg, max, min, dim );
181     else if( srcType == CV_32FC1 )
182         testReduce<float>( src, sum, avg, max, min, dim );
183     else if( srcType == CV_64FC1 )
184         testReduce<double>( src, sum, avg, max, min, dim );
185     else
186         assert( 0 );
187
188     // 1. sum
189     tempCode = checkOp( src, dstType, CV_REDUCE_SUM, sum, dim );
190     code = tempCode != cvtest::TS::OK ? tempCode : code;
191
192     // 2. avg
193     tempCode = checkOp( src, dstType, CV_REDUCE_AVG, avg, dim );
194     code = tempCode != cvtest::TS::OK ? tempCode : code;
195
196     // 3. max
197     tempCode = checkOp( src, dstType, CV_REDUCE_MAX, max, dim );
198     code = tempCode != cvtest::TS::OK ? tempCode : code;
199
200     // 4. min
201     tempCode = checkOp( src, dstType, CV_REDUCE_MIN, min, dim );
202     code = tempCode != cvtest::TS::OK ? tempCode : code;
203
204     return code;
205 }
206
207 int Core_ReduceTest::checkDim( int dim, Size sz )
208 {
209     int code = cvtest::TS::OK, tempCode;
210
211     // CV_8UC1
212     tempCode = checkCase( CV_8UC1, CV_8UC1, dim, sz );
213     code = tempCode != cvtest::TS::OK ? tempCode : code;
214
215     tempCode = checkCase( CV_8UC1, CV_32SC1, dim, sz );
216     code = tempCode != cvtest::TS::OK ? tempCode : code;
217
218     tempCode = checkCase( CV_8UC1, CV_32FC1, dim, sz );
219     code = tempCode != cvtest::TS::OK ? tempCode : code;
220
221     tempCode = checkCase( CV_8UC1, CV_64FC1, dim, sz );
222     code = tempCode != cvtest::TS::OK ? tempCode : code;
223
224     // CV_16UC1
225     tempCode = checkCase( CV_16UC1, CV_32FC1, dim, sz );
226     code = tempCode != cvtest::TS::OK ? tempCode : code;
227
228     tempCode = checkCase( CV_16UC1, CV_64FC1, dim, sz );
229     code = tempCode != cvtest::TS::OK ? tempCode : code;
230
231     // CV_16SC1
232     tempCode = checkCase( CV_16SC1, CV_32FC1, dim, sz );
233     code = tempCode != cvtest::TS::OK ? tempCode : code;
234
235     tempCode = checkCase( CV_16SC1, CV_64FC1, dim, sz );
236     code = tempCode != cvtest::TS::OK ? tempCode : code;
237
238     // CV_32FC1
239     tempCode = checkCase( CV_32FC1, CV_32FC1, dim, sz );
240     code = tempCode != cvtest::TS::OK ? tempCode : code;
241
242     tempCode = checkCase( CV_32FC1, CV_64FC1, dim, sz );
243     code = tempCode != cvtest::TS::OK ? tempCode : code;
244
245     // CV_64FC1
246     tempCode = checkCase( CV_64FC1, CV_64FC1, dim, sz );
247     code = tempCode != cvtest::TS::OK ? tempCode : code;
248
249     return code;
250 }
251
252 int Core_ReduceTest::checkSize( Size sz )
253 {
254     int code = cvtest::TS::OK, tempCode;
255
256     tempCode = checkDim( 0, sz ); // rows
257     code = tempCode != cvtest::TS::OK ? tempCode : code;
258
259     tempCode = checkDim( 1, sz ); // cols
260     code = tempCode != cvtest::TS::OK ? tempCode : code;
261
262     return code;
263 }
264
265 void Core_ReduceTest::run( int )
266 {
267     int code = cvtest::TS::OK, tempCode;
268
269     tempCode = checkSize( Size(1,1) );
270     code = tempCode != cvtest::TS::OK ? tempCode : code;
271
272     tempCode = checkSize( Size(1,100) );
273     code = tempCode != cvtest::TS::OK ? tempCode : code;
274
275     tempCode = checkSize( Size(100,1) );
276     code = tempCode != cvtest::TS::OK ? tempCode : code;
277
278     tempCode = checkSize( Size(1000,500) );
279     code = tempCode != cvtest::TS::OK ? tempCode : code;
280
281     ts->set_failed_test_info( code );
282 }
283
284
285 #define CHECK_C
286
287 class Core_PCATest : public cvtest::BaseTest
288 {
289 public:
290     Core_PCATest() {}
291 protected:
292     void run(int)
293     {
294         const Size sz(200, 500);
295
296         double diffPrjEps, diffBackPrjEps,
297         prjEps, backPrjEps,
298         evalEps, evecEps;
299         int maxComponents = 100;
300         Mat rPoints(sz, CV_32FC1), rTestPoints(sz, CV_32FC1);
301         RNG& rng = ts->get_rng();
302
303         rng.fill( rPoints, RNG::UNIFORM, Scalar::all(0.0), Scalar::all(1.0) );
304         rng.fill( rTestPoints, RNG::UNIFORM, Scalar::all(0.0), Scalar::all(1.0) );
305
306         PCA rPCA( rPoints, Mat(), CV_PCA_DATA_AS_ROW, maxComponents ), cPCA;
307
308         // 1. check C++ PCA & ROW
309         Mat rPrjTestPoints = rPCA.project( rTestPoints );
310         Mat rBackPrjTestPoints = rPCA.backProject( rPrjTestPoints );
311
312         Mat avg(1, sz.width, CV_32FC1 );
313         reduce( rPoints, avg, 0, CV_REDUCE_AVG );
314         Mat Q = rPoints - repeat( avg, rPoints.rows, 1 ), Qt = Q.t(), eval, evec;
315         Q = Qt * Q;
316         Q = Q /(float)rPoints.rows;
317
318         eigen( Q, eval, evec );
319         /*SVD svd(Q);
320          evec = svd.vt;
321          eval = svd.w;*/
322
323         Mat subEval( maxComponents, 1, eval.type(), eval.data ),
324         subEvec( maxComponents, evec.cols, evec.type(), evec.data );
325
326     #ifdef CHECK_C
327         Mat prjTestPoints, backPrjTestPoints, cPoints = rPoints.t(), cTestPoints = rTestPoints.t();
328         CvMat _points, _testPoints, _avg, _eval, _evec, _prjTestPoints, _backPrjTestPoints;
329     #endif
330
331         // check eigen()
332         double eigenEps = 1e-6;
333         double err;
334         for(int i = 0; i < Q.rows; i++ )
335         {
336             Mat v = evec.row(i).t();
337             Mat Qv = Q * v;
338
339             Mat lv = eval.at<float>(i,0) * v;
340             err = norm( Qv, lv );
341             if( err > eigenEps )
342             {
343                 ts->printf( cvtest::TS::LOG, "bad accuracy of eigen(); err = %f\n", err );
344                 ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
345                 return;
346             }
347         }
348         // check pca eigenvalues
349         evalEps = 1e-6, evecEps = 1e-3;
350         err = norm( rPCA.eigenvalues, subEval );
351         if( err > evalEps )
352         {
353             ts->printf( cvtest::TS::LOG, "pca.eigenvalues is incorrect (CV_PCA_DATA_AS_ROW); err = %f\n", err );
354             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
355             return;
356         }
357         // check pca eigenvectors
358         for(int i = 0; i < subEvec.rows; i++)
359         {
360             Mat r0 = rPCA.eigenvectors.row(i);
361             Mat r1 = subEvec.row(i);
362             err = norm( r0, r1, CV_L2 );
363             if( err > evecEps )
364             {
365                 r1 *= -1;
366                 double err2 = norm(r0, r1, CV_L2);
367                 if( err2 > evecEps )
368                 {
369                     Mat tmp;
370                     absdiff(rPCA.eigenvectors, subEvec, tmp);
371                     double mval = 0; Point mloc;
372                     minMaxLoc(tmp, 0, &mval, 0, &mloc);
373
374                     ts->printf( cvtest::TS::LOG, "pca.eigenvectors is incorrect (CV_PCA_DATA_AS_ROW); err = %f\n", err );
375                     ts->printf( cvtest::TS::LOG, "max diff is %g at (i=%d, j=%d) (%g vs %g)\n",
376                                mval, mloc.y, mloc.x, rPCA.eigenvectors.at<float>(mloc.y, mloc.x),
377                                subEvec.at<float>(mloc.y, mloc.x));
378                     ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
379                     return;
380                 }
381             }
382         }
383
384         prjEps = 1.265, backPrjEps = 1.265;
385         for( int i = 0; i < rTestPoints.rows; i++ )
386         {
387             // check pca project
388             Mat subEvec_t = subEvec.t();
389             Mat prj = rTestPoints.row(i) - avg; prj *= subEvec_t;
390             err = norm(rPrjTestPoints.row(i), prj, CV_RELATIVE_L2);
391             if( err > prjEps )
392             {
393                 ts->printf( cvtest::TS::LOG, "bad accuracy of project() (CV_PCA_DATA_AS_ROW); err = %f\n", err );
394                 ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
395                 return;
396             }
397             // check pca backProject
398             Mat backPrj = rPrjTestPoints.row(i) * subEvec + avg;
399             err = norm( rBackPrjTestPoints.row(i), backPrj, CV_RELATIVE_L2 );
400             if( err > backPrjEps )
401             {
402                 ts->printf( cvtest::TS::LOG, "bad accuracy of backProject() (CV_PCA_DATA_AS_ROW); err = %f\n", err );
403                 ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
404                 return;
405             }
406         }
407
408         // 2. check C++ PCA & COL
409         cPCA( rPoints.t(), Mat(), CV_PCA_DATA_AS_COL, maxComponents );
410         diffPrjEps = 1, diffBackPrjEps = 1;
411         Mat ocvPrjTestPoints = cPCA.project(rTestPoints.t());
412         err = norm(cv::abs(ocvPrjTestPoints), cv::abs(rPrjTestPoints.t()), CV_RELATIVE_L2 );
413         if( err > diffPrjEps )
414         {
415             ts->printf( cvtest::TS::LOG, "bad accuracy of project() (CV_PCA_DATA_AS_COL); err = %f\n", err );
416             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
417             return;
418         }
419         err = norm(cPCA.backProject(ocvPrjTestPoints), rBackPrjTestPoints.t(), CV_RELATIVE_L2 );
420         if( err > diffBackPrjEps )
421         {
422             ts->printf( cvtest::TS::LOG, "bad accuracy of backProject() (CV_PCA_DATA_AS_COL); err = %f\n", err );
423             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
424             return;
425         }
426
427     #ifdef CHECK_C
428         // 3. check C PCA & ROW
429         _points = rPoints;
430         _testPoints = rTestPoints;
431         _avg = avg;
432         _eval = eval;
433         _evec = evec;
434         prjTestPoints.create(rTestPoints.rows, maxComponents, rTestPoints.type() );
435         backPrjTestPoints.create(rPoints.size(), rPoints.type() );
436         _prjTestPoints = prjTestPoints;
437         _backPrjTestPoints = backPrjTestPoints;
438
439         cvCalcPCA( &_points, &_avg, &_eval, &_evec, CV_PCA_DATA_AS_ROW );
440         cvProjectPCA( &_testPoints, &_avg, &_evec, &_prjTestPoints );
441         cvBackProjectPCA( &_prjTestPoints, &_avg, &_evec, &_backPrjTestPoints );
442
443         err = norm(prjTestPoints, rPrjTestPoints, CV_RELATIVE_L2);
444         if( err > diffPrjEps )
445         {
446             ts->printf( cvtest::TS::LOG, "bad accuracy of cvProjectPCA() (CV_PCA_DATA_AS_ROW); err = %f\n", err );
447             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
448             return;
449         }
450         err = norm(backPrjTestPoints, rBackPrjTestPoints, CV_RELATIVE_L2);
451         if( err > diffBackPrjEps )
452         {
453             ts->printf( cvtest::TS::LOG, "bad accuracy of cvBackProjectPCA() (CV_PCA_DATA_AS_ROW); err = %f\n", err );
454             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
455             return;
456         }
457
458         // 3. check C PCA & COL
459         _points = cPoints;
460         _testPoints = cTestPoints;
461         avg = avg.t(); _avg = avg;
462         eval = eval.t(); _eval = eval;
463         evec = evec.t(); _evec = evec;
464         prjTestPoints = prjTestPoints.t(); _prjTestPoints = prjTestPoints;
465         backPrjTestPoints = backPrjTestPoints.t(); _backPrjTestPoints = backPrjTestPoints;
466
467         cvCalcPCA( &_points, &_avg, &_eval, &_evec, CV_PCA_DATA_AS_COL );
468         cvProjectPCA( &_testPoints, &_avg, &_evec, &_prjTestPoints );
469         cvBackProjectPCA( &_prjTestPoints, &_avg, &_evec, &_backPrjTestPoints );
470
471         err = norm(cv::abs(prjTestPoints), cv::abs(rPrjTestPoints.t()), CV_RELATIVE_L2 );
472         if( err > diffPrjEps )
473         {
474             ts->printf( cvtest::TS::LOG, "bad accuracy of cvProjectPCA() (CV_PCA_DATA_AS_COL); err = %f\n", err );
475             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
476             return;
477         }
478         err = norm(backPrjTestPoints, rBackPrjTestPoints.t(), CV_RELATIVE_L2);
479         if( err > diffBackPrjEps )
480         {
481             ts->printf( cvtest::TS::LOG, "bad accuracy of cvBackProjectPCA() (CV_PCA_DATA_AS_COL); err = %f\n", err );
482             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
483             return;
484         }
485     #endif
486     }
487 };
488
489 class Core_ArrayOpTest : public cvtest::BaseTest
490 {
491 public:
492     Core_ArrayOpTest();
493     ~Core_ArrayOpTest();
494 protected:
495     void run(int);
496 };
497
498
499 Core_ArrayOpTest::Core_ArrayOpTest()
500 {
501 }
502 Core_ArrayOpTest::~Core_ArrayOpTest() {}
503
504 static string idx2string(const int* idx, int dims)
505 {
506     char buf[256];
507     char* ptr = buf;
508     for( int k = 0; k < dims; k++ )
509     {
510         sprintf(ptr, "%4d ", idx[k]);
511         ptr += strlen(ptr);
512     }
513     ptr[-1] = '\0';
514     return string(buf);
515 }
516
517 static const int* string2idx(const string& s, int* idx, int dims)
518 {
519     const char* ptr = s.c_str();
520     for( int k = 0; k < dims; k++ )
521     {
522         int n = 0;
523         sscanf(ptr, "%d%n", idx + k, &n);
524         ptr += n;
525     }
526     return idx;
527 }
528
529 static double getValue(SparseMat& M, const int* idx, RNG& rng)
530 {
531     int d = M.dims();
532     size_t hv = 0, *phv = 0;
533     if( (unsigned)rng % 2 )
534     {
535         hv = d == 2 ? M.hash(idx[0], idx[1]) :
536         d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx);
537         phv = &hv;
538     }
539
540     const uchar* ptr = d == 2 ? M.ptr(idx[0], idx[1], false, phv) :
541     d == 3 ? M.ptr(idx[0], idx[1], idx[2], false, phv) :
542     M.ptr(idx, false, phv);
543     return !ptr ? 0 : M.type() == CV_32F ? *(float*)ptr : M.type() == CV_64F ? *(double*)ptr : 0;
544 }
545
546 static double getValue(const CvSparseMat* M, const int* idx)
547 {
548     int type = 0;
549     const uchar* ptr = cvPtrND(M, idx, &type, 0);
550     return !ptr ? 0 : type == CV_32F ? *(float*)ptr : type == CV_64F ? *(double*)ptr : 0;
551 }
552
553 static void eraseValue(SparseMat& M, const int* idx, RNG& rng)
554 {
555     int d = M.dims();
556     size_t hv = 0, *phv = 0;
557     if( (unsigned)rng % 2 )
558     {
559         hv = d == 2 ? M.hash(idx[0], idx[1]) :
560         d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx);
561         phv = &hv;
562     }
563
564     if( d == 2 )
565         M.erase(idx[0], idx[1], phv);
566     else if( d == 3 )
567         M.erase(idx[0], idx[1], idx[2], phv);
568     else
569         M.erase(idx, phv);
570 }
571
572 static void eraseValue(CvSparseMat* M, const int* idx)
573 {
574     cvClearND(M, idx);
575 }
576
577 static void setValue(SparseMat& M, const int* idx, double value, RNG& rng)
578 {
579     int d = M.dims();
580     size_t hv = 0, *phv = 0;
581     if( (unsigned)rng % 2 )
582     {
583         hv = d == 2 ? M.hash(idx[0], idx[1]) :
584         d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx);
585         phv = &hv;
586     }
587
588     uchar* ptr = d == 2 ? M.ptr(idx[0], idx[1], true, phv) :
589     d == 3 ? M.ptr(idx[0], idx[1], idx[2], true, phv) :
590     M.ptr(idx, true, phv);
591     if( M.type() == CV_32F )
592         *(float*)ptr = (float)value;
593     else if( M.type() == CV_64F )
594         *(double*)ptr = value;
595     else
596         CV_Error(CV_StsUnsupportedFormat, "");
597 }
598
599 void Core_ArrayOpTest::run( int /* start_from */)
600 {
601     int errcount = 0;
602
603     // dense matrix operations
604     {
605         int sz3[] = {5, 10, 15};
606         MatND A(3, sz3, CV_32F), B(3, sz3, CV_16SC4);
607         CvMatND matA = A, matB = B;
608         RNG rng;
609         rng.fill(A, CV_RAND_UNI, Scalar::all(-10), Scalar::all(10));
610         rng.fill(B, CV_RAND_UNI, Scalar::all(-10), Scalar::all(10));
611
612         int idx0[] = {3,4,5}, idx1[] = {0, 9, 7};
613         float val0 = 130;
614         Scalar val1(-1000, 30, 3, 8);
615         cvSetRealND(&matA, idx0, val0);
616         cvSetReal3D(&matA, idx1[0], idx1[1], idx1[2], -val0);
617         cvSetND(&matB, idx0, val1);
618         cvSet3D(&matB, idx1[0], idx1[1], idx1[2], -val1);
619         Ptr<CvMatND> matC = cvCloneMatND(&matB);
620
621         if( A.at<float>(idx0[0], idx0[1], idx0[2]) != val0 ||
622            A.at<float>(idx1[0], idx1[1], idx1[2]) != -val0 ||
623            cvGetReal3D(&matA, idx0[0], idx0[1], idx0[2]) != val0 ||
624            cvGetRealND(&matA, idx1) != -val0 ||
625
626            Scalar(B.at<Vec4s>(idx0[0], idx0[1], idx0[2])) != val1 ||
627            Scalar(B.at<Vec4s>(idx1[0], idx1[1], idx1[2])) != -val1 ||
628            Scalar(cvGet3D(matC, idx0[0], idx0[1], idx0[2])) != val1 ||
629            Scalar(cvGetND(matC, idx1)) != -val1 )
630         {
631             ts->printf(cvtest::TS::LOG, "one of cvSetReal3D, cvSetRealND, cvSet3D, cvSetND "
632                        "or the corresponding *Get* functions is not correct\n");
633             errcount++;
634         }
635     }
636
637     RNG rng;
638     const int MAX_DIM = 5, MAX_DIM_SZ = 10;
639     // sparse matrix operations
640     for( int si = 0; si < 10; si++ )
641     {
642         int depth = (unsigned)rng % 2 == 0 ? CV_32F : CV_64F;
643         int dims = ((unsigned)rng % MAX_DIM) + 1;
644         int i, k, size[MAX_DIM]={0}, idx[MAX_DIM]={0};
645         vector<string> all_idxs;
646         vector<double> all_vals;
647         vector<double> all_vals2;
648         string sidx, min_sidx, max_sidx;
649         double min_val=0, max_val=0;
650
651         int p = 1;
652         for( k = 0; k < dims; k++ )
653         {
654             size[k] = ((unsigned)rng % MAX_DIM_SZ) + 1;
655             p *= size[k];
656         }
657         SparseMat M( dims, size, depth );
658         map<string, double> M0;
659
660         int nz0 = (unsigned)rng % max(p/5,10);
661         nz0 = min(max(nz0, 1), p);
662         all_vals.resize(nz0);
663         all_vals2.resize(nz0);
664         Mat_<double> _all_vals(all_vals), _all_vals2(all_vals2);
665         rng.fill(_all_vals, CV_RAND_UNI, Scalar(-1000), Scalar(1000));
666         if( depth == CV_32F )
667         {
668             Mat _all_vals_f;
669             _all_vals.convertTo(_all_vals_f, CV_32F);
670             _all_vals_f.convertTo(_all_vals, CV_64F);
671         }
672         _all_vals.convertTo(_all_vals2, _all_vals2.type(), 2);
673         if( depth == CV_32F )
674         {
675             Mat _all_vals2_f;
676             _all_vals2.convertTo(_all_vals2_f, CV_32F);
677             _all_vals2_f.convertTo(_all_vals2, CV_64F);
678         }
679
680         minMaxLoc(_all_vals, &min_val, &max_val);
681         double _norm0 = norm(_all_vals, CV_C);
682         double _norm1 = norm(_all_vals, CV_L1);
683         double _norm2 = norm(_all_vals, CV_L2);
684
685         for( i = 0; i < nz0; i++ )
686         {
687             for(;;)
688             {
689                 for( k = 0; k < dims; k++ )
690                     idx[k] = (unsigned)rng % size[k];
691                 sidx = idx2string(idx, dims);
692                 if( M0.count(sidx) == 0 )
693                     break;
694             }
695             all_idxs.push_back(sidx);
696             M0[sidx] = all_vals[i];
697             if( all_vals[i] == min_val )
698                 min_sidx = sidx;
699             if( all_vals[i] == max_val )
700                 max_sidx = sidx;
701             setValue(M, idx, all_vals[i], rng);
702             double v = getValue(M, idx, rng);
703             if( v != all_vals[i] )
704             {
705                 ts->printf(cvtest::TS::LOG, "%d. immediately after SparseMat[%s]=%.20g the current value is %.20g\n",
706                            i, sidx.c_str(), all_vals[i], v);
707                 errcount++;
708                 break;
709             }
710         }
711
712         Ptr<CvSparseMat> M2 = (CvSparseMat*)M;
713         MatND Md;
714         M.copyTo(Md);
715         SparseMat M3; SparseMat(Md).convertTo(M3, Md.type(), 2);
716
717         int nz1 = (int)M.nzcount(), nz2 = (int)M3.nzcount();
718         double norm0 = norm(M, CV_C);
719         double norm1 = norm(M, CV_L1);
720         double norm2 = norm(M, CV_L2);
721         double eps = depth == CV_32F ? FLT_EPSILON*100 : DBL_EPSILON*1000;
722
723         if( nz1 != nz0 || nz2 != nz0)
724         {
725             errcount++;
726             ts->printf(cvtest::TS::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",
727                        si, nz1, nz2, nz0 );
728             break;
729         }
730
731         if( fabs(norm0 - _norm0) > fabs(_norm0)*eps ||
732            fabs(norm1 - _norm1) > fabs(_norm1)*eps ||
733            fabs(norm2 - _norm2) > fabs(_norm2)*eps )
734         {
735             errcount++;
736             ts->printf(cvtest::TS::LOG, "%d: The norms are different: %.20g/%.20g/%.20g vs %.20g/%.20g/%.20g\n",
737                        si, norm0, norm1, norm2, _norm0, _norm1, _norm2 );
738             break;
739         }
740
741         int n = (unsigned)rng % max(p/5,10);
742         n = min(max(n, 1), p) + nz0;
743
744         for( i = 0; i < n; i++ )
745         {
746             double val1, val2, val3, val0;
747             if(i < nz0)
748             {
749                 sidx = all_idxs[i];
750                 string2idx(sidx, idx, dims);
751                 val0 = all_vals[i];
752             }
753             else
754             {
755                 for( k = 0; k < dims; k++ )
756                     idx[k] = (unsigned)rng % size[k];
757                 sidx = idx2string(idx, dims);
758                 val0 = M0[sidx];
759             }
760             val1 = getValue(M, idx, rng);
761             val2 = getValue(M2, idx);
762             val3 = getValue(M3, idx, rng);
763
764             if( val1 != val0 || val2 != val0 || fabs(val3 - val0*2) > fabs(val0*2)*FLT_EPSILON )
765             {
766                 errcount++;
767                 ts->printf(cvtest::TS::LOG, "SparseMat M[%s] = %g/%g/%g (while it should be %g)\n", sidx.c_str(), val1, val2, val3, val0 );
768                 break;
769             }
770         }
771
772         for( i = 0; i < n; i++ )
773         {
774             double val1, val2;
775             if(i < nz0)
776             {
777                 sidx = all_idxs[i];
778                 string2idx(sidx, idx, dims);
779             }
780             else
781             {
782                 for( k = 0; k < dims; k++ )
783                     idx[k] = (unsigned)rng % size[k];
784                 sidx = idx2string(idx, dims);
785             }
786             eraseValue(M, idx, rng);
787             eraseValue(M2, idx);
788             val1 = getValue(M, idx, rng);
789             val2 = getValue(M2, idx);
790             if( val1 != 0 || val2 != 0 )
791             {
792                 errcount++;
793                 ts->printf(cvtest::TS::LOG, "SparseMat: after deleting M[%s], it is =%g/%g (while it should be 0)\n", sidx.c_str(), val1, val2 );
794                 break;
795             }
796         }
797
798         int nz = (int)M.nzcount();
799         if( nz != 0 )
800         {
801             errcount++;
802             ts->printf(cvtest::TS::LOG, "The number of non-zero elements after removing all the elements = %d (while it should be 0)\n", nz );
803             break;
804         }
805
806         int idx1[MAX_DIM], idx2[MAX_DIM];
807         double val1 = 0, val2 = 0;
808         M3 = SparseMat(Md);
809         minMaxLoc(M3, &val1, &val2, idx1, idx2);
810         string s1 = idx2string(idx1, dims), s2 = idx2string(idx2, dims);
811         if( val1 != min_val || val2 != max_val || s1 != min_sidx || s2 != max_sidx )
812         {
813             errcount++;
814             ts->printf(cvtest::TS::LOG, "%d. Sparse: The value and positions of minimum/maximum elements are different from the reference values and positions:\n\t"
815                        "(%g, %g, %s, %s) vs (%g, %g, %s, %s)\n", si, val1, val2, s1.c_str(), s2.c_str(),
816                        min_val, max_val, min_sidx.c_str(), max_sidx.c_str());
817             break;
818         }
819
820         minMaxIdx(Md, &val1, &val2, idx1, idx2);
821         s1 = idx2string(idx1, dims), s2 = idx2string(idx2, dims);
822         if( (min_val < 0 && (val1 != min_val || s1 != min_sidx)) ||
823            (max_val > 0 && (val2 != max_val || s2 != max_sidx)) )
824         {
825             errcount++;
826             ts->printf(cvtest::TS::LOG, "%d. Dense: The value and positions of minimum/maximum elements are different from the reference values and positions:\n\t"
827                        "(%g, %g, %s, %s) vs (%g, %g, %s, %s)\n", si, val1, val2, s1.c_str(), s2.c_str(),
828                        min_val, max_val, min_sidx.c_str(), max_sidx.c_str());
829             break;
830         }
831     }
832
833     ts->set_failed_test_info(errcount == 0 ? cvtest::TS::OK : cvtest::TS::FAIL_INVALID_OUTPUT);
834 }
835
836 TEST(Core_PCA, accuracy) { Core_PCATest test; test.safe_run(); }
837 TEST(Core_Reduce, accuracy) { Core_ReduceTest test; test.safe_run(); }
838 TEST(Core_Array, basic_operations) { Core_ArrayOpTest test; test.safe_run(); }
839
840
841 TEST(Core_IOArray, submat_assignment)
842 {
843     Mat1f A = Mat1f::zeros(2,2);
844     Mat1f B = Mat1f::ones(1,3);
845
846     EXPECT_THROW( B.colRange(0,3).copyTo(A.row(0)), cv::Exception );
847
848     EXPECT_NO_THROW( B.colRange(0,2).copyTo(A.row(0)) );
849
850     EXPECT_EQ( 1.0f, A(0,0) );
851     EXPECT_EQ( 1.0f, A(0,1) );
852 }
853
854 void OutputArray_create1(OutputArray m) { m.create(1, 2, CV_32S); }
855 void OutputArray_create2(OutputArray m) { m.create(1, 3, CV_32F); }
856
857 TEST(Core_IOArray, submat_create)
858 {
859     Mat1f A = Mat1f::zeros(2,2);
860
861     EXPECT_THROW( OutputArray_create1(A.row(0)), cv::Exception );
862     EXPECT_THROW( OutputArray_create2(A.row(0)), cv::Exception );
863 }
864
865 TEST(Core_Mat, reshape_1942)
866 {
867     cv::Mat A = (cv::Mat_<float>(2,3) << 3.4884074, 1.4159607, 0.78737736,  2.3456569, -0.88010466, 0.3009364);
868     int cn = 0;
869     ASSERT_NO_THROW(
870         cv::Mat_<float> M = A.reshape(3);
871         cn = M.channels();
872     );
873     ASSERT_EQ(1, cn);
874 }