Overloaded PCA constructor and ( ) operator to implement Feature#2287 - PCA that...
[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         double retainedVariance = 0.95;
301         Mat rPoints(sz, CV_32FC1), rTestPoints(sz, CV_32FC1);
302         RNG& rng = ts->get_rng();
303
304         rng.fill( rPoints, RNG::UNIFORM, Scalar::all(0.0), Scalar::all(1.0) );
305         rng.fill( rTestPoints, RNG::UNIFORM, Scalar::all(0.0), Scalar::all(1.0) );
306
307         PCA rPCA( rPoints, Mat(), CV_PCA_DATA_AS_ROW, maxComponents ), cPCA;
308
309         // 1. check C++ PCA & ROW
310         Mat rPrjTestPoints = rPCA.project( rTestPoints );
311         Mat rBackPrjTestPoints = rPCA.backProject( rPrjTestPoints );
312
313         Mat avg(1, sz.width, CV_32FC1 );
314         reduce( rPoints, avg, 0, CV_REDUCE_AVG );
315         Mat Q = rPoints - repeat( avg, rPoints.rows, 1 ), Qt = Q.t(), eval, evec;
316         Q = Qt * Q;
317         Q = Q /(float)rPoints.rows;
318
319         eigen( Q, eval, evec );
320         /*SVD svd(Q);
321          evec = svd.vt;
322          eval = svd.w;*/
323
324         Mat subEval( maxComponents, 1, eval.type(), eval.data ),
325         subEvec( maxComponents, evec.cols, evec.type(), evec.data );
326
327     #ifdef CHECK_C
328         Mat prjTestPoints, backPrjTestPoints, cPoints = rPoints.t(), cTestPoints = rTestPoints.t();
329         CvMat _points, _testPoints, _avg, _eval, _evec, _prjTestPoints, _backPrjTestPoints;
330     #endif
331
332         // check eigen()
333         double eigenEps = 1e-6;
334         double err;
335         for(int i = 0; i < Q.rows; i++ )
336         {
337             Mat v = evec.row(i).t();
338             Mat Qv = Q * v;
339
340             Mat lv = eval.at<float>(i,0) * v;
341             err = norm( Qv, lv );
342             if( err > eigenEps )
343             {
344                 ts->printf( cvtest::TS::LOG, "bad accuracy of eigen(); err = %f\n", err );
345                 ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
346                 return;
347             }
348         }
349         // check pca eigenvalues
350         evalEps = 1e-6, evecEps = 1e-3;
351         err = norm( rPCA.eigenvalues, subEval );
352         if( err > evalEps )
353         {
354             ts->printf( cvtest::TS::LOG, "pca.eigenvalues is incorrect (CV_PCA_DATA_AS_ROW); err = %f\n", err );
355             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
356             return;
357         }
358         // check pca eigenvectors
359         for(int i = 0; i < subEvec.rows; i++)
360         {
361             Mat r0 = rPCA.eigenvectors.row(i);
362             Mat r1 = subEvec.row(i);
363             err = norm( r0, r1, CV_L2 );
364             if( err > evecEps )
365             {
366                 r1 *= -1;
367                 double err2 = norm(r0, r1, CV_L2);
368                 if( err2 > evecEps )
369                 {
370                     Mat tmp;
371                     absdiff(rPCA.eigenvectors, subEvec, tmp);
372                     double mval = 0; Point mloc;
373                     minMaxLoc(tmp, 0, &mval, 0, &mloc);
374
375                     ts->printf( cvtest::TS::LOG, "pca.eigenvectors is incorrect (CV_PCA_DATA_AS_ROW); err = %f\n", err );
376                     ts->printf( cvtest::TS::LOG, "max diff is %g at (i=%d, j=%d) (%g vs %g)\n",
377                                mval, mloc.y, mloc.x, rPCA.eigenvectors.at<float>(mloc.y, mloc.x),
378                                subEvec.at<float>(mloc.y, mloc.x));
379                     ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
380                     return;
381                 }
382             }
383         }
384
385         prjEps = 1.265, backPrjEps = 1.265;
386         for( int i = 0; i < rTestPoints.rows; i++ )
387         {
388             // check pca project
389             Mat subEvec_t = subEvec.t();
390             Mat prj = rTestPoints.row(i) - avg; prj *= subEvec_t;
391             err = norm(rPrjTestPoints.row(i), prj, CV_RELATIVE_L2);
392             if( err > prjEps )
393             {
394                 ts->printf( cvtest::TS::LOG, "bad accuracy of project() (CV_PCA_DATA_AS_ROW); err = %f\n", err );
395                 ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
396                 return;
397             }
398             // check pca backProject
399             Mat backPrj = rPrjTestPoints.row(i) * subEvec + avg;
400             err = norm( rBackPrjTestPoints.row(i), backPrj, CV_RELATIVE_L2 );
401             if( err > backPrjEps )
402             {
403                 ts->printf( cvtest::TS::LOG, "bad accuracy of backProject() (CV_PCA_DATA_AS_ROW); err = %f\n", err );
404                 ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
405                 return;
406             }
407         }
408
409         // 2. check C++ PCA & COL
410         cPCA( rPoints.t(), Mat(), CV_PCA_DATA_AS_COL, maxComponents );
411         diffPrjEps = 1, diffBackPrjEps = 1;
412         Mat ocvPrjTestPoints = cPCA.project(rTestPoints.t());
413         err = norm(cv::abs(ocvPrjTestPoints), cv::abs(rPrjTestPoints.t()), CV_RELATIVE_L2 );
414         if( err > diffPrjEps )
415         {
416             ts->printf( cvtest::TS::LOG, "bad accuracy of project() (CV_PCA_DATA_AS_COL); err = %f\n", err );
417             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
418             return;
419         }
420         err = norm(cPCA.backProject(ocvPrjTestPoints), rBackPrjTestPoints.t(), CV_RELATIVE_L2 );
421         if( err > diffBackPrjEps )
422         {
423             ts->printf( cvtest::TS::LOG, "bad accuracy of backProject() (CV_PCA_DATA_AS_COL); err = %f\n", err );
424             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
425             return;
426         }
427         
428         // 3. check C++ PCA w/retainedVariance
429         cPCA( rPoints.t(), Mat(), CV_PCA_DATA_AS_COL, retainedVariance );
430         diffPrjEps = 1, diffBackPrjEps = 1;
431         Mat rvPrjTestPoints = cPCA.project(rTestPoints.t()); 
432         
433         if( cPCA.eigenvectors.rows > maxComponents)
434             err = norm(cv::abs(rvPrjTestPoints.rowRange(0,maxComponents)), cv::abs(rPrjTestPoints.t()), CV_RELATIVE_L2 );
435         else
436             err = norm(cv::abs(rvPrjTestPoints), cv::abs(rPrjTestPoints.colRange(0,cPCA.eigenvectors.rows).t()), CV_RELATIVE_L2 );
437           
438         if( err > diffPrjEps )
439         {
440             ts->printf( cvtest::TS::LOG, "bad accuracy of project() (CV_PCA_DATA_AS_COL); retainedVariance=0.95; err = %f\n", err );
441             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
442             return;
443         }
444         err = norm(cPCA.backProject(rvPrjTestPoints), rBackPrjTestPoints.t(), CV_RELATIVE_L2 );
445         if( err > diffBackPrjEps )
446         {
447             ts->printf( cvtest::TS::LOG, "bad accuracy of backProject() (CV_PCA_DATA_AS_COL); retainedVariance=0.95; err = %f\n", err );
448             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
449             return;
450         }
451         
452     #ifdef CHECK_C
453         // 4. check C PCA & ROW
454         _points = rPoints;
455         _testPoints = rTestPoints;
456         _avg = avg;
457         _eval = eval;
458         _evec = evec;
459         prjTestPoints.create(rTestPoints.rows, maxComponents, rTestPoints.type() );
460         backPrjTestPoints.create(rPoints.size(), rPoints.type() );
461         _prjTestPoints = prjTestPoints;
462         _backPrjTestPoints = backPrjTestPoints;
463
464         cvCalcPCA( &_points, &_avg, &_eval, &_evec, CV_PCA_DATA_AS_ROW );
465         cvProjectPCA( &_testPoints, &_avg, &_evec, &_prjTestPoints );
466         cvBackProjectPCA( &_prjTestPoints, &_avg, &_evec, &_backPrjTestPoints );
467
468         err = norm(prjTestPoints, rPrjTestPoints, CV_RELATIVE_L2);
469         if( err > diffPrjEps )
470         {
471             ts->printf( cvtest::TS::LOG, "bad accuracy of cvProjectPCA() (CV_PCA_DATA_AS_ROW); err = %f\n", err );
472             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
473             return;
474         }
475         err = norm(backPrjTestPoints, rBackPrjTestPoints, CV_RELATIVE_L2);
476         if( err > diffBackPrjEps )
477         {
478             ts->printf( cvtest::TS::LOG, "bad accuracy of cvBackProjectPCA() (CV_PCA_DATA_AS_ROW); err = %f\n", err );
479             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
480             return;
481         }
482
483         // 5. check C PCA & COL
484         _points = cPoints;
485         _testPoints = cTestPoints;
486         avg = avg.t(); _avg = avg;
487         eval = eval.t(); _eval = eval;
488         evec = evec.t(); _evec = evec;
489         prjTestPoints = prjTestPoints.t(); _prjTestPoints = prjTestPoints;
490         backPrjTestPoints = backPrjTestPoints.t(); _backPrjTestPoints = backPrjTestPoints;
491
492         cvCalcPCA( &_points, &_avg, &_eval, &_evec, CV_PCA_DATA_AS_COL );
493         cvProjectPCA( &_testPoints, &_avg, &_evec, &_prjTestPoints );
494         cvBackProjectPCA( &_prjTestPoints, &_avg, &_evec, &_backPrjTestPoints );
495
496         err = norm(cv::abs(prjTestPoints), cv::abs(rPrjTestPoints.t()), CV_RELATIVE_L2 );
497         if( err > diffPrjEps )
498         {
499             ts->printf( cvtest::TS::LOG, "bad accuracy of cvProjectPCA() (CV_PCA_DATA_AS_COL); err = %f\n", err );
500             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
501             return;
502         }
503         err = norm(backPrjTestPoints, rBackPrjTestPoints.t(), CV_RELATIVE_L2);
504         if( err > diffBackPrjEps )
505         {
506             ts->printf( cvtest::TS::LOG, "bad accuracy of cvBackProjectPCA() (CV_PCA_DATA_AS_COL); err = %f\n", err );
507             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
508             return;
509         }
510     #endif
511     }
512 };
513
514 class Core_ArrayOpTest : public cvtest::BaseTest
515 {
516 public:
517     Core_ArrayOpTest();
518     ~Core_ArrayOpTest();
519 protected:
520     void run(int);
521 };
522
523
524 Core_ArrayOpTest::Core_ArrayOpTest()
525 {
526 }
527 Core_ArrayOpTest::~Core_ArrayOpTest() {}
528
529 static string idx2string(const int* idx, int dims)
530 {
531     char buf[256];
532     char* ptr = buf;
533     for( int k = 0; k < dims; k++ )
534     {
535         sprintf(ptr, "%4d ", idx[k]);
536         ptr += strlen(ptr);
537     }
538     ptr[-1] = '\0';
539     return string(buf);
540 }
541
542 static const int* string2idx(const string& s, int* idx, int dims)
543 {
544     const char* ptr = s.c_str();
545     for( int k = 0; k < dims; k++ )
546     {
547         int n = 0;
548         sscanf(ptr, "%d%n", idx + k, &n);
549         ptr += n;
550     }
551     return idx;
552 }
553
554 static double getValue(SparseMat& M, const int* idx, RNG& rng)
555 {
556     int d = M.dims();
557     size_t hv = 0, *phv = 0;
558     if( (unsigned)rng % 2 )
559     {
560         hv = d == 2 ? M.hash(idx[0], idx[1]) :
561         d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx);
562         phv = &hv;
563     }
564
565     const uchar* ptr = d == 2 ? M.ptr(idx[0], idx[1], false, phv) :
566     d == 3 ? M.ptr(idx[0], idx[1], idx[2], false, phv) :
567     M.ptr(idx, false, phv);
568     return !ptr ? 0 : M.type() == CV_32F ? *(float*)ptr : M.type() == CV_64F ? *(double*)ptr : 0;
569 }
570
571 static double getValue(const CvSparseMat* M, const int* idx)
572 {
573     int type = 0;
574     const uchar* ptr = cvPtrND(M, idx, &type, 0);
575     return !ptr ? 0 : type == CV_32F ? *(float*)ptr : type == CV_64F ? *(double*)ptr : 0;
576 }
577
578 static void eraseValue(SparseMat& M, const int* idx, RNG& rng)
579 {
580     int d = M.dims();
581     size_t hv = 0, *phv = 0;
582     if( (unsigned)rng % 2 )
583     {
584         hv = d == 2 ? M.hash(idx[0], idx[1]) :
585         d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx);
586         phv = &hv;
587     }
588
589     if( d == 2 )
590         M.erase(idx[0], idx[1], phv);
591     else if( d == 3 )
592         M.erase(idx[0], idx[1], idx[2], phv);
593     else
594         M.erase(idx, phv);
595 }
596
597 static void eraseValue(CvSparseMat* M, const int* idx)
598 {
599     cvClearND(M, idx);
600 }
601
602 static void setValue(SparseMat& M, const int* idx, double value, RNG& rng)
603 {
604     int d = M.dims();
605     size_t hv = 0, *phv = 0;
606     if( (unsigned)rng % 2 )
607     {
608         hv = d == 2 ? M.hash(idx[0], idx[1]) :
609         d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx);
610         phv = &hv;
611     }
612
613     uchar* ptr = d == 2 ? M.ptr(idx[0], idx[1], true, phv) :
614     d == 3 ? M.ptr(idx[0], idx[1], idx[2], true, phv) :
615     M.ptr(idx, true, phv);
616     if( M.type() == CV_32F )
617         *(float*)ptr = (float)value;
618     else if( M.type() == CV_64F )
619         *(double*)ptr = value;
620     else
621         CV_Error(CV_StsUnsupportedFormat, "");
622 }
623
624 void Core_ArrayOpTest::run( int /* start_from */)
625 {
626     int errcount = 0;
627
628     // dense matrix operations
629     {
630         int sz3[] = {5, 10, 15};
631         MatND A(3, sz3, CV_32F), B(3, sz3, CV_16SC4);
632         CvMatND matA = A, matB = B;
633         RNG rng;
634         rng.fill(A, CV_RAND_UNI, Scalar::all(-10), Scalar::all(10));
635         rng.fill(B, CV_RAND_UNI, Scalar::all(-10), Scalar::all(10));
636
637         int idx0[] = {3,4,5}, idx1[] = {0, 9, 7};
638         float val0 = 130;
639         Scalar val1(-1000, 30, 3, 8);
640         cvSetRealND(&matA, idx0, val0);
641         cvSetReal3D(&matA, idx1[0], idx1[1], idx1[2], -val0);
642         cvSetND(&matB, idx0, val1);
643         cvSet3D(&matB, idx1[0], idx1[1], idx1[2], -val1);
644         Ptr<CvMatND> matC = cvCloneMatND(&matB);
645
646         if( A.at<float>(idx0[0], idx0[1], idx0[2]) != val0 ||
647            A.at<float>(idx1[0], idx1[1], idx1[2]) != -val0 ||
648            cvGetReal3D(&matA, idx0[0], idx0[1], idx0[2]) != val0 ||
649            cvGetRealND(&matA, idx1) != -val0 ||
650
651            Scalar(B.at<Vec4s>(idx0[0], idx0[1], idx0[2])) != val1 ||
652            Scalar(B.at<Vec4s>(idx1[0], idx1[1], idx1[2])) != -val1 ||
653            Scalar(cvGet3D(matC, idx0[0], idx0[1], idx0[2])) != val1 ||
654            Scalar(cvGetND(matC, idx1)) != -val1 )
655         {
656             ts->printf(cvtest::TS::LOG, "one of cvSetReal3D, cvSetRealND, cvSet3D, cvSetND "
657                        "or the corresponding *Get* functions is not correct\n");
658             errcount++;
659         }
660     }
661
662     RNG rng;
663     const int MAX_DIM = 5, MAX_DIM_SZ = 10;
664     // sparse matrix operations
665     for( int si = 0; si < 10; si++ )
666     {
667         int depth = (unsigned)rng % 2 == 0 ? CV_32F : CV_64F;
668         int dims = ((unsigned)rng % MAX_DIM) + 1;
669         int i, k, size[MAX_DIM]={0}, idx[MAX_DIM]={0};
670         vector<string> all_idxs;
671         vector<double> all_vals;
672         vector<double> all_vals2;
673         string sidx, min_sidx, max_sidx;
674         double min_val=0, max_val=0;
675
676         int p = 1;
677         for( k = 0; k < dims; k++ )
678         {
679             size[k] = ((unsigned)rng % MAX_DIM_SZ) + 1;
680             p *= size[k];
681         }
682         SparseMat M( dims, size, depth );
683         map<string, double> M0;
684
685         int nz0 = (unsigned)rng % max(p/5,10);
686         nz0 = min(max(nz0, 1), p);
687         all_vals.resize(nz0);
688         all_vals2.resize(nz0);
689         Mat_<double> _all_vals(all_vals), _all_vals2(all_vals2);
690         rng.fill(_all_vals, CV_RAND_UNI, Scalar(-1000), Scalar(1000));
691         if( depth == CV_32F )
692         {
693             Mat _all_vals_f;
694             _all_vals.convertTo(_all_vals_f, CV_32F);
695             _all_vals_f.convertTo(_all_vals, CV_64F);
696         }
697         _all_vals.convertTo(_all_vals2, _all_vals2.type(), 2);
698         if( depth == CV_32F )
699         {
700             Mat _all_vals2_f;
701             _all_vals2.convertTo(_all_vals2_f, CV_32F);
702             _all_vals2_f.convertTo(_all_vals2, CV_64F);
703         }
704
705         minMaxLoc(_all_vals, &min_val, &max_val);
706         double _norm0 = norm(_all_vals, CV_C);
707         double _norm1 = norm(_all_vals, CV_L1);
708         double _norm2 = norm(_all_vals, CV_L2);
709
710         for( i = 0; i < nz0; i++ )
711         {
712             for(;;)
713             {
714                 for( k = 0; k < dims; k++ )
715                     idx[k] = (unsigned)rng % size[k];
716                 sidx = idx2string(idx, dims);
717                 if( M0.count(sidx) == 0 )
718                     break;
719             }
720             all_idxs.push_back(sidx);
721             M0[sidx] = all_vals[i];
722             if( all_vals[i] == min_val )
723                 min_sidx = sidx;
724             if( all_vals[i] == max_val )
725                 max_sidx = sidx;
726             setValue(M, idx, all_vals[i], rng);
727             double v = getValue(M, idx, rng);
728             if( v != all_vals[i] )
729             {
730                 ts->printf(cvtest::TS::LOG, "%d. immediately after SparseMat[%s]=%.20g the current value is %.20g\n",
731                            i, sidx.c_str(), all_vals[i], v);
732                 errcount++;
733                 break;
734             }
735         }
736
737         Ptr<CvSparseMat> M2 = (CvSparseMat*)M;
738         MatND Md;
739         M.copyTo(Md);
740         SparseMat M3; SparseMat(Md).convertTo(M3, Md.type(), 2);
741
742         int nz1 = (int)M.nzcount(), nz2 = (int)M3.nzcount();
743         double norm0 = norm(M, CV_C);
744         double norm1 = norm(M, CV_L1);
745         double norm2 = norm(M, CV_L2);
746         double eps = depth == CV_32F ? FLT_EPSILON*100 : DBL_EPSILON*1000;
747
748         if( nz1 != nz0 || nz2 != nz0)
749         {
750             errcount++;
751             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",
752                        si, nz1, nz2, nz0 );
753             break;
754         }
755
756         if( fabs(norm0 - _norm0) > fabs(_norm0)*eps ||
757            fabs(norm1 - _norm1) > fabs(_norm1)*eps ||
758            fabs(norm2 - _norm2) > fabs(_norm2)*eps )
759         {
760             errcount++;
761             ts->printf(cvtest::TS::LOG, "%d: The norms are different: %.20g/%.20g/%.20g vs %.20g/%.20g/%.20g\n",
762                        si, norm0, norm1, norm2, _norm0, _norm1, _norm2 );
763             break;
764         }
765
766         int n = (unsigned)rng % max(p/5,10);
767         n = min(max(n, 1), p) + nz0;
768
769         for( i = 0; i < n; i++ )
770         {
771             double val1, val2, val3, val0;
772             if(i < nz0)
773             {
774                 sidx = all_idxs[i];
775                 string2idx(sidx, idx, dims);
776                 val0 = all_vals[i];
777             }
778             else
779             {
780                 for( k = 0; k < dims; k++ )
781                     idx[k] = (unsigned)rng % size[k];
782                 sidx = idx2string(idx, dims);
783                 val0 = M0[sidx];
784             }
785             val1 = getValue(M, idx, rng);
786             val2 = getValue(M2, idx);
787             val3 = getValue(M3, idx, rng);
788
789             if( val1 != val0 || val2 != val0 || fabs(val3 - val0*2) > fabs(val0*2)*FLT_EPSILON )
790             {
791                 errcount++;
792                 ts->printf(cvtest::TS::LOG, "SparseMat M[%s] = %g/%g/%g (while it should be %g)\n", sidx.c_str(), val1, val2, val3, val0 );
793                 break;
794             }
795         }
796
797         for( i = 0; i < n; i++ )
798         {
799             double val1, val2;
800             if(i < nz0)
801             {
802                 sidx = all_idxs[i];
803                 string2idx(sidx, idx, dims);
804             }
805             else
806             {
807                 for( k = 0; k < dims; k++ )
808                     idx[k] = (unsigned)rng % size[k];
809                 sidx = idx2string(idx, dims);
810             }
811             eraseValue(M, idx, rng);
812             eraseValue(M2, idx);
813             val1 = getValue(M, idx, rng);
814             val2 = getValue(M2, idx);
815             if( val1 != 0 || val2 != 0 )
816             {
817                 errcount++;
818                 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 );
819                 break;
820             }
821         }
822
823         int nz = (int)M.nzcount();
824         if( nz != 0 )
825         {
826             errcount++;
827             ts->printf(cvtest::TS::LOG, "The number of non-zero elements after removing all the elements = %d (while it should be 0)\n", nz );
828             break;
829         }
830
831         int idx1[MAX_DIM], idx2[MAX_DIM];
832         double val1 = 0, val2 = 0;
833         M3 = SparseMat(Md);
834         minMaxLoc(M3, &val1, &val2, idx1, idx2);
835         string s1 = idx2string(idx1, dims), s2 = idx2string(idx2, dims);
836         if( val1 != min_val || val2 != max_val || s1 != min_sidx || s2 != max_sidx )
837         {
838             errcount++;
839             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"
840                        "(%g, %g, %s, %s) vs (%g, %g, %s, %s)\n", si, val1, val2, s1.c_str(), s2.c_str(),
841                        min_val, max_val, min_sidx.c_str(), max_sidx.c_str());
842             break;
843         }
844
845         minMaxIdx(Md, &val1, &val2, idx1, idx2);
846         s1 = idx2string(idx1, dims), s2 = idx2string(idx2, dims);
847         if( (min_val < 0 && (val1 != min_val || s1 != min_sidx)) ||
848            (max_val > 0 && (val2 != max_val || s2 != max_sidx)) )
849         {
850             errcount++;
851             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"
852                        "(%g, %g, %s, %s) vs (%g, %g, %s, %s)\n", si, val1, val2, s1.c_str(), s2.c_str(),
853                        min_val, max_val, min_sidx.c_str(), max_sidx.c_str());
854             break;
855         }
856     }
857
858     ts->set_failed_test_info(errcount == 0 ? cvtest::TS::OK : cvtest::TS::FAIL_INVALID_OUTPUT);
859 }
860
861 TEST(Core_PCA, accuracy) { Core_PCATest test; test.safe_run(); }
862 TEST(Core_Reduce, accuracy) { Core_ReduceTest test; test.safe_run(); }
863 TEST(Core_Array, basic_operations) { Core_ArrayOpTest test; test.safe_run(); }
864
865
866 TEST(Core_IOArray, submat_assignment)
867 {
868     Mat1f A = Mat1f::zeros(2,2);
869     Mat1f B = Mat1f::ones(1,3);
870
871     EXPECT_THROW( B.colRange(0,3).copyTo(A.row(0)), cv::Exception );
872
873     EXPECT_NO_THROW( B.colRange(0,2).copyTo(A.row(0)) );
874
875     EXPECT_EQ( 1.0f, A(0,0) );
876     EXPECT_EQ( 1.0f, A(0,1) );
877 }
878
879 void OutputArray_create1(OutputArray m) { m.create(1, 2, CV_32S); }
880 void OutputArray_create2(OutputArray m) { m.create(1, 3, CV_32F); }
881
882 TEST(Core_IOArray, submat_create)
883 {
884     Mat1f A = Mat1f::zeros(2,2);
885
886     EXPECT_THROW( OutputArray_create1(A.row(0)), cv::Exception );
887     EXPECT_THROW( OutputArray_create2(A.row(0)), cv::Exception );
888 }
889
890 TEST(Core_Mat, reshape_1942)
891 {
892     cv::Mat A = (cv::Mat_<float>(2,3) << 3.4884074, 1.4159607, 0.78737736,  2.3456569, -0.88010466, 0.3009364);
893     int cn = 0;
894     ASSERT_NO_THROW(
895         cv::Mat_<float> M = A.reshape(3);
896         cn = M.channels();
897     );
898     ASSERT_EQ(1, cn);
899 }