some formal changes (generally adding constness)
[profile/ivi/opencv.git] / modules / imgproc / test / test_filter.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "test_precomp.hpp"
43
44 using namespace cv;
45 using namespace std;
46
47 class CV_FilterBaseTest : public cvtest::ArrayTest
48 {
49 public:
50     CV_FilterBaseTest( bool _fp_kernel );
51
52 protected:
53     int prepare_test_case( int test_case_idx );
54     int read_params( CvFileStorage* fs );
55     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
56     void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
57     CvSize aperture_size;
58     CvPoint anchor;
59     int max_aperture_size;
60     bool fp_kernel;
61     bool inplace;
62     int border;
63 };
64
65
66 CV_FilterBaseTest::CV_FilterBaseTest( bool _fp_kernel ) : fp_kernel(_fp_kernel)
67 {
68     test_array[INPUT].push_back(NULL);
69     test_array[INPUT].push_back(NULL);
70     test_array[OUTPUT].push_back(NULL);
71     test_array[REF_OUTPUT].push_back(NULL);
72     max_aperture_size = 13;
73     inplace = false;
74     aperture_size = cvSize(0,0);
75     anchor = cvPoint(0,0);
76     element_wise_relative_error = false;
77 }
78
79
80 int CV_FilterBaseTest::read_params( CvFileStorage* fs )
81 {
82     int code = cvtest::ArrayTest::read_params( fs );
83     if( code < 0 )
84         return code;
85
86     max_aperture_size = cvReadInt( find_param( fs, "max_aperture_size" ), max_aperture_size );
87     max_aperture_size = cvtest::clipInt( max_aperture_size, 1, 100 );
88
89     return code;
90 }
91
92
93 void CV_FilterBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
94 {
95     cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
96     if( i == INPUT )
97     {
98         if( j == 1 )
99         {
100             if( fp_kernel )
101             {
102                 RNG& rng = ts->get_rng();
103                 double val = exp( cvtest::randReal(rng)*10 - 4 );
104                 low = Scalar::all(-val);
105                 high = Scalar::all(val);
106             }
107             else
108             {
109                 low = Scalar::all(0);
110                 high = Scalar::all(2);
111             }
112         }
113         else if( CV_MAT_DEPTH(type) == CV_16U )
114         {
115             low = Scalar::all(0.);
116             high = Scalar::all(40000.);
117         }
118         else if( CV_MAT_DEPTH(type) == CV_32F )
119         {
120             low = Scalar::all(-10.);
121             high = Scalar::all(10.);
122         }
123     }
124 }
125
126
127 void CV_FilterBaseTest::get_test_array_types_and_sizes( int test_case_idx,
128                                                         vector<vector<Size> >& sizes,
129                                                         vector<vector<int> >& types )
130 {
131     RNG& rng = ts->get_rng();
132     int depth = cvtest::randInt(rng) % CV_32F;
133     int cn = cvtest::randInt(rng) % 3 + 1;
134     cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
135     depth += depth == CV_8S;
136     cn += cn == 2;
137
138     types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn);
139
140     aperture_size.width = cvtest::randInt(rng) % max_aperture_size + 1;
141     aperture_size.height = cvtest::randInt(rng) % max_aperture_size + 1;
142     anchor.x = cvtest::randInt(rng) % aperture_size.width;
143     anchor.y = cvtest::randInt(rng) % aperture_size.height;
144
145     types[INPUT][1] = fp_kernel ? CV_32FC1 : CV_8UC1;
146     sizes[INPUT][1] = aperture_size;
147
148     inplace = cvtest::randInt(rng) % 2 != 0;
149     border = BORDER_REPLICATE;
150 }
151
152
153 int CV_FilterBaseTest::prepare_test_case( int test_case_idx )
154 {
155     int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
156     if( code > 0 )
157     {
158         if( inplace && test_mat[INPUT][0].type() == test_mat[OUTPUT][0].type())
159             cvtest::copy( test_mat[INPUT][0], test_mat[OUTPUT][0] );
160         else
161             inplace = false;
162     }
163     return code;
164 }
165
166
167 /////////////////////////
168
169 class CV_MorphologyBaseTest : public CV_FilterBaseTest
170 {
171 public:
172     CV_MorphologyBaseTest();
173
174 protected:
175     void prepare_to_validation( int test_case_idx );
176     int prepare_test_case( int test_case_idx );
177     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
178     double get_success_error_level( int test_case_idx, int i, int j );
179     int optype, optype_min, optype_max;
180     int shape;
181     IplConvKernel* element;
182 };
183
184
185 CV_MorphologyBaseTest::CV_MorphologyBaseTest() : CV_FilterBaseTest( false )
186 {
187     shape = -1;
188     element = 0;
189     optype = optype_min = optype_max = -1;
190 }
191
192
193 void CV_MorphologyBaseTest::get_test_array_types_and_sizes( int test_case_idx,
194                                                 vector<vector<Size> >& sizes, vector<vector<int> >& types )
195 {
196     RNG& rng = ts->get_rng();
197     CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
198     int depth = cvtest::randInt(rng) % 4;
199     depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : depth == 2 ? CV_16S : CV_32F;
200     int cn = CV_MAT_CN(types[INPUT][0]);
201
202     types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn);
203     shape = cvtest::randInt(rng) % 4;
204     if( shape >= 3 )
205         shape = CV_SHAPE_CUSTOM;
206     else
207         sizes[INPUT][1] = cvSize(0,0);
208     optype = cvtest::randInt(rng) % (optype_max - optype_min + 1) + optype_min;
209 }
210
211
212 double CV_MorphologyBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
213 {
214     return test_mat[INPUT][0].depth() < CV_32F ||
215         (optype == CV_MOP_ERODE || optype == CV_MOP_DILATE ||
216         optype == CV_MOP_OPEN || optype == CV_MOP_CLOSE) ? 0 : 1e-5;
217 }
218
219
220 int CV_MorphologyBaseTest::prepare_test_case( int test_case_idx )
221 {
222     int code = CV_FilterBaseTest::prepare_test_case( test_case_idx );
223     vector<int> eldata;
224
225     if( code <= 0 )
226         return code;
227
228     if( shape == CV_SHAPE_CUSTOM )
229     {
230         eldata.resize(aperture_size.width*aperture_size.height);
231         const uchar* src = test_mat[INPUT][1].data;
232         int srcstep = (int)test_mat[INPUT][1].step;
233         int i, j, nonzero = 0;
234
235         for( i = 0; i < aperture_size.height; i++ )
236         {
237             for( j = 0; j < aperture_size.width; j++ )
238             {
239                 eldata[i*aperture_size.width + j] = src[i*srcstep + j];
240                 nonzero += src[i*srcstep + j] != 0;
241             }
242         }
243
244         if( nonzero == 0 )
245             eldata[anchor.y*aperture_size.width + anchor.x] = 1;
246     }
247
248     cvReleaseStructuringElement( &element );
249     element = cvCreateStructuringElementEx( aperture_size.width, aperture_size.height,
250                                            anchor.x, anchor.y, shape, eldata.empty() ? 0 : &eldata[0] );
251     return code;
252 }
253
254
255 void CV_MorphologyBaseTest::prepare_to_validation( int /*test_case_idx*/ )
256 {
257     Mat& src = test_mat[INPUT][0], &dst = test_mat[REF_OUTPUT][0];
258     Mat _ielement(element->nRows, element->nCols, CV_32S, element->values);
259     Mat _element;
260     _ielement.convertTo(_element, CV_8U);
261     Point _anchor(element->anchorX, element->anchorY);
262     int _border = BORDER_REPLICATE;
263
264     if( optype == CV_MOP_ERODE )
265     {
266         cvtest::erode( src, dst, _element, _anchor, _border );
267     }
268     else if( optype == CV_MOP_DILATE )
269     {
270         cvtest::dilate( src, dst, _element, _anchor, _border );
271     }
272     else
273     {
274         Mat temp;
275         if( optype == CV_MOP_OPEN )
276         {
277             cvtest::erode( src, temp, _element, _anchor, _border );
278             cvtest::dilate( temp, dst, _element, _anchor, _border );
279         }
280         else if( optype == CV_MOP_CLOSE )
281         {
282             cvtest::dilate( src, temp, _element, _anchor, _border );
283             cvtest::erode( temp, dst, _element, _anchor, _border );
284         }
285         else if( optype == CV_MOP_GRADIENT )
286         {
287             cvtest::erode( src, temp, _element, _anchor, _border );
288             cvtest::dilate( src, dst, _element, _anchor, _border );
289             cvtest::add( dst, 1, temp, -1, Scalar::all(0), dst, dst.type() );
290         }
291         else if( optype == CV_MOP_TOPHAT )
292         {
293             cvtest::erode( src, temp, _element, _anchor, _border );
294             cvtest::dilate( temp, dst, _element, _anchor, _border );
295             cvtest::add( src, 1, dst, -1, Scalar::all(0), dst, dst.type() );
296         }
297         else if( optype == CV_MOP_BLACKHAT )
298         {
299             cvtest::dilate( src, temp, _element, _anchor, _border );
300             cvtest::erode( temp, dst, _element, _anchor, _border );
301             cvtest::add( dst, 1, src, -1, Scalar::all(0), dst, dst.type() );
302         }
303         else
304             CV_Error( CV_StsBadArg, "Unknown operation" );
305     }
306
307     cvReleaseStructuringElement( &element );
308 }
309
310
311 /////////////// erode ///////////////
312
313 class CV_ErodeTest : public CV_MorphologyBaseTest
314 {
315 public:
316     CV_ErodeTest();
317 protected:
318     void run_func();
319 };
320
321
322 CV_ErodeTest::CV_ErodeTest()
323 {
324     optype_min = optype_max = CV_MOP_ERODE;
325 }
326
327
328 void CV_ErodeTest::run_func()
329 {
330     cvErode( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0],
331              test_array[OUTPUT][0], element, 1 );
332 }
333
334
335 /////////////// dilate ///////////////
336
337 class CV_DilateTest : public CV_MorphologyBaseTest
338 {
339 public:
340     CV_DilateTest();
341 protected:
342     void run_func();
343 };
344
345
346 CV_DilateTest::CV_DilateTest()
347 {
348     optype_min = optype_max = CV_MOP_DILATE;
349 }
350
351
352 void CV_DilateTest::run_func()
353 {
354     cvDilate( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0],
355              test_array[OUTPUT][0], element, 1 );
356 }
357
358 /////////////// morphEx ///////////////
359
360 class CV_MorphExTest : public CV_MorphologyBaseTest
361 {
362 public:
363     CV_MorphExTest();
364 protected:
365     void run_func();
366 };
367
368
369 CV_MorphExTest::CV_MorphExTest()
370 {
371     optype_min = CV_MOP_ERODE;
372     optype_max = CV_MOP_BLACKHAT;
373 }
374
375
376 void CV_MorphExTest::run_func()
377 {
378     cvMorphologyEx( test_array[inplace ? OUTPUT : INPUT][0],
379              test_array[OUTPUT][0], 0, element, optype, 1 );
380 }
381
382 /////////////// generic filter ///////////////
383
384 class CV_FilterTest : public CV_FilterBaseTest
385 {
386 public:
387     CV_FilterTest();
388
389 protected:
390     void prepare_to_validation( int test_case_idx );
391     void run_func();
392     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
393     double get_success_error_level( int test_case_idx, int i, int j );
394 };
395
396
397 CV_FilterTest::CV_FilterTest() : CV_FilterBaseTest( true )
398 {
399 }
400
401
402 void CV_FilterTest::get_test_array_types_and_sizes( int test_case_idx,
403                                                 vector<vector<Size> >& sizes, vector<vector<int> >& types )
404 {
405     CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
406     RNG& rng = ts->get_rng();
407     int depth = cvtest::randInt(rng)%3;
408     int cn = CV_MAT_CN(types[INPUT][0]);
409     depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : CV_32F;
410     types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn);
411 }
412
413
414 double CV_FilterTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
415 {
416     int depth = test_mat[INPUT][0].depth();
417     return depth <= CV_8S ? 2 : depth <= CV_32S ? 32 :
418            depth == CV_32F ? 1e-4 : 1e-10;
419 }
420
421
422 void CV_FilterTest::run_func()
423 {
424     CvMat kernel = test_mat[INPUT][1];
425     cvFilter2D( test_array[inplace ? OUTPUT : INPUT][0],
426                 test_array[OUTPUT][0], &kernel, anchor );
427 }
428
429
430 void CV_FilterTest::prepare_to_validation( int /*test_case_idx*/ )
431 {
432     cvtest::filter2D( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].type(),
433                       test_mat[INPUT][1], anchor, 0, BORDER_REPLICATE );
434 }
435
436
437 ////////////////////////
438
439 class CV_DerivBaseTest : public CV_FilterBaseTest
440 {
441 public:
442     CV_DerivBaseTest();
443 protected:
444     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
445     double get_success_error_level( int test_case_idx, int i, int j );
446     int _aperture_size;
447 };
448
449
450 CV_DerivBaseTest::CV_DerivBaseTest() : CV_FilterBaseTest( true )
451 {
452     max_aperture_size = 7;
453 }
454
455
456 void CV_DerivBaseTest::get_test_array_types_and_sizes( int test_case_idx,
457                                                 vector<vector<Size> >& sizes, vector<vector<int> >& types )
458 {
459     RNG& rng = ts->get_rng();
460     CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
461     int depth = cvtest::randInt(rng) % 2;
462     depth = depth == 0 ? CV_8U : CV_32F;
463     types[INPUT][0] = CV_MAKETYPE(depth,1);
464     types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth==CV_8U?CV_16S:CV_32F,1);
465     _aperture_size = (cvtest::randInt(rng)%5)*2 - 1;
466     sizes[INPUT][1] = aperture_size = cvSize(_aperture_size, _aperture_size);
467 }
468
469
470 double CV_DerivBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
471 {
472     int depth = test_mat[INPUT][0].depth();
473     return depth <= CV_8S ? 2 : 5e-4;
474 }
475
476
477 /////////////// sobel ///////////////
478
479 class CV_SobelTest : public CV_DerivBaseTest
480 {
481 public:
482     CV_SobelTest();
483
484 protected:
485     void prepare_to_validation( int test_case_idx );
486     void run_func();
487     void get_test_array_types_and_sizes( int test_case_idx,
488         vector<vector<Size> >& sizes, vector<vector<int> >& types );
489     int dx, dy, origin;
490 };
491
492
493 CV_SobelTest::CV_SobelTest() {}
494
495
496 void CV_SobelTest::get_test_array_types_and_sizes( int test_case_idx,
497                                                    vector<vector<Size> >& sizes,
498                                                    vector<vector<int> >& types )
499 {
500     RNG& rng = ts->get_rng();
501     CV_DerivBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
502     int max_d = _aperture_size > 0 ? 2 : 1;
503     origin = cvtest::randInt(rng) % 2;
504     dx = cvtest::randInt(rng) % (max_d + 1);
505     dy = cvtest::randInt(rng) % (max_d + 1 - dx);
506     if( dx == 0 && dy == 0 )
507         dx = 1;
508     if( cvtest::randInt(rng) % 2 )
509     {
510         int t;
511         CV_SWAP( dx, dy, t );
512     }
513
514     if( _aperture_size < 0 )
515         aperture_size = cvSize(3, 3);
516     else if( _aperture_size == 1 )
517     {
518         if( dx == 0 )
519             aperture_size = cvSize(1, 3);
520         else if( dy == 0 )
521             aperture_size = cvSize(3, 1);
522         else
523         {
524             _aperture_size = 3;
525             aperture_size = cvSize(3, 3);
526         }
527     }
528     else
529         aperture_size = cvSize(_aperture_size, _aperture_size);
530
531     sizes[INPUT][1] = aperture_size;
532     anchor.x = aperture_size.width / 2;
533     anchor.y = aperture_size.height / 2;
534 }
535
536
537 void CV_SobelTest::run_func()
538 {
539     cvSobel( test_array[inplace ? OUTPUT : INPUT][0],
540              test_array[OUTPUT][0], dx, dy, _aperture_size );
541     /*cv::Sobel( test_mat[inplace ? OUTPUT : INPUT][0],
542                test_mat[OUTPUT][0], test_mat[OUTPUT][0].depth(),
543                dx, dy, _aperture_size, 1, 0, border );*/
544 }
545
546
547 void CV_SobelTest::prepare_to_validation( int /*test_case_idx*/ )
548 {
549     Mat kernel = cvtest::calcSobelKernel2D( dx, dy, _aperture_size, 0 );
550     cvtest::filter2D( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].depth(),
551                       kernel, anchor, 0, BORDER_REPLICATE);
552 }
553
554
555 /////////////// laplace ///////////////
556
557 class CV_LaplaceTest : public CV_DerivBaseTest
558 {
559 public:
560     CV_LaplaceTest();
561
562 protected:
563     int prepare_test_case( int test_case_idx );
564     void prepare_to_validation( int test_case_idx );
565     void run_func();
566     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
567 };
568
569
570 CV_LaplaceTest::CV_LaplaceTest()
571 {
572 }
573
574
575 void CV_LaplaceTest::get_test_array_types_and_sizes( int test_case_idx,
576                                                 vector<vector<Size> >& sizes, vector<vector<int> >& types )
577 {
578     CV_DerivBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
579     if( _aperture_size <= 1 )
580     {
581         if( _aperture_size < 0 )
582             _aperture_size = 1;
583         aperture_size = cvSize(3, 3);
584     }
585     else
586         aperture_size = cvSize(_aperture_size, _aperture_size);
587
588     sizes[INPUT][1] = aperture_size;
589     anchor.x = aperture_size.width / 2;
590     anchor.y = aperture_size.height / 2;
591 }
592
593
594 void CV_LaplaceTest::run_func()
595 {
596     cvLaplace( test_array[inplace ? OUTPUT : INPUT][0],
597                test_array[OUTPUT][0], _aperture_size );
598 }
599
600
601 int CV_LaplaceTest::prepare_test_case( int test_case_idx )
602 {
603     int code = CV_DerivBaseTest::prepare_test_case( test_case_idx );
604     return _aperture_size < 0 ? 0 : code;
605 }
606
607
608 void CV_LaplaceTest::prepare_to_validation( int /*test_case_idx*/ )
609 {
610     Mat kernel = cvtest::calcLaplaceKernel2D( _aperture_size );
611     cvtest::filter2D( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].depth(),
612                       kernel, anchor, 0, BORDER_REPLICATE );
613 }
614
615
616 ////////////////////////////////////////////////////////////
617
618 class CV_SmoothBaseTest : public CV_FilterBaseTest
619 {
620 public:
621     CV_SmoothBaseTest();
622
623 protected:
624     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
625     double get_success_error_level( int test_case_idx, int i, int j );
626     const char* smooth_type;
627 };
628
629
630 CV_SmoothBaseTest::CV_SmoothBaseTest() : CV_FilterBaseTest( true )
631 {
632     smooth_type = "";
633 }
634
635
636 void CV_SmoothBaseTest::get_test_array_types_and_sizes( int test_case_idx,
637                                                 vector<vector<Size> >& sizes, vector<vector<int> >& types )
638 {
639     RNG& rng = ts->get_rng();
640     CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
641     int depth = cvtest::randInt(rng) % 2;
642     int cn = CV_MAT_CN(types[INPUT][0]);
643     depth = depth == 0 ? CV_8U : CV_32F;
644     types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth,cn);
645     anchor.x = cvtest::randInt(rng)%(max_aperture_size/2+1);
646     anchor.y = cvtest::randInt(rng)%(max_aperture_size/2+1);
647     aperture_size.width = anchor.x*2 + 1;
648     aperture_size.height = anchor.y*2 + 1;
649     sizes[INPUT][1] = aperture_size;
650 }
651
652
653 double CV_SmoothBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
654 {
655     int depth = test_mat[INPUT][0].depth();
656     return depth <= CV_8S ? 1 : 1e-5;
657 }
658
659
660 /////////////// blur ///////////////
661
662 class CV_BlurTest : public CV_SmoothBaseTest
663 {
664 public:
665     CV_BlurTest();
666
667 protected:
668     int prepare_test_case( int test_case_idx );
669     void prepare_to_validation( int test_case_idx );
670     void run_func();
671     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
672     bool normalize;
673 };
674
675
676 CV_BlurTest::CV_BlurTest()
677 {
678 }
679
680
681 void CV_BlurTest::get_test_array_types_and_sizes( int test_case_idx,
682                                                 vector<vector<Size> >& sizes, vector<vector<int> >& types )
683 {
684     RNG& rng = ts->get_rng();
685     CV_SmoothBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
686     int depth = cvtest::randInt(rng) % 4;
687     int cn = (cvtest::randInt(rng) % 4) + 1;
688     depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : depth == 2 ? CV_16S : CV_32F;
689     types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][0] = CV_MAKETYPE(depth, cn);
690     normalize = cvtest::randInt(rng) % 2 != 0;
691     if( !normalize )
692     {
693         types[INPUT][0] = CV_MAKETYPE(depth, 1);
694         types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth==CV_8U?CV_16S:CV_32F,1);
695     }
696 }
697
698
699 void CV_BlurTest::run_func()
700 {
701     cvSmooth( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0],
702               test_array[OUTPUT][0], normalize ? CV_BLUR : CV_BLUR_NO_SCALE,
703               aperture_size.width, aperture_size.height );
704 }
705
706
707 int CV_BlurTest::prepare_test_case( int test_case_idx )
708 {
709     int code = CV_SmoothBaseTest::prepare_test_case( test_case_idx );
710     return code > 0 && !normalize && test_mat[INPUT][0].channels() > 1 ? 0 : code;
711 }
712
713
714 void CV_BlurTest::prepare_to_validation( int /*test_case_idx*/ )
715 {
716     Mat kernel(aperture_size, CV_64F);
717     kernel.setTo(Scalar::all(normalize ? 1./(aperture_size.width*aperture_size.height) : 1.));
718     cvtest::filter2D( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].depth(),
719                       kernel, anchor, 0, BORDER_REPLICATE );
720 }
721
722
723 /////////////// gaussian ///////////////
724
725 class CV_GaussianBlurTest : public CV_SmoothBaseTest
726 {
727 public:
728     CV_GaussianBlurTest();
729
730 protected:
731     void prepare_to_validation( int test_case_idx );
732     void run_func();
733     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
734     double get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ );
735     double sigma;
736     int param1, param2;
737 };
738
739
740 CV_GaussianBlurTest::CV_GaussianBlurTest() : CV_SmoothBaseTest()
741 {
742     sigma = 0.;
743     smooth_type = "Gaussian";
744 }
745
746
747 double CV_GaussianBlurTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
748 {
749     int depth = test_mat[INPUT][0].depth();
750     return depth <= CV_8S ? 8 : 1e-5;
751 }
752
753
754 void CV_GaussianBlurTest::get_test_array_types_and_sizes( int test_case_idx,
755                                                 vector<vector<Size> >& sizes, vector<vector<int> >& types )
756 {
757     RNG& rng = ts->get_rng();
758     int kernel_case = cvtest::randInt(rng) % 2;
759     CV_SmoothBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
760     anchor = cvPoint(aperture_size.width/2,aperture_size.height/2);
761
762     sigma = exp(cvtest::randReal(rng)*5-2);
763     param1 = aperture_size.width;
764     param2 = aperture_size.height;
765
766     if( kernel_case == 0 )
767         sigma = 0.;
768 }
769
770 void CV_GaussianBlurTest::run_func()
771 {
772     cvSmooth( test_array[inplace ? OUTPUT : INPUT][0],
773               test_array[OUTPUT][0], CV_GAUSSIAN,
774               param1, param2, sigma, sigma );
775 }
776
777
778 // !!! Copied from cvSmooth, if the code is changed in cvSmooth,
779 // make sure to update this one too.
780 #define SMALL_GAUSSIAN_SIZE 7
781 static void
782 calcGaussianKernel( int n, double sigma, vector<float>& kernel )
783 {
784     static const float small_gaussian_tab[][SMALL_GAUSSIAN_SIZE] =
785     {
786         {1.f},
787         {0.25f, 0.5f, 0.25f},
788         {0.0625f, 0.25f, 0.375f, 0.25f, 0.0625f},
789         {0.03125, 0.109375, 0.21875, 0.28125, 0.21875, 0.109375, 0.03125}
790     };
791
792     kernel.resize(n);
793     if( n <= SMALL_GAUSSIAN_SIZE && sigma <= 0 )
794     {
795         assert( n%2 == 1 );
796         memcpy( &kernel[0], small_gaussian_tab[n>>1], n*sizeof(kernel[0]));
797     }
798     else
799     {
800         double sigmaX = sigma > 0 ? sigma : (n/2 - 1)*0.3 + 0.8;
801         double scale2X = -0.5/(sigmaX*sigmaX);
802         double sum = 1.;
803         int i;
804         sum = kernel[n/2] = 1.f;
805
806         for( i = 1; i <= n/2; i++ )
807         {
808             kernel[n/2+i] = kernel[n/2-i] = (float)exp(scale2X*i*i);
809             sum += kernel[n/2+i]*2;
810         }
811
812         sum = 1./sum;
813         for( i = 0; i <= n/2; i++ )
814             kernel[n/2+i] = kernel[n/2-i] = (float)(kernel[n/2+i]*sum);
815     }
816 }
817
818
819 static Mat calcGaussianKernel2D( Size ksize, double sigma )
820 {
821     vector<float> kx, ky;
822     Mat kernel(ksize, CV_32F);
823
824     calcGaussianKernel( kernel.cols, sigma, kx );
825     calcGaussianKernel( kernel.rows, sigma, ky );
826
827     for( int i = 0; i < kernel.rows; i++ )
828         for( int j = 0; j < kernel.cols; j++ )
829             kernel.at<float>(i, j) = kx[j]*ky[i];
830     return kernel;
831 }
832
833
834 void CV_GaussianBlurTest::prepare_to_validation( int /*test_case_idx*/ )
835 {
836     Mat kernel = calcGaussianKernel2D( aperture_size, sigma );
837     cvtest::filter2D( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].depth(),
838                       kernel, anchor, 0, border & ~BORDER_ISOLATED );
839 }
840
841
842 /////////////// median ///////////////
843
844 class CV_MedianBlurTest : public CV_SmoothBaseTest
845 {
846 public:
847     CV_MedianBlurTest();
848
849 protected:
850     void prepare_to_validation( int test_case_idx );
851     double get_success_error_level( int test_case_idx, int i, int j );
852     void run_func();
853     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
854 };
855
856
857 CV_MedianBlurTest::CV_MedianBlurTest()
858 {
859     smooth_type = "Median";
860 }
861
862
863 void CV_MedianBlurTest::get_test_array_types_and_sizes( int test_case_idx,
864                                                 vector<vector<Size> >& sizes, vector<vector<int> >& types )
865 {
866     CV_SmoothBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
867     int depth = CV_8U;
868     int cn = CV_MAT_CN(types[INPUT][0]);
869     types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth,cn);
870     types[INPUT][1] = CV_MAKETYPE(depth,1);
871
872     aperture_size.height = aperture_size.width;
873     anchor.x = anchor.y = aperture_size.width / 2;
874     sizes[INPUT][1] = cvSize(aperture_size.width,aperture_size.height);
875
876     sizes[OUTPUT][0] = sizes[INPUT][0];
877     sizes[REF_OUTPUT][0] = sizes[INPUT][0];
878
879     inplace = false;
880     border = BORDER_REPLICATE | BORDER_ISOLATED;
881 }
882
883
884 double CV_MedianBlurTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
885 {
886     return 0;
887 }
888
889
890 void CV_MedianBlurTest::run_func()
891 {
892     cvSmooth( test_array[INPUT][0], test_array[OUTPUT][0],
893               CV_MEDIAN, aperture_size.width );
894 }
895
896
897 struct median_pair
898 {
899     int col;
900     int val;
901     median_pair() { }
902     median_pair( int _col, int _val ) : col(_col), val(_val) { }
903 };
904
905
906 static void test_medianFilter( const Mat& src, Mat& dst, int m )
907 {
908     int i, j, k, l, m2 = m*m, n;
909     vector<int> col_buf(m+1);
910     vector<median_pair> _buf0(m*m+1), _buf1(m*m+1);
911     median_pair *buf0 = &_buf0[0], *buf1 = &_buf1[0];
912     int step = (int)(src.step/src.elemSize());
913
914     assert( src.rows == dst.rows + m - 1 && src.cols == dst.cols + m - 1 &&
915             src.type() == dst.type() && src.type() == CV_8UC1 );
916
917     for( i = 0; i < dst.rows; i++ )
918     {
919         uchar* dst1 = dst.ptr<uchar>(i);
920         for( k = 0; k < m; k++ )
921         {
922             const uchar* src1 = src.ptr<uchar>(i+k);
923             for( j = 0; j < m-1; j++ )
924                 *buf0++ = median_pair(j, src1[j]);
925         }
926
927         n = m2 - m;
928         buf0 -= n;
929         for( k = n-1; k > 0; k-- )
930         {
931             int f = 0;
932             for( j = 0; j < k; j++ )
933             {
934                 if( buf0[j].val > buf0[j+1].val )
935                 {
936                     median_pair t;
937                     CV_SWAP( buf0[j], buf0[j+1], t );
938                     f = 1;
939                 }
940             }
941             if( !f )
942                 break;
943         }
944
945         for( j = 0; j < dst.cols; j++ )
946         {
947             int ins_col = j + m - 1;
948             int del_col = j - 1;
949             const uchar* src1 = src.ptr<uchar>(i) + ins_col;
950             for( k = 0; k < m; k++, src1 += step )
951             {
952                 col_buf[k] = src1[0];
953                 for( l = k-1; l >= 0; l-- )
954                 {
955                     int t;
956                     if( col_buf[l] < col_buf[l+1] )
957                         break;
958                     CV_SWAP( col_buf[l], col_buf[l+1], t );
959                 }
960             }
961
962             col_buf[m] = INT_MAX;
963
964             for( k = 0, l = 0; k < n; )
965             {
966                 if( buf0[k].col == del_col )
967                     k++;
968                 else if( buf0[k].val < col_buf[l] )
969                     *buf1++ = buf0[k++];
970                 else
971                 {
972                     assert( col_buf[l] < INT_MAX );
973                     *buf1++ = median_pair(ins_col,col_buf[l++]);
974                 }
975             }
976
977             for( ; l < m; l++ )
978                 *buf1++ = median_pair(ins_col,col_buf[l]);
979
980             if( del_col < 0 )
981                 n += m;
982             buf1 -= n;
983             assert( n == m2 );
984             dst1[j] = (uchar)buf1[n/2].val;
985             median_pair* tbuf;
986             CV_SWAP( buf0, buf1, tbuf );
987         }
988     }
989 }
990
991
992 void CV_MedianBlurTest::prepare_to_validation( int /*test_case_idx*/ )
993 {
994     // CV_SmoothBaseTest::prepare_to_validation( test_case_idx );
995     const Mat& src0 = test_mat[INPUT][0];
996     Mat& dst0 = test_mat[REF_OUTPUT][0];
997     int i, cn = src0.channels();
998     int m = aperture_size.width;
999     Mat src(src0.rows + m - 1, src0.cols + m - 1, src0.depth());
1000     Mat dst;
1001     if( cn == 1 )
1002         dst = dst0;
1003     else
1004         dst.create(src0.size(), src0.depth());
1005
1006     for( i = 0; i < cn; i++ )
1007     {
1008         Mat ptr = src0;
1009         if( cn > 1 )
1010         {
1011             cvtest::extract( src0, dst, i );
1012             ptr = dst;
1013         }
1014         cvtest::copyMakeBorder( ptr, src, m/2, m/2, m/2, m/2, border & ~BORDER_ISOLATED );
1015         test_medianFilter( src, dst, m );
1016         if( cn > 1 )
1017             cvtest::insert( dst, dst0, i );
1018     }
1019 }
1020
1021
1022 /////////////// pyramid tests ///////////////
1023
1024 class CV_PyramidBaseTest : public CV_FilterBaseTest
1025 {
1026 public:
1027     CV_PyramidBaseTest( bool downsample );
1028
1029 protected:
1030     double get_success_error_level( int test_case_idx, int i, int j );
1031     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
1032     bool downsample;
1033     Mat kernel;
1034 };
1035
1036
1037 CV_PyramidBaseTest::CV_PyramidBaseTest( bool _downsample ) : CV_FilterBaseTest(true)
1038 {
1039     static float kdata[] = { 1.f, 4.f, 6.f, 4.f, 1.f };
1040     downsample = _downsample;
1041     Mat kernel1d(1, 5, CV_32F, kdata);
1042     kernel = (kernel1d.t()*kernel1d)*((downsample ? 1 : 4)/256.);
1043 }
1044
1045
1046 double CV_PyramidBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1047 {
1048     int depth = test_mat[INPUT][0].depth();
1049     return depth < CV_32F ? 1 : 1e-5;
1050 }
1051
1052
1053 void CV_PyramidBaseTest::get_test_array_types_and_sizes( int test_case_idx,
1054                                                          vector<vector<Size> >& sizes,
1055                                                          vector<vector<int> >& types )
1056 {
1057     const int channels[] = {1, 3, 4};
1058     const int depthes[] = {CV_8U, CV_16S, CV_16U, CV_32F};
1059
1060     RNG& rng = ts->get_rng();
1061     CvSize sz;
1062     CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1063
1064     int depth = depthes[cvtest::randInt(rng) % (sizeof(depthes)/sizeof(depthes[0]))];
1065     int cn = channels[cvtest::randInt(rng) % (sizeof(channels)/sizeof(channels[0]))];
1066
1067     aperture_size = cvSize(5,5);
1068     anchor = cvPoint(aperture_size.width/2, aperture_size.height/2);
1069
1070     types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn);
1071
1072     sz.width = MAX( sizes[INPUT][0].width/2, 1 );
1073     sz.height = MAX( sizes[INPUT][0].height/2, 1 );
1074
1075     if( downsample )
1076     {
1077         sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sz;
1078         sz.width *= 2;
1079         sz.height *= 2;
1080         sizes[INPUT][0] = sz;
1081     }
1082     else
1083     {
1084         sizes[INPUT][0] = sz;
1085         sz.width *= 2;
1086         sz.height *= 2;
1087         sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sz;
1088     }
1089
1090     sizes[INPUT][1] = aperture_size;
1091     inplace = false;
1092 }
1093
1094
1095 /////// pyrdown ////////
1096
1097 class CV_PyramidDownTest : public CV_PyramidBaseTest
1098 {
1099 public:
1100     CV_PyramidDownTest();
1101
1102 protected:
1103     void run_func();
1104     void prepare_to_validation( int );
1105 };
1106
1107
1108 CV_PyramidDownTest::CV_PyramidDownTest() : CV_PyramidBaseTest( true )
1109 {
1110 }
1111
1112
1113 void CV_PyramidDownTest::run_func()
1114 {
1115     cvPyrDown( test_array[INPUT][0], test_array[OUTPUT][0], CV_GAUSSIAN_5x5 );
1116 }
1117
1118
1119 void CV_PyramidDownTest::prepare_to_validation( int /*test_case_idx*/ )
1120 {
1121     Mat& src = test_mat[INPUT][0], &dst = test_mat[REF_OUTPUT][0];
1122     Mat temp;
1123     cvtest::filter2D(src, temp, src.depth(),
1124                      kernel, Point(kernel.cols/2, kernel.rows/2),
1125                      0, BORDER_REFLECT_101);
1126
1127     size_t elem_size = temp.elemSize();
1128     size_t ncols = dst.cols*elem_size;
1129
1130     for( int i = 0; i < dst.rows; i++ )
1131     {
1132         const uchar* src_row = temp.ptr(i*2);
1133         uchar* dst_row = dst.ptr(i);
1134
1135         for( size_t j = 0; j < ncols; j += elem_size )
1136         {
1137             for( size_t k = 0; k < elem_size; k++ )
1138                 dst_row[j+k] = src_row[j*2+k];
1139         }
1140     }
1141 }
1142
1143
1144 /////// pyrup ////////
1145
1146 class CV_PyramidUpTest : public CV_PyramidBaseTest
1147 {
1148 public:
1149     CV_PyramidUpTest();
1150
1151 protected:
1152     void run_func();
1153     void prepare_to_validation( int );
1154 };
1155
1156
1157 CV_PyramidUpTest::CV_PyramidUpTest() : CV_PyramidBaseTest( false )
1158 {
1159 }
1160
1161
1162 void CV_PyramidUpTest::run_func()
1163 {
1164     cvPyrUp( test_array[INPUT][0], test_array[OUTPUT][0], CV_GAUSSIAN_5x5 );
1165 }
1166
1167
1168 void CV_PyramidUpTest::prepare_to_validation( int /*test_case_idx*/ )
1169 {
1170     Mat& src = test_mat[INPUT][0], &dst = test_mat[REF_OUTPUT][0];
1171     Mat temp(dst.size(), dst.type());
1172
1173     size_t elem_size = src.elemSize();
1174     size_t ncols = src.cols*elem_size;
1175
1176     for( int i = 0; i < src.rows; i++ )
1177     {
1178         const uchar* src_row = src.ptr(i);
1179         uchar* dst_row = temp.ptr(i*2);
1180
1181         if( i*2 + 1 < temp.rows )
1182             memset( temp.ptr(i*2+1), 0, temp.cols*elem_size );
1183         for( size_t j = 0; j < ncols; j += elem_size )
1184         {
1185             for( size_t k = 0; k < elem_size; k++ )
1186             {
1187                 dst_row[j*2+k] = src_row[j+k];
1188                 dst_row[j*2+k+elem_size] = 0;
1189             }
1190         }
1191     }
1192
1193     cvtest::filter2D(temp, dst, dst.depth(),
1194                      kernel, Point(kernel.cols/2, kernel.rows/2),
1195                      0, BORDER_REFLECT_101);
1196 }
1197
1198
1199 //////////////////////// feature selection //////////////////////////
1200
1201 class CV_FeatureSelBaseTest : public cvtest::ArrayTest
1202 {
1203 public:
1204     CV_FeatureSelBaseTest( int width_factor );
1205
1206 protected:
1207     int read_params( CvFileStorage* fs );
1208     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
1209     void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
1210     double get_success_error_level( int test_case_idx, int i, int j );
1211     int aperture_size, block_size;
1212     int max_aperture_size;
1213     int max_block_size;
1214     int width_factor;
1215 };
1216
1217
1218 CV_FeatureSelBaseTest::CV_FeatureSelBaseTest( int _width_factor )
1219 {
1220     max_aperture_size = 7;
1221     max_block_size = 21;
1222     // 1 input, 1 output, temp arrays are allocated in the reference functions
1223     test_array[INPUT].push_back(NULL);
1224     test_array[OUTPUT].push_back(NULL);
1225     test_array[REF_OUTPUT].push_back(NULL);
1226     element_wise_relative_error = false;
1227     width_factor = _width_factor;
1228 }
1229
1230
1231 int CV_FeatureSelBaseTest::read_params( CvFileStorage* fs )
1232 {
1233     int code = cvtest::BaseTest::read_params( fs );
1234     if( code < 0 )
1235         return code;
1236
1237     max_aperture_size = cvReadInt( find_param( fs, "max_aperture_size" ), max_aperture_size );
1238     max_aperture_size = cvtest::clipInt( max_aperture_size, 1, 9 );
1239     max_block_size = cvReadInt( find_param( fs, "max_block_size" ), max_block_size );
1240     max_block_size = cvtest::clipInt( max_aperture_size, 1, 100 );
1241
1242     return code;
1243 }
1244
1245
1246 double CV_FeatureSelBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
1247 {
1248     int depth = test_mat[INPUT][0].depth();
1249     return depth <= CV_8S ? 3e-2 : depth == CV_32F ? 1e-3 : 1e-10;
1250 }
1251
1252
1253 void CV_FeatureSelBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
1254 {
1255     cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
1256     if( i == INPUT && CV_MAT_DEPTH(type) == CV_32F )
1257     {
1258         low = Scalar::all(-10.);
1259         high = Scalar::all(10.);
1260     }
1261 }
1262
1263
1264 void CV_FeatureSelBaseTest::get_test_array_types_and_sizes( int test_case_idx,
1265                                                 vector<vector<Size> >& sizes, vector<vector<int> >& types )
1266 {
1267     RNG& rng = ts->get_rng();
1268     cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1269     int depth = cvtest::randInt(rng) % 2, asz;
1270
1271     depth = depth == 0 ? CV_8U : CV_32F;
1272     types[INPUT][0] = depth;
1273     types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_32FC1;
1274
1275     aperture_size = (cvtest::randInt(rng) % (max_aperture_size+2) - 1) | 1;
1276     if( aperture_size == 1 )
1277         aperture_size = 3;
1278     if( depth == CV_8U )
1279         aperture_size = MIN( aperture_size, 5 );
1280     block_size = (cvtest::randInt(rng) % max_block_size + 1) | 1;
1281     if( block_size <= 3 )
1282         block_size = 3;
1283     asz = aperture_size > 0 ? aperture_size : 3;
1284
1285     sizes[INPUT][0].width = MAX( sizes[INPUT][0].width, asz + block_size );
1286     sizes[INPUT][0].height = MAX( sizes[INPUT][0].height, asz + block_size );
1287     sizes[OUTPUT][0].height = sizes[REF_OUTPUT][0].height = sizes[INPUT][0].height;
1288     sizes[OUTPUT][0].width = sizes[REF_OUTPUT][0].width = sizes[INPUT][0].width*width_factor;
1289 }
1290
1291
1292 static void
1293 test_cornerEigenValsVecs( const Mat& src, Mat& eigenv, Mat& ocv_eigenv,
1294                           int block_size, int _aperture_size, int mode )
1295 {
1296     int i, j;
1297     int aperture_size = _aperture_size < 0 ? 3 : _aperture_size;
1298     Point anchor( aperture_size/2, aperture_size/2 );
1299
1300     CV_Assert( src.type() == CV_8UC1 || src.type() == CV_32FC1 );
1301     CV_Assert( eigenv.type() == CV_32FC1 );
1302     CV_Assert( src.rows == eigenv.rows &&
1303               ((mode > 0 && src.cols == eigenv.cols) ||
1304               (mode == 0 && src.cols*6 == eigenv.cols)) );
1305
1306     int type = src.type();
1307     int ftype = CV_32FC1;
1308     double kernel_scale = type != ftype ? 1./255 : 1;
1309
1310     Mat dx2, dy2, dxdy(src.size(), CV_32F), kernel;
1311
1312     kernel = cvtest::calcSobelKernel2D( 1, 0, _aperture_size );
1313     cvtest::filter2D( src, dx2, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE );
1314     kernel = cvtest::calcSobelKernel2D( 0, 1, _aperture_size );
1315     cvtest::filter2D( src, dy2, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE );
1316
1317     double denom = (1 << (aperture_size-1))*block_size;
1318     denom = denom * denom;
1319     if( _aperture_size < 0 )
1320         denom *= 4;
1321     denom = 1./denom;
1322
1323     for( i = 0; i < src.rows; i++ )
1324     {
1325         float* dxdyp = dxdy.ptr<float>(i);
1326         float* dx2p = dx2.ptr<float>(i);
1327         float* dy2p = dy2.ptr<float>(i);
1328
1329         for( j = 0; j < src.cols; j++ )
1330         {
1331             double xval = dx2p[j], yval = dy2p[j];
1332             dxdyp[j] = (float)(xval*yval*denom);
1333             dx2p[j] = (float)(xval*xval*denom);
1334             dy2p[j] = (float)(yval*yval*denom);
1335         }
1336     }
1337
1338     kernel = Mat::ones(block_size, block_size, CV_32F);
1339     anchor = Point(block_size/2, block_size/2);
1340
1341     cvtest::filter2D( dx2, dx2, ftype, kernel, anchor, 0, BORDER_REPLICATE );
1342     cvtest::filter2D( dy2, dy2, ftype, kernel, anchor, 0, BORDER_REPLICATE );
1343     cvtest::filter2D( dxdy, dxdy, ftype, kernel, anchor, 0, BORDER_REPLICATE );
1344
1345     if( mode == 0 )
1346     {
1347         for( i = 0; i < src.rows; i++ )
1348         {
1349             float* eigenvp = eigenv.ptr<float>(i);
1350             float* ocv_eigenvp = ocv_eigenv.ptr<float>(i);
1351             const float* dxdyp = dxdy.ptr<float>(i);
1352             const float* dx2p = dx2.ptr<float>(i);
1353             const float* dy2p = dy2.ptr<float>(i);
1354
1355             for( j = 0; j < src.cols; j++ )
1356             {
1357                 double a = dx2p[j], b = dxdyp[j], c = dy2p[j];
1358                 double d = sqrt((a-c)*(a-c) + 4*b*b);
1359                 double l1 = 0.5*(a + c + d);
1360                 double l2 = 0.5*(a + c - d);
1361                 double x1, y1, x2, y2, s;
1362
1363                 if( fabs(a - l1) + fabs(b) >= 1e-3 )
1364                     x1 = b, y1 = l1 - a;
1365                 else
1366                     x1 = l1 - c, y1 = b;
1367                 s = 1./(sqrt(x1*x1+y1*y1)+DBL_EPSILON);
1368                 x1 *= s; y1 *= s;
1369
1370                 if( fabs(a - l2) + fabs(b) >= 1e-3 )
1371                     x2 = b, y2 = l2 - a;
1372                 else
1373                     x2 = l2 - c, y2 = b;
1374                 s = 1./(sqrt(x2*x2+y2*y2)+DBL_EPSILON);
1375                 x2 *= s; y2 *= s;
1376
1377                 /* the orientation of eigen vectors might be inversed relative to OpenCV function,
1378                    which is normal */
1379                 if( (fabs(x1) >= fabs(y1) && ocv_eigenvp[j*6+2]*x1 < 0) ||
1380                     (fabs(x1) < fabs(y1) && ocv_eigenvp[j*6+3]*y1 < 0) )
1381                     x1 = -x1, y1 = -y1;
1382
1383                 if( (fabs(x2) >= fabs(y2) && ocv_eigenvp[j*6+4]*x2 < 0) ||
1384                     (fabs(x2) < fabs(y2) && ocv_eigenvp[j*6+5]*y2 < 0) )
1385                     x2 = -x2, y2 = -y2;
1386
1387                 eigenvp[j*6] = (float)l1;
1388                 eigenvp[j*6+1] = (float)l2;
1389                 eigenvp[j*6+2] = (float)x1;
1390                 eigenvp[j*6+3] = (float)y1;
1391                 eigenvp[j*6+4] = (float)x2;
1392                 eigenvp[j*6+5] = (float)y2;
1393             }
1394         }
1395     }
1396     else if( mode == 1 )
1397     {
1398         for( i = 0; i < src.rows; i++ )
1399         {
1400             float* eigenvp = eigenv.ptr<float>(i);
1401             const float* dxdyp = dxdy.ptr<float>(i);
1402             const float* dx2p = dx2.ptr<float>(i);
1403             const float* dy2p = dy2.ptr<float>(i);
1404
1405             for( j = 0; j < src.cols; j++ )
1406             {
1407                 double a = dx2p[j], b = dxdyp[j], c = dy2p[j];
1408                 double d = sqrt((a-c)*(a-c) + 4*b*b);
1409                 eigenvp[j] = (float)(0.5*(a + c - d));
1410             }
1411         }
1412     }
1413 }
1414
1415
1416 // min eigenval
1417 class CV_MinEigenValTest : public CV_FeatureSelBaseTest
1418 {
1419 public:
1420     CV_MinEigenValTest();
1421
1422 protected:
1423     void run_func();
1424     void prepare_to_validation( int );
1425 };
1426
1427
1428 CV_MinEigenValTest::CV_MinEigenValTest() : CV_FeatureSelBaseTest( 1 )
1429 {
1430 }
1431
1432
1433 void CV_MinEigenValTest::run_func()
1434 {
1435     cvCornerMinEigenVal( test_array[INPUT][0], test_array[OUTPUT][0],
1436                          block_size, aperture_size );
1437 }
1438
1439
1440 void CV_MinEigenValTest::prepare_to_validation( int /*test_case_idx*/ )
1441 {
1442     test_cornerEigenValsVecs( test_mat[INPUT][0], test_mat[REF_OUTPUT][0],
1443                     test_mat[OUTPUT][0], block_size, aperture_size, 1 );
1444 }
1445
1446
1447 // eigenval's & vec's
1448 class CV_EigenValVecTest : public CV_FeatureSelBaseTest
1449 {
1450 public:
1451     CV_EigenValVecTest();
1452
1453 protected:
1454     void run_func();
1455     void prepare_to_validation( int );
1456 };
1457
1458
1459 CV_EigenValVecTest::CV_EigenValVecTest() : CV_FeatureSelBaseTest( 6 )
1460 {
1461 }
1462
1463
1464 void CV_EigenValVecTest::run_func()
1465 {
1466     cvCornerEigenValsAndVecs( test_array[INPUT][0], test_array[OUTPUT][0],
1467                               block_size, aperture_size );
1468 }
1469
1470
1471 void CV_EigenValVecTest::prepare_to_validation( int /*test_case_idx*/ )
1472 {
1473     test_cornerEigenValsVecs( test_mat[INPUT][0], test_mat[REF_OUTPUT][0],
1474                     test_mat[OUTPUT][0], block_size, aperture_size, 0 );
1475 }
1476
1477
1478 // precornerdetect
1479 class CV_PreCornerDetectTest : public CV_FeatureSelBaseTest
1480 {
1481 public:
1482     CV_PreCornerDetectTest();
1483
1484 protected:
1485     void run_func();
1486     void prepare_to_validation( int );
1487     int prepare_test_case( int );
1488 };
1489
1490
1491 CV_PreCornerDetectTest::CV_PreCornerDetectTest() : CV_FeatureSelBaseTest( 1 )
1492 {
1493 }
1494
1495
1496 void CV_PreCornerDetectTest::run_func()
1497 {
1498     cvPreCornerDetect( test_array[INPUT][0], test_array[OUTPUT][0], aperture_size );
1499 }
1500
1501
1502 int CV_PreCornerDetectTest::prepare_test_case( int test_case_idx )
1503 {
1504     int code = CV_FeatureSelBaseTest::prepare_test_case( test_case_idx );
1505     if( aperture_size < 0 )
1506         aperture_size = 3;
1507     return code;
1508 }
1509
1510
1511 void CV_PreCornerDetectTest::prepare_to_validation( int /*test_case_idx*/ )
1512 {
1513     /*cvTsCornerEigenValsVecs( test_mat[INPUT][0], test_mat[REF_OUTPUT][0],
1514                              block_size, aperture_size, 0 );*/
1515     const Mat& src = test_mat[INPUT][0];
1516     Mat& dst = test_mat[REF_OUTPUT][0];
1517
1518     int type = src.type(), ftype = CV_32FC1;
1519     Point anchor(aperture_size/2, aperture_size/2);
1520
1521     double kernel_scale = type != ftype ? 1./255 : 1.;
1522
1523     Mat dx, dy, d2x, d2y, dxy, kernel;
1524
1525     kernel = cvtest::calcSobelKernel2D(1, 0, aperture_size);
1526     cvtest::filter2D(src, dx, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE);
1527     kernel = cvtest::calcSobelKernel2D(2, 0, aperture_size);
1528     cvtest::filter2D(src, d2x, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE);
1529     kernel = cvtest::calcSobelKernel2D(0, 1, aperture_size);
1530     cvtest::filter2D(src, dy, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE);
1531     kernel = cvtest::calcSobelKernel2D(0, 2, aperture_size);
1532     cvtest::filter2D(src, d2y, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE);
1533     kernel = cvtest::calcSobelKernel2D(1, 1, aperture_size);
1534     cvtest::filter2D(src, dxy, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE);
1535
1536     double denom = 1 << (aperture_size-1);
1537     denom = denom * denom * denom;
1538     denom = 1./denom;
1539
1540     for( int i = 0; i < src.rows; i++ )
1541     {
1542         const float* _dx = dx.ptr<float>(i);
1543         const float* _dy = dy.ptr<float>(i);
1544         const float* _d2x = d2x.ptr<float>(i);
1545         const float* _d2y = d2y.ptr<float>(i);
1546         const float* _dxy = dxy.ptr<float>(i);
1547         float* corner = dst.ptr<float>(i);
1548
1549         for( int j = 0; j < src.cols; j++ )
1550         {
1551             double x = _dx[j];
1552             double y = _dy[j];
1553
1554             corner[j] = (float)(denom*(x*x*_d2y[j] + y*y*_d2x[j] - 2*x*y*_dxy[j]));
1555         }
1556     }
1557 }
1558
1559
1560 ///////// integral /////////
1561
1562 class CV_IntegralTest : public cvtest::ArrayTest
1563 {
1564 public:
1565     CV_IntegralTest();
1566
1567 protected:
1568     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
1569     void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
1570     double get_success_error_level( int test_case_idx, int i, int j );
1571     void run_func();
1572     void prepare_to_validation( int );
1573
1574     int prepare_test_case( int test_case_idx );
1575 };
1576
1577
1578 CV_IntegralTest::CV_IntegralTest()
1579 {
1580     test_array[INPUT].push_back(NULL);
1581     test_array[OUTPUT].push_back(NULL);
1582     test_array[OUTPUT].push_back(NULL);
1583     test_array[OUTPUT].push_back(NULL);
1584     test_array[REF_OUTPUT].push_back(NULL);
1585     test_array[REF_OUTPUT].push_back(NULL);
1586     test_array[REF_OUTPUT].push_back(NULL);
1587     element_wise_relative_error = true;
1588 }
1589
1590
1591 void CV_IntegralTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
1592 {
1593     cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
1594     int depth = CV_MAT_DEPTH(type);
1595     if( depth == CV_32F )
1596     {
1597         low = Scalar::all(-10.);
1598         high = Scalar::all(10.);
1599     }
1600 }
1601
1602
1603 void CV_IntegralTest::get_test_array_types_and_sizes( int test_case_idx,
1604                                                 vector<vector<Size> >& sizes, vector<vector<int> >& types )
1605 {
1606     RNG& rng = ts->get_rng();
1607     int depth = cvtest::randInt(rng) % 2, sum_depth;
1608     int cn = cvtest::randInt(rng) % 3 + 1;
1609     cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1610     Size sum_size;
1611
1612     depth = depth == 0 ? CV_8U : CV_32F;
1613     cn += cn == 2;
1614     int b = (cvtest::randInt(rng) & 1) != 0;
1615     sum_depth = depth == CV_8U && b ? CV_32S : b ? CV_32F : CV_64F;
1616
1617     types[INPUT][0] = CV_MAKETYPE(depth,cn);
1618     types[OUTPUT][0] = types[REF_OUTPUT][0] =
1619         types[OUTPUT][2] = types[REF_OUTPUT][2] = CV_MAKETYPE(sum_depth, cn);
1620     types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_MAKETYPE(CV_64F, cn);
1621
1622     sum_size.width = sizes[INPUT][0].width + 1;
1623     sum_size.height = sizes[INPUT][0].height + 1;
1624
1625     sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sum_size;
1626     sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] =
1627         sizes[OUTPUT][2] = sizes[REF_OUTPUT][2] = Size(0,0);
1628
1629     if( cvtest::randInt(rng) % 3 > 0 )
1630     {
1631         sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] = sum_size;
1632         if( cvtest::randInt(rng) % 2 > 0 )
1633             sizes[REF_OUTPUT][2] = sizes[OUTPUT][2] = sum_size;
1634     }
1635 }
1636
1637
1638 double CV_IntegralTest::get_success_error_level( int, int i, int j )
1639 {
1640     int depth = test_mat[i][j].depth();
1641     return depth == CV_32S ? 0 : depth == CV_64F ? FLT_EPSILON : 5e-3;
1642 }
1643
1644
1645 int CV_IntegralTest::prepare_test_case( int test_case_idx )
1646 {
1647     int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
1648     return code > 0 && ((test_array[OUTPUT][2] && test_mat[OUTPUT][2].channels() > 1) ||
1649         test_mat[OUTPUT][0].depth() < test_mat[INPUT][0].depth()) ? 0 : code;
1650 }
1651
1652
1653 void CV_IntegralTest::run_func()
1654 {
1655     cvIntegral( test_array[INPUT][0], test_array[OUTPUT][0],
1656                 test_array[OUTPUT][1], test_array[OUTPUT][2] );
1657 }
1658
1659
1660 static void test_integral( const Mat& img, Mat* sum, Mat* sqsum, Mat* tilted )
1661 {
1662     CV_Assert( img.depth() == CV_32F );
1663
1664     sum->create(img.rows+1, img.cols+1, CV_64F);
1665     if( sqsum )
1666         sqsum->create(img.rows+1, img.cols+1, CV_64F);
1667     if( tilted )
1668         tilted->create(img.rows+1, img.cols+1, CV_64F);
1669
1670     const float* data = img.ptr<float>();
1671     double* sdata = sum->ptr<double>();
1672     double* sqdata = sqsum ? sqsum->ptr<double>() : 0;
1673     double* tdata = tilted ? tilted->ptr<double>() : 0;
1674     int step = (int)(img.step/sizeof(data[0]));
1675     int sstep = (int)(sum->step/sizeof(sdata[0]));
1676     int sqstep = sqsum ? (int)(sqsum->step/sizeof(sqdata[0])) : 0;
1677     int tstep = tilted ? (int)(tilted->step/sizeof(tdata[0])) : 0;
1678     Size size = img.size();
1679
1680     memset( sdata, 0, (size.width+1)*sizeof(sdata[0]) );
1681     if( sqsum )
1682         memset( sqdata, 0, (size.width+1)*sizeof(sqdata[0]) );
1683     if( tilted )
1684         memset( tdata, 0, (size.width+1)*sizeof(tdata[0]) );
1685
1686     for( ; size.height--; data += step )
1687     {
1688         double s = 0, sq = 0;
1689         int x;
1690         sdata += sstep;
1691         sqdata += sqstep;
1692         tdata += tstep;
1693
1694         for( x = 0; x <= size.width; x++ )
1695         {
1696             double t = x > 0 ? data[x-1] : 0, ts = t;
1697             s += t;
1698             sq += t*t;
1699
1700             sdata[x] = s + sdata[x - sstep];
1701             if( sqdata )
1702                 sqdata[x] = sq + sqdata[x - sqstep];
1703
1704             if( !tdata )
1705                 continue;
1706
1707             if( x == 0 )
1708                 ts += tdata[-tstep+1];
1709             else
1710             {
1711                 ts += tdata[x-tstep-1];
1712                 if( data > img.ptr<float>() )
1713                 {
1714                     ts += data[x-step-1];
1715                     if( x < size.width )
1716                         ts += tdata[x-tstep+1] - tdata[x-tstep*2];
1717                 }
1718             }
1719
1720             tdata[x] = ts;
1721         }
1722     }
1723 }
1724
1725
1726 void CV_IntegralTest::prepare_to_validation( int /*test_case_idx*/ )
1727 {
1728     Mat& src = test_mat[INPUT][0];
1729     int cn = src.channels();
1730
1731     Mat* sum0 = &test_mat[REF_OUTPUT][0];
1732     Mat* sqsum0 = test_array[REF_OUTPUT][1] ? &test_mat[REF_OUTPUT][1] : 0;
1733     Mat* tsum0 = test_array[REF_OUTPUT][2] ? &test_mat[REF_OUTPUT][2] : 0;
1734
1735     Mat plane, srcf, psum, psqsum, ptsum, psum2, psqsum2, ptsum2;
1736     if( cn == 1 )
1737     {
1738         plane = src;
1739         psum2 = *sum0;
1740         psqsum2 = sqsum0 ? *sqsum0 : Mat();
1741         ptsum2 = tsum0 ? *tsum0 : Mat();
1742     }
1743
1744     for( int i = 0; i < cn; i++ )
1745     {
1746         if( cn > 1 )
1747             cvtest::extract(src, plane, i);
1748         plane.convertTo(srcf, CV_32F);
1749
1750         test_integral( srcf, &psum, sqsum0 ? &psqsum : 0, tsum0 ? &ptsum : 0 );
1751         psum.convertTo(psum2, sum0->depth());
1752         if( sqsum0 )
1753             psqsum.convertTo(psqsum2, sqsum0->depth());
1754         if( tsum0 )
1755             ptsum.convertTo(ptsum2, tsum0->depth());
1756
1757         if( cn > 1 )
1758         {
1759             cvtest::insert(psum2, *sum0, i);
1760             if( sqsum0 )
1761                 cvtest::insert(psqsum2, *sqsum0, i);
1762             if( tsum0 )
1763                 cvtest::insert(ptsum2, *tsum0, i);
1764         }
1765     }
1766 }
1767
1768
1769 ///////////////////////////////////////////////////////////////////////////////////
1770
1771 TEST(Imgproc_Erode, accuracy) { CV_ErodeTest test; test.safe_run(); }
1772 TEST(Imgproc_Dilate, accuracy) { CV_DilateTest test; test.safe_run(); }
1773 TEST(Imgproc_MorphologyEx, accuracy) { CV_MorphExTest test; test.safe_run(); }
1774 TEST(Imgproc_Filter2D, accuracy) { CV_FilterTest test; test.safe_run(); }
1775 TEST(Imgproc_Sobel, accuracy) { CV_SobelTest test; test.safe_run(); }
1776 TEST(Imgproc_Laplace, accuracy) { CV_LaplaceTest test; test.safe_run(); }
1777 TEST(Imgproc_Blur, accuracy) { CV_BlurTest test; test.safe_run(); }
1778 TEST(Imgproc_GaussianBlur, accuracy) { CV_GaussianBlurTest test; test.safe_run(); }
1779 TEST(Imgproc_MedianBlur, accuracy) { CV_MedianBlurTest test; test.safe_run(); }
1780 TEST(Imgproc_PyramidDown, accuracy) { CV_PyramidDownTest test; test.safe_run(); }
1781 TEST(Imgproc_PyramidUp, accuracy) { CV_PyramidUpTest test; test.safe_run(); }
1782 TEST(Imgproc_MinEigenVal, accuracy) { CV_MinEigenValTest test; test.safe_run(); }
1783 TEST(Imgproc_EigenValsVecs, accuracy) { CV_EigenValVecTest test; test.safe_run(); }
1784 TEST(Imgproc_PreCornerDetect, accuracy) { CV_PreCornerDetectTest test; test.safe_run(); }
1785 TEST(Imgproc_Integral, accuracy) { CV_IntegralTest test; test.safe_run(); }
1786
1787 //////////////////////////////////////////////////////////////////////////////////
1788
1789 class CV_FilterSupportedFormatsTest : public cvtest::BaseTest
1790 {
1791 public:
1792     CV_FilterSupportedFormatsTest() {}
1793     ~CV_FilterSupportedFormatsTest() {}
1794 protected:
1795     void run(int)
1796     {
1797         const int depths[][2] =
1798         {
1799             {CV_8U, CV_8U},
1800             {CV_8U, CV_16U},
1801             {CV_8U, CV_16S},
1802             {CV_8U, CV_32F},
1803             {CV_8U, CV_64F},
1804             {CV_16U, CV_16U},
1805             {CV_16U, CV_32F},
1806             {CV_16U, CV_64F},
1807             {CV_16S, CV_16S},
1808             {CV_16S, CV_32F},
1809             {CV_16S, CV_64F},
1810             {CV_32F, CV_32F},
1811             {CV_64F, CV_64F},
1812             {-1, -1}
1813         };
1814
1815         int i = 0;
1816         volatile int fidx = -1;
1817         try
1818         {
1819             // use some "odd" size to do yet another smoke
1820             // testing of the non-SIMD loop tails
1821             Size sz(163, 117);
1822             Mat small_kernel(5, 5, CV_32F), big_kernel(21, 21, CV_32F);
1823             Mat kernelX(11, 1, CV_32F), kernelY(7, 1, CV_32F);
1824             Mat symkernelX(11, 1, CV_32F), symkernelY(7, 1, CV_32F);
1825             randu(small_kernel, -10, 10);
1826             randu(big_kernel, -1, 1);
1827             randu(kernelX, -1, 1);
1828             randu(kernelY, -1, 1);
1829             flip(kernelX, symkernelX, 0);
1830             symkernelX += kernelX;
1831             flip(kernelY, symkernelY, 0);
1832             symkernelY += kernelY;
1833
1834             Mat elem_ellipse = getStructuringElement(MORPH_ELLIPSE, Size(7, 7));
1835             Mat elem_rect = getStructuringElement(MORPH_RECT, Size(7, 7));
1836
1837             for( i = 0; depths[i][0] >= 0; i++ )
1838             {
1839                 int sdepth = depths[i][0];
1840                 int ddepth = depths[i][1];
1841                 Mat src(sz, CV_MAKETYPE(sdepth, 5)), dst;
1842                 randu(src, 0, 100);
1843                 // non-separable filtering with a small kernel
1844                 fidx = 0;
1845                 filter2D(src, dst, ddepth, small_kernel);
1846                 fidx++;
1847                 filter2D(src, dst, ddepth, big_kernel);
1848                 fidx++;
1849                 sepFilter2D(src, dst, ddepth, kernelX, kernelY);
1850                 fidx++;
1851                 sepFilter2D(src, dst, ddepth, symkernelX, symkernelY);
1852                 fidx++;
1853                 Sobel(src, dst, ddepth, 2, 0, 5);
1854                 fidx++;
1855                 Scharr(src, dst, ddepth, 0, 1);
1856                 if( sdepth != ddepth )
1857                     continue;
1858                 fidx++;
1859                 GaussianBlur(src, dst, Size(5, 5), 1.2, 1.2);
1860                 fidx++;
1861                 blur(src, dst, Size(11, 11));
1862                 fidx++;
1863                 morphologyEx(src, dst, MORPH_GRADIENT, elem_ellipse);
1864                 fidx++;
1865                 morphologyEx(src, dst, MORPH_GRADIENT, elem_rect);
1866             }
1867         }
1868         catch(...)
1869         {
1870             ts->printf(cvtest::TS::LOG, "Combination of depths %d => %d in %s is not supported (yet it should be)",
1871                        depths[i][0], depths[i][1],
1872                        fidx == 0 ? "filter2D (small kernel)" :
1873                        fidx == 1 ? "filter2D (large kernel)" :
1874                        fidx == 2 ? "sepFilter2D" :
1875                        fidx == 3 ? "sepFilter2D (symmetrical/asymmetrical kernel)" :
1876                        fidx == 4 ? "Sobel" :
1877                        fidx == 5 ? "Scharr" :
1878                        fidx == 6 ? "GaussianBlur" :
1879                        fidx == 7 ? "blur" :
1880                        fidx == 8 || fidx == 9 ? "morphologyEx" :
1881                        "unknown???");
1882
1883             ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
1884         }
1885     }
1886 };
1887
1888 TEST(Imgproc_Filtering, supportedFormats) { CV_FilterSupportedFormatsTest test; test.safe_run(); }
1889
1890 TEST(Imgproc_Blur, borderTypes)
1891 {
1892     Size kernelSize(3, 3);
1893
1894     /// ksize > src_roi.size()
1895     Mat src(3, 3, CV_8UC1, cv::Scalar::all(255)), dst;
1896     Mat src_roi = src(Rect(1, 1, 1, 1));
1897     src_roi.setTo(cv::Scalar::all(0));
1898
1899     // should work like !BORDER_ISOLATED
1900     blur(src_roi, dst, kernelSize, Point(-1, -1), BORDER_REPLICATE);
1901     EXPECT_EQ(227, dst.at<uchar>(0, 0));
1902
1903     // should work like BORDER_ISOLATED
1904     blur(src_roi, dst, kernelSize, Point(-1, -1), BORDER_REPLICATE | BORDER_ISOLATED);
1905     EXPECT_EQ(0, dst.at<uchar>(0, 0));
1906
1907     /// ksize <= src_roi.size()
1908     src = Mat(5, 5, CV_8UC1, cv::Scalar(255));
1909     src_roi = src(Rect(1, 1, 3, 3));
1910     src_roi.setTo(0);
1911     src.at<uchar>(2, 2) = 255;
1912
1913     // should work like !BORDER_ISOLATED
1914     blur(src_roi, dst, kernelSize, Point(-1, -1), BORDER_REPLICATE);
1915     Mat expected_dst =
1916             (Mat_<uchar>(3, 3) << 170, 113, 170, 113, 28, 113, 170, 113, 170);
1917     EXPECT_EQ(expected_dst.type(), dst.type());
1918     EXPECT_EQ(expected_dst.size(), dst.size());
1919     EXPECT_DOUBLE_EQ(0.0, cvtest::norm(expected_dst, dst, NORM_INF));
1920 }