Update to 2.0.0 tree from current Fremantle build
[opencv] / src / cxcore / cxstat.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 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
19 //
20 //   * Redistribution's of source code must retain the above copyright notice,
21 //     this list of conditions and the following disclaimer.
22 //
23 //   * Redistribution's in binary form must reproduce the above copyright notice,
24 //     this list of conditions and the following disclaimer in the documentation
25 //     and/or other materials provided with the distribution.
26 //
27 //   * The name of the copyright holders may not be used to endorse or promote products
28 //     derived from this software without specific prior written permission.
29 //
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
40 //
41 //M*/
42
43 #include "_cxcore.h"
44
45 namespace cv
46 {
47
48 template<typename T> static inline Scalar rawToScalar(const T& v)
49 {
50     Scalar s;
51     typedef typename DataType<T>::channel_type T1;
52     int i, n = DataType<T>::channels;
53     for( i = 0; i < n; i++ )
54         s.val[i] = ((T1*)&v)[i];
55     return s;
56 }    
57
58 /****************************************************************************************\
59 *                                        sum                                             *
60 \****************************************************************************************/
61
62 template<typename T, typename WT, typename ST, int BLOCK_SIZE>
63 static Scalar sumBlock_( const Mat& srcmat )
64 {
65     assert( DataType<T>::type == srcmat.type() );
66     Size size = getContinuousSize( srcmat );
67     ST s0 = 0;
68     WT s = 0;
69     int y, remaining = BLOCK_SIZE;
70
71     for( y = 0; y < size.height; y++ )
72     {
73         const T* src = (const T*)(srcmat.data + srcmat.step*y);
74         int x = 0;
75         while( x < size.width )
76         {
77             int limit = std::min( remaining, size.width - x );
78             remaining -= limit;
79             limit += x;
80             for( ; x <= limit - 4; x += 4 )
81             {
82                 s += src[x];
83                 s += src[x+1];
84                 s += src[x+2];
85                 s += src[x+3];
86             }
87             for( ; x < limit; x++ )
88                 s += src[x];
89             if( remaining == 0 || (x == size.width && y == size.height-1) )
90             {
91                 s0 += s;
92                 s = 0;
93                 remaining = BLOCK_SIZE;
94             }
95         }
96     }
97     return rawToScalar(s0);
98 }
99
100 template<typename T, typename ST>
101 static Scalar sum_( const Mat& srcmat )
102 {
103     assert( DataType<T>::type == srcmat.type() );
104     Size size = getContinuousSize( srcmat );
105     ST s = 0;
106
107     for( int y = 0; y < size.height; y++ )
108     {
109         const T* src = (const T*)(srcmat.data + srcmat.step*y);
110         int x = 0;
111         for( ; x <= size.width - 4; x += 4 )
112         {
113             s += src[x];
114             s += src[x+1];
115             s += src[x+2];
116             s += src[x+3];
117         }
118         for( ; x < size.width; x++ )
119             s += src[x];
120     }
121     return rawToScalar(s);
122 }
123
124 typedef Scalar (*SumFunc)(const Mat& src);
125
126 Scalar sum( const Mat& m )
127 {
128     static SumFunc tab[]=
129     {
130         sumBlock_<uchar, unsigned, double, 1<<24>, 0,
131         sumBlock_<ushort, unsigned, double, 1<<16>,
132         sumBlock_<short, int, double, 1<<16>,
133         sum_<int, double>,
134         sum_<float, double>,
135         sum_<double, double>, 0,
136
137         sumBlock_<Vec<uchar, 2>, Vec<unsigned, 2>, Vec<double, 2>, 1<<24>, 0,
138         sumBlock_<Vec<ushort, 2>, Vec<unsigned, 2>, Vec<double, 2>, 1<<16>,
139         sumBlock_<Vec<short, 2>, Vec<int, 2>, Vec<double, 2>, 1<<16>,
140         sum_<Vec<int, 2>, Vec<double, 2> >,
141         sum_<Vec<float, 2>, Vec<double, 2> >,
142         sum_<Vec<double, 2>, Vec<double, 2> >, 0,
143
144         sumBlock_<Vec<uchar, 3>, Vec<unsigned, 3>, Vec<double, 3>, 1<<24>, 0,
145         sumBlock_<Vec<ushort, 3>, Vec<unsigned, 3>, Vec<double, 3>, 1<<16>,
146         sumBlock_<Vec<short, 3>, Vec<int, 3>, Vec<double, 3>, 1<<16>,
147         sum_<Vec<int, 3>, Vec<double, 3> >,
148         sum_<Vec<float, 3>, Vec<double, 3> >,
149         sum_<Vec<double, 3>, Vec<double, 3> >, 0,
150
151         sumBlock_<Vec<uchar, 4>, Vec<unsigned, 4>, Vec<double, 4>, 1<<24>, 0,
152         sumBlock_<Vec<ushort, 4>, Vec<unsigned, 4>, Vec<double, 4>, 1<<16>,
153         sumBlock_<Vec<short, 4>, Vec<int, 4>, Vec<double, 4>, 1<<16>,
154         sum_<Vec<int, 4>, Vec<double, 4> >,
155         sum_<Vec<float, 4>, Vec<double, 4> >,
156         sum_<Vec<double, 4>, Vec<double, 4> >, 0
157     };
158
159     Size size = m.size();
160     SumFunc func; 
161
162     CV_Assert( m.channels() <= 4 );
163
164     func = tab[m.type()];
165     CV_Assert( func != 0 );
166
167     return func(m);
168 }
169
170 /****************************************************************************************\
171 *                                     countNonZero                                       *
172 \****************************************************************************************/
173
174 template<typename T>
175 static int countNonZero_( const Mat& srcmat )
176 {
177     //assert( DataType<T>::type == srcmat.type() );
178     const T* src = (const T*)srcmat.data;
179     size_t step = srcmat.step/sizeof(src[0]);
180     Size size = getContinuousSize( srcmat );
181     int nz = 0;
182
183     for( ; size.height--; src += step )
184     {
185         int x = 0;
186         for( ; x <= size.width - 4; x += 4 )
187             nz += (src[x] != 0) + (src[x+1] != 0) + (src[x+2] != 0) + (src[x+3] != 0);
188         for( ; x < size.width; x++ )
189             nz += src[x] != 0;
190     }
191     return nz;
192 }
193
194 typedef int (*CountNonZeroFunc)(const Mat& src);
195
196 int countNonZero( const Mat& m )
197 {
198     static CountNonZeroFunc tab[] =
199     {
200         countNonZero_<uchar>, countNonZero_<uchar>, countNonZero_<ushort>,
201         countNonZero_<ushort>, countNonZero_<int>, countNonZero_<float>,
202         countNonZero_<double>, 0
203     };
204     
205     CountNonZeroFunc func = tab[m.depth()];
206     CV_Assert( m.channels() == 1 && func != 0 );
207     return func(m);
208 }
209
210
211 /****************************************************************************************\
212 *                                         mean                                           *
213 \****************************************************************************************/
214
215 template<typename T, typename WT, typename ST, int BLOCK_SIZE>
216 static Scalar meanBlock_( const Mat& srcmat, const Mat& maskmat )
217 {
218     assert( DataType<T>::type == srcmat.type() &&
219         CV_8U == maskmat.type() && srcmat.size() == maskmat.size() );
220     Size size = getContinuousSize( srcmat, maskmat );
221     ST s0 = 0;
222     WT s = 0;
223     int y, remaining = BLOCK_SIZE, pix = 0;
224
225     for( y = 0; y < size.height; y++ )
226     {
227         const T* src = (const T*)(srcmat.data + srcmat.step*y);
228         const uchar* mask = maskmat.data + maskmat.step*y;
229         int x = 0;
230         while( x < size.width )
231         {
232             int limit = std::min( remaining, size.width - x );
233             remaining -= limit;
234             limit += x;
235             for( ; x < limit; x++ )
236                 if( mask[x] )
237                     s += src[x], pix++;
238             if( remaining == 0 || (x == size.width && y == size.height-1) )
239             {
240                 s0 += s;
241                 s = 0;
242                 remaining = BLOCK_SIZE;
243             }
244         }
245     }
246     return rawToScalar(s0)*(1./std::max(pix, 1));
247 }
248
249
250 template<typename T, typename ST>
251 static Scalar mean_( const Mat& srcmat, const Mat& maskmat )
252 {
253     assert( DataType<T>::type == srcmat.type() &&
254         CV_8U == maskmat.type() && srcmat.size() == maskmat.size() );
255     Size size = getContinuousSize( srcmat, maskmat );
256     ST s = 0;
257     int y, pix = 0;
258
259     for( y = 0; y < size.height; y++ )
260     {
261         const T* src = (const T*)(srcmat.data + srcmat.step*y);
262         const uchar* mask = maskmat.data + maskmat.step*y;
263         for( int x = 0; x < size.width; x++ )
264             if( mask[x] )
265                 s += src[x], pix++;
266     }
267     return rawToScalar(s)*(1./std::max(pix, 1));
268 }
269
270 typedef Scalar (*MeanMaskFunc)(const Mat& src, const Mat& mask);
271
272 Scalar mean(const Mat& m)
273 {
274     return sum(m)*(1./std::max(m.rows*m.cols, 1));
275 }
276
277 Scalar mean( const Mat& m, const Mat& mask )
278 {
279     static MeanMaskFunc tab[]=
280     {
281         meanBlock_<uchar, unsigned, double, 1<<24>, 0,
282         meanBlock_<ushort, unsigned, double, 1<<16>,
283         meanBlock_<short, int, double, 1<<16>,
284         mean_<int, double>,
285         mean_<float, double>,
286         mean_<double, double>, 0,
287
288         meanBlock_<Vec<uchar, 2>, Vec<unsigned, 2>, Vec<double, 2>, 1<<24>, 0,
289         meanBlock_<Vec<ushort, 2>, Vec<unsigned, 2>, Vec<double, 2>, 1<<16>,
290         meanBlock_<Vec<short, 2>, Vec<int, 2>, Vec<double, 2>, 1<<16>,
291         mean_<Vec<int, 2>, Vec<double, 2> >,
292         mean_<Vec<float, 2>, Vec<double, 2> >,
293         mean_<Vec<double, 2>, Vec<double, 2> >, 0,
294
295         meanBlock_<Vec<uchar, 3>, Vec<unsigned, 3>, Vec<double, 3>, 1<<24>, 0,
296         meanBlock_<Vec<ushort, 3>, Vec<unsigned, 3>, Vec<double, 3>, 1<<16>,
297         meanBlock_<Vec<short, 3>, Vec<int, 3>, Vec<double, 3>, 1<<16>,
298         mean_<Vec<int, 3>, Vec<double, 3> >,
299         mean_<Vec<float, 3>, Vec<double, 3> >,
300         mean_<Vec<double, 3>, Vec<double, 3> >, 0,
301
302         meanBlock_<Vec<uchar, 4>, Vec<unsigned, 4>, Vec<double, 4>, 1<<24>, 0,
303         meanBlock_<Vec<ushort, 4>, Vec<unsigned, 4>, Vec<double, 4>, 1<<16>,
304         meanBlock_<Vec<short, 4>, Vec<int, 4>, Vec<double, 4>, 1<<16>,
305         mean_<Vec<int, 4>, Vec<double, 4> >,
306         mean_<Vec<float, 4>, Vec<double, 4> >,
307         mean_<Vec<double, 4>, Vec<double, 4> >, 0
308     };
309     
310     if( !mask.data )
311         return mean(m);
312
313     CV_Assert( m.channels() <= 4 && m.size() == mask.size() && mask.type() == CV_8U );
314
315     MeanMaskFunc func = tab[m.type()];
316     CV_Assert( func != 0 );
317
318     return func( m, mask );
319 }
320
321 /****************************************************************************************\
322 *                                       meanStdDev                                       *
323 \****************************************************************************************/
324
325 template<typename T, typename SqT> struct SqrC1
326 {
327     typedef T type1;
328     typedef SqT rtype;
329     rtype operator()(type1 x) const { return (SqT)x*x; }
330 };
331
332 template<typename T, typename SqT> struct SqrC2
333 {
334     typedef Vec<T, 2> type1;
335     typedef Vec<SqT, 2> rtype;
336     rtype operator()(const type1& x) const { return rtype((SqT)x[0]*x[0], (SqT)x[1]*x[1]); }
337 };
338
339 template<typename T, typename SqT> struct SqrC3
340 {
341     typedef Vec<T, 3> type1;
342     typedef Vec<SqT, 3> rtype;
343     rtype operator()(const type1& x) const
344     { return rtype((SqT)x[0]*x[0], (SqT)x[1]*x[1], (SqT)x[2]*x[2]); }
345 };
346
347 template<typename T, typename SqT> struct SqrC4
348 {
349     typedef Vec<T, 4> type1;
350     typedef Vec<SqT, 4> rtype;
351     rtype operator()(const type1& x) const
352     { return rtype((SqT)x[0]*x[0], (SqT)x[1]*x[1], (SqT)x[2]*x[2], (SqT)x[3]*x[3]); }
353 };
354
355 template<> inline double SqrC1<uchar, double>::operator()(uchar x) const
356 { return CV_SQR_8U(x); }
357
358 template<> inline Vec<double, 2> SqrC2<uchar, double>::operator()(const Vec<uchar, 2>& x) const
359 { return Vec<double, 2>(CV_SQR_8U(x[0]), CV_SQR_8U(x[1])); }
360
361 template<> inline Vec<double, 3> SqrC3<uchar, double>::operator() (const Vec<uchar, 3>& x) const
362 { return Vec<double, 3>(CV_SQR_8U(x[0]), CV_SQR_8U(x[1]), CV_SQR_8U(x[2])); }
363
364 template<> inline Vec<double, 4> SqrC4<uchar, double>::operator() (const Vec<uchar, 4>& x) const
365 { return Vec<double, 4>(CV_SQR_8U(x[0]), CV_SQR_8U(x[1]), CV_SQR_8U(x[2]), CV_SQR_8U(x[3])); }
366
367
368 template<class SqrOp> static void
369 meanStdDev_( const Mat& srcmat, Scalar& _mean, Scalar& _stddev )
370 {
371     SqrOp sqr;
372     typedef typename SqrOp::type1 T;
373     typedef typename SqrOp::rtype ST;
374     typedef typename DataType<ST>::channel_type ST1;
375     
376     assert( DataType<T>::type == srcmat.type() );
377     Size size = getContinuousSize( srcmat );
378     ST s = 0, sq = 0;
379
380     for( int y = 0; y < size.height; y++ )
381     {
382         const T* src = (const T*)(srcmat.data + srcmat.step*y);
383         for( int x = 0; x < size.width; x++ )
384         {
385             T v = src[x];
386             s += v;
387             sq += sqr(v);
388         }
389     }
390
391     _mean = _stddev = Scalar();
392     double scale = 1./std::max(size.width*size.height, 1);
393     for( int i = 0; i < DataType<ST>::channels; i++ )
394     {
395         double t = ((ST1*)&s)[i]*scale;
396         _mean.val[i] = t;
397         _stddev.val[i] = std::sqrt(std::max(((ST1*)&sq)[i]*scale - t*t, 0.));
398     }
399 }
400
401 template<class SqrOp> static void
402 meanStdDevMask_( const Mat& srcmat, const Mat& maskmat,
403                  Scalar& _mean, Scalar& _stddev )
404 {
405     SqrOp sqr;
406     typedef typename SqrOp::type1 T;
407     typedef typename SqrOp::rtype ST;
408     typedef typename DataType<ST>::channel_type ST1;
409
410     assert( DataType<T>::type == srcmat.type() &&
411             CV_8U == maskmat.type() &&
412             srcmat.size() == maskmat.size() );
413     Size size = getContinuousSize( srcmat, maskmat );
414     ST s = 0, sq = 0;
415     int pix = 0;
416
417     for( int y = 0; y < size.height; y++ )
418     {
419         const T* src = (const T*)(srcmat.data + srcmat.step*y);
420         const uchar* mask = maskmat.data + maskmat.step*y;
421         for( int x = 0; x < size.width; x++ )
422             if( mask[x] )
423             {
424                 T v = src[x];
425                 s += v;
426                 sq += sqr(v);
427                 pix++;
428             }
429     }
430     _mean = _stddev = Scalar();
431     double scale = 1./std::max(pix, 1);
432     for( int i = 0; i < DataType<ST>::channels; i++ )
433     {
434         double t = ((ST1*)&s)[i]*scale;
435         _mean.val[i] = t;
436         _stddev.val[i] = std::sqrt(std::max(((ST1*)&sq)[i]*scale - t*t, 0.));
437     }
438 }
439
440 typedef void (*MeanStdDevFunc)(const Mat& src, Scalar& mean, Scalar& stddev);
441
442 typedef void (*MeanStdDevMaskFunc)(const Mat& src, const Mat& mask,
443                                    Scalar& mean, Scalar& stddev);
444
445 void meanStdDev( const Mat& m, Scalar& mean, Scalar& stddev, const Mat& mask )
446 {
447     static MeanStdDevFunc tab[]=
448     {
449         meanStdDev_<SqrC1<uchar, double> >, 0,
450         meanStdDev_<SqrC1<ushort, double> >,
451         meanStdDev_<SqrC1<short, double> >,
452         meanStdDev_<SqrC1<int, double> >,
453         meanStdDev_<SqrC1<float, double> >,
454         meanStdDev_<SqrC1<double, double> >, 0,
455
456         meanStdDev_<SqrC2<uchar, double> >, 0,
457         meanStdDev_<SqrC2<ushort, double> >,
458         meanStdDev_<SqrC2<short, double> >,
459         meanStdDev_<SqrC2<int, double> >,
460         meanStdDev_<SqrC2<float, double> >,
461         meanStdDev_<SqrC2<double, double> >, 0,
462
463         meanStdDev_<SqrC3<uchar, double> >, 0,
464         meanStdDev_<SqrC3<ushort, double> >,
465         meanStdDev_<SqrC3<short, double> >,
466         meanStdDev_<SqrC3<int, double> >,
467         meanStdDev_<SqrC3<float, double> >,
468         meanStdDev_<SqrC3<double, double> >, 0,
469
470         meanStdDev_<SqrC4<uchar, double> >, 0,
471         meanStdDev_<SqrC4<ushort, double> >,
472         meanStdDev_<SqrC4<short, double> >,
473         meanStdDev_<SqrC4<int, double> >,
474         meanStdDev_<SqrC4<float, double> >,
475         meanStdDev_<SqrC4<double, double> >, 0
476     };
477
478     static MeanStdDevMaskFunc mtab[]=
479     {
480         meanStdDevMask_<SqrC1<uchar, double> >, 0,
481         meanStdDevMask_<SqrC1<ushort, double> >,
482         meanStdDevMask_<SqrC1<short, double> >,
483         meanStdDevMask_<SqrC1<int, double> >,
484         meanStdDevMask_<SqrC1<float, double> >,
485         meanStdDevMask_<SqrC1<double, double> >, 0,
486
487         meanStdDevMask_<SqrC2<uchar, double> >, 0,
488         meanStdDevMask_<SqrC2<ushort, double> >,
489         meanStdDevMask_<SqrC2<short, double> >,
490         meanStdDevMask_<SqrC2<int, double> >,
491         meanStdDevMask_<SqrC2<float, double> >,
492         meanStdDevMask_<SqrC2<double, double> >, 0,
493
494         meanStdDevMask_<SqrC3<uchar, double> >, 0,
495         meanStdDevMask_<SqrC3<ushort, double> >,
496         meanStdDevMask_<SqrC3<short, double> >,
497         meanStdDevMask_<SqrC3<int, double> >,
498         meanStdDevMask_<SqrC3<float, double> >,
499         meanStdDevMask_<SqrC3<double, double> >, 0,
500
501         meanStdDevMask_<SqrC4<uchar, double> >, 0,
502         meanStdDevMask_<SqrC4<ushort, double> >,
503         meanStdDevMask_<SqrC4<short, double> >,
504         meanStdDevMask_<SqrC4<int, double> >,
505         meanStdDevMask_<SqrC4<float, double> >,
506         meanStdDevMask_<SqrC4<double, double> >, 0
507     };
508
509     CV_Assert( m.channels() <= 4 );
510     
511     if( !mask.data )
512     {
513         MeanStdDevFunc func = tab[m.type()];
514         CV_Assert( func != 0 );
515         func( m, mean, stddev );
516     }
517     else
518     {
519         MeanStdDevMaskFunc func = mtab[m.type()];
520         CV_Assert( mask.size() == m.size() && mask.type() == CV_8U && func != 0 );
521         func( m, mask, mean, stddev );
522     }
523 }
524
525
526 /****************************************************************************************\
527 *                                       minMaxLoc                                        *
528 \****************************************************************************************/
529
530 template<typename T> static void
531 minMaxIndx_( const Mat& srcmat, double* minVal, double* maxVal, int* minLoc, int* maxLoc )
532 {
533     assert( DataType<T>::type == srcmat.type() );
534     const T* src = (const T*)srcmat.data;
535     size_t step = srcmat.step/sizeof(src[0]);
536     T min_val = src[0], max_val = min_val;
537     int min_loc = 0, max_loc = 0;
538     int x, loc = 0;
539     Size size = getContinuousSize( srcmat );
540
541     for( ; size.height--; src += step, loc += size.width )
542     {
543         for( x = 0; x < size.width; x++ )
544         {
545             T val = src[x];
546             if( val < min_val )
547             {
548                 min_val = val;
549                 min_loc = loc + x;
550             }
551             else if( val > max_val )
552             {
553                 max_val = val;
554                 max_loc = loc + x;
555             }
556         }
557     }
558
559     *minLoc = min_loc;
560     *maxLoc = max_loc;
561     *minVal = min_val;
562     *maxVal = max_val;
563 }
564
565
566 template<typename T> static void
567 minMaxIndxMask_( const Mat& srcmat, const Mat& maskmat,
568     double* minVal, double* maxVal, int* minLoc, int* maxLoc )
569 {
570     assert( DataType<T>::type == srcmat.type() &&
571         CV_8U == maskmat.type() &&
572         srcmat.size() == maskmat.size() );
573     const T* src = (const T*)srcmat.data;
574     const uchar* mask = maskmat.data;
575     size_t step = srcmat.step/sizeof(src[0]);
576     size_t maskstep = maskmat.step;
577     T min_val = 0, max_val = 0;
578     int min_loc = -1, max_loc = -1;
579     int x = 0, y, loc = 0;
580     Size size = getContinuousSize( srcmat, maskmat );
581
582     for( y = 0; y < size.height; y++, src += step, mask += maskstep, loc += size.width )
583     {
584         for( x = 0; x < size.width; x++ )
585             if( mask[x] != 0 )
586             {
587                 min_loc = max_loc = loc + x;
588                 min_val = max_val = src[x];
589                 break;
590             }
591         if( x < size.width )
592             break;
593     }
594
595     for( ; y < size.height; x = 0, y++, src += step, mask += maskstep, loc += size.width )
596     {
597         for( ; x < size.width; x++ )
598         {
599             T val = src[x];
600             int m = mask[x];
601
602             if( val < min_val && m )
603             {
604                 min_val = val;
605                 min_loc = loc + x;
606             }
607             else if( val > max_val && m )
608             {
609                 max_val = val;
610                 max_loc = loc + x;
611             }
612         }
613     }
614
615     *minLoc = min_loc;
616     *maxLoc = max_loc;
617     *minVal = min_val;
618     *maxVal = max_val;
619 }
620
621 typedef void (*MinMaxIndxFunc)(const Mat&, double*, double*, int*, int*);
622
623 typedef void (*MinMaxIndxMaskFunc)(const Mat&, const Mat&,
624                                     double*, double*, int*, int*);
625
626 void minMaxLoc( const Mat& img, double* minVal, double* maxVal,
627                 Point* minLoc, Point* maxLoc, const Mat& mask )
628 {
629     static MinMaxIndxFunc tab[] =
630         {minMaxIndx_<uchar>, 0, minMaxIndx_<ushort>, minMaxIndx_<short>,
631         minMaxIndx_<int>, minMaxIndx_<float>, minMaxIndx_<double>, 0};
632     static MinMaxIndxMaskFunc tabm[] =
633         {minMaxIndxMask_<uchar>, 0, minMaxIndxMask_<ushort>, minMaxIndxMask_<short>,
634         minMaxIndxMask_<int>, minMaxIndxMask_<float>, minMaxIndxMask_<double>, 0};
635
636     int depth = img.depth();
637     double minval=0, maxval=0;
638     int minloc=0, maxloc=0;
639
640     CV_Assert( img.channels() == 1 );
641
642     if( !mask.data )
643     {
644         MinMaxIndxFunc func = tab[depth];
645         CV_Assert( func != 0 );
646         func( img, &minval, &maxval, &minloc, &maxloc );
647     }
648     else
649     {
650         CV_Assert( img.size() == mask.size() && mask.type() == CV_8U );
651         MinMaxIndxMaskFunc func = tabm[depth];
652         CV_Assert( func != 0 );
653         func( img, mask, &minval, &maxval, &minloc, &maxloc );
654     }
655
656     if( minVal )
657         *minVal = minval;
658     if( maxVal )
659         *maxVal = maxval;
660     if( minLoc )
661     {
662         if( minloc >= 0 )
663         {
664             minLoc->y = minloc/img.cols;
665             minLoc->x = minloc - minLoc->y*img.cols;
666         }
667         else
668             minLoc->x = minLoc->y = -1;
669     }
670     if( maxLoc )
671     {
672         if( maxloc >= 0 )
673         {
674             maxLoc->y = maxloc/img.cols;
675             maxLoc->x = maxloc - maxLoc->y*img.cols;
676         }
677         else
678             maxLoc->x = maxLoc->y = -1;
679     }
680 }
681
682 /****************************************************************************************\
683 *                                         norm                                           *
684 \****************************************************************************************/
685
686 template<typename T, typename WT=T> struct OpAbs
687 {
688     typedef T type1;
689     typedef WT rtype;
690     rtype operator()(type1 x) const { return (WT)std::abs(x); }
691 };
692
693 template<> inline uchar OpAbs<uchar, uchar>::operator()(uchar x) const { return x; }
694 template<> inline ushort OpAbs<ushort, ushort>::operator()(ushort x) const { return x; }
695
696 template<class ElemFunc, class UpdateFunc, class GlobUpdateFunc, int BLOCK_SIZE>
697 static double normBlock_( const Mat& srcmat )
698 {
699     ElemFunc f;
700     UpdateFunc update;
701     GlobUpdateFunc globUpdate;
702     typedef typename ElemFunc::type1 T;
703     typedef typename UpdateFunc::rtype WT;
704     typedef typename GlobUpdateFunc::rtype ST;
705     
706     assert( DataType<T>::depth == srcmat.depth() );
707     Size size = getContinuousSize( srcmat, srcmat.channels() );
708     ST s0 = 0; // luckily, 0 is the correct starting value for both + and max update operations
709     WT s = 0;
710     int y, remaining = BLOCK_SIZE;
711
712     for( y = 0; y < size.height; y++ )
713     {
714         const T* src = (const T*)(srcmat.data + srcmat.step*y);
715         int x = 0;
716         while( x < size.width )
717         {
718             int limit = std::min( remaining, size.width - x );
719             remaining -= limit;
720             limit += x;
721             for( ; x <= limit - 4; x += 4 )
722             {
723                 s = update(s, (WT)f(src[x]));
724                 s = update(s, (WT)f(src[x+1]));
725                 s = update(s, (WT)f(src[x+2]));
726                 s = update(s, (WT)f(src[x+3]));
727             }
728             for( ; x < limit; x++ )
729                 s = update(s, (WT)f(src[x]));
730             if( remaining == 0 || (x == size.width && y == size.height-1) )
731             {
732                 s0 = globUpdate(s0, (ST)s);
733                 s = 0;
734                 remaining = BLOCK_SIZE;
735             }
736         }
737     }
738     return s0;
739 }
740
741 template<class ElemFunc, class UpdateFunc>
742 static double norm_( const Mat& srcmat )
743 {
744     ElemFunc f;
745     UpdateFunc update;
746     typedef typename ElemFunc::type1 T;
747     typedef typename UpdateFunc::rtype ST;
748     
749     assert( DataType<T>::depth == srcmat.depth() );
750     Size size = getContinuousSize( srcmat, srcmat.channels() );
751     ST s = 0;
752
753     for( int y = 0; y < size.height; y++ )
754     {
755         const T* src = (const T*)(srcmat.data + srcmat.step*y);
756         int x = 0;
757         for( ; x <= size.width - 4; x += 4 )
758         {
759             s = update(s, (ST)f(src[x]));
760             s = update(s, (ST)f(src[x+1]));
761             s = update(s, (ST)f(src[x+2]));
762             s = update(s, (ST)f(src[x+3]));
763         }
764         for( ; x < size.width; x++ )
765             s = update(s, (ST)f(src[x]));
766     }
767     return s;
768 }
769
770 template<class ElemFunc, class UpdateFunc, class GlobUpdateFunc, int BLOCK_SIZE>
771 static double normMaskBlock_( const Mat& srcmat, const Mat& maskmat )
772 {
773     ElemFunc f;
774     UpdateFunc update;
775     GlobUpdateFunc globUpdate;
776     typedef typename ElemFunc::type1 T;
777     typedef typename UpdateFunc::rtype WT;
778     typedef typename GlobUpdateFunc::rtype ST;
779     
780     assert( DataType<T>::depth == srcmat.depth() );
781     Size size = getContinuousSize( srcmat, maskmat );
782     ST s0 = 0;
783     WT s = 0;
784     int y, remaining = BLOCK_SIZE;
785
786     for( y = 0; y < size.height; y++ )
787     {
788         const T* src = (const T*)(srcmat.data + srcmat.step*y);
789         const uchar* mask = maskmat.data + maskmat.step*y;
790         int x = 0;
791         while( x < size.width )
792         {
793             int limit = std::min( remaining, size.width - x );
794             remaining -= limit;
795             limit += x;
796             for( ; x <= limit - 4; x += 4 )
797             {
798                 if( mask[x] )
799                     s = update(s, (WT)f(src[x]));
800                 if( mask[x+1] )
801                     s = update(s, (WT)f(src[x+1]));
802                 if( mask[x+2] )
803                     s = update(s, (WT)f(src[x+2]));
804                 if( mask[x+3] )
805                     s = update(s, (WT)f(src[x+3]));
806             }
807             for( ; x < limit; x++ )
808             {
809                 if( mask[x] )
810                     s = update(s, (WT)f(src[x]));
811             }
812             if( remaining == 0 || (x == size.width && y == size.height-1) )
813             {
814                 s0 = globUpdate(s0, (ST)s);
815                 s = 0;
816                 remaining = BLOCK_SIZE;
817             }
818         }
819     }
820     return s0;
821 }
822
823 template<class ElemFunc, class UpdateFunc>
824 static double normMask_( const Mat& srcmat, const Mat& maskmat )
825 {
826     ElemFunc f;
827     UpdateFunc update;
828     typedef typename ElemFunc::type1 T;
829     typedef typename UpdateFunc::rtype ST;
830     
831     assert( DataType<T>::depth == srcmat.depth() );
832     Size size = getContinuousSize( srcmat, maskmat );
833     ST s = 0;
834
835     for( int y = 0; y < size.height; y++ )
836     {
837         const T* src = (const T*)(srcmat.data + srcmat.step*y);
838         const uchar* mask = maskmat.data + maskmat.step*y;
839         int x = 0;
840         for( ; x <= size.width - 4; x += 4 )
841         {
842             if( mask[x] )
843                 s = update(s, (ST)f(src[x]));
844             if( mask[x+1] )
845                 s = update(s, (ST)f(src[x+1]));
846             if( mask[x+2] )
847                 s = update(s, (ST)f(src[x+2]));
848             if( mask[x+3] )
849                 s = update(s, (ST)f(src[x+3]));
850         }
851         for( ; x < size.width; x++ )
852         {
853             if( mask[x] )
854                 s = update(s, (ST)f(src[x]));
855         }
856     }
857     return s;
858 }
859
860 template<typename T, class ElemFunc, class UpdateFunc, class GlobUpdateFunc, int BLOCK_SIZE>
861 static double normDiffBlock_( const Mat& srcmat1, const Mat& srcmat2 )
862 {
863     ElemFunc f;
864     UpdateFunc update;
865     GlobUpdateFunc globUpdate;
866     typedef typename UpdateFunc::rtype WT;
867     typedef typename GlobUpdateFunc::rtype ST;
868     
869     assert( DataType<T>::depth == srcmat1.depth() );
870     Size size = getContinuousSize( srcmat1, srcmat2, srcmat1.channels() );
871     ST s0 = 0;
872     WT s = 0;
873     int y, remaining = BLOCK_SIZE;
874
875     for( y = 0; y < size.height; y++ )
876     {
877         const T* src1 = (const T*)(srcmat1.data + srcmat1.step*y);
878         const T* src2 = (const T*)(srcmat2.data + srcmat2.step*y);
879         int x = 0;
880         while( x < size.width )
881         {
882             int limit = std::min( remaining, size.width - x );
883             remaining -= limit;
884             limit += x;
885             for( ; x <= limit - 4; x += 4 )
886             {
887                 s = update(s, (WT)f(src1[x] - src2[x]));
888                 s = update(s, (WT)f(src1[x+1] - src2[x+1]));
889                 s = update(s, (WT)f(src1[x+2] - src2[x+2]));
890                 s = update(s, (WT)f(src1[x+3] - src2[x+3]));
891             }
892             for( ; x < limit; x++ )
893                 s = update(s, (WT)f(src1[x] - src2[x]));
894             if( remaining == 0 || (x == size.width && y == size.height-1) )
895             {
896                 s0 = globUpdate(s0, (ST)s);
897                 s = 0;
898                 remaining = BLOCK_SIZE;
899             }
900         }
901     }
902     return s0;
903 }
904
905 template<typename T, class ElemFunc, class UpdateFunc>
906 static double normDiff_( const Mat& srcmat1, const Mat& srcmat2 )
907 {
908     ElemFunc f;
909     UpdateFunc update;
910     typedef typename UpdateFunc::rtype ST;
911     
912     assert( DataType<T>::depth == srcmat1.depth() );
913     Size size = getContinuousSize( srcmat1, srcmat2, srcmat1.channels() );
914     ST s = 0;
915
916     for( int y = 0; y < size.height; y++ )
917     {
918         const T* src1 = (const T*)(srcmat1.data + srcmat1.step*y);
919         const T* src2 = (const T*)(srcmat2.data + srcmat2.step*y);
920         int x = 0;
921         for( ; x <= size.width - 4; x += 4 )
922         {
923             s = update(s, (ST)f(src1[x] - src2[x]));
924             s = update(s, (ST)f(src1[x+1] - src2[x+1]));
925             s = update(s, (ST)f(src1[x+2] - src2[x+2]));
926             s = update(s, (ST)f(src1[x+3] - src2[x+3]));
927         }
928         for( ; x < size.width; x++ )
929             s = update(s, (ST)f(src1[x] - src2[x]));
930     }
931     return s;
932 }
933
934 template<typename T, class ElemFunc, class UpdateFunc, class GlobUpdateFunc, int BLOCK_SIZE>
935 static double normDiffMaskBlock_( const Mat& srcmat1, const Mat& srcmat2, const Mat& maskmat )
936 {
937     ElemFunc f;
938     UpdateFunc update;
939     GlobUpdateFunc globUpdate;
940     typedef typename UpdateFunc::rtype WT;
941     typedef typename GlobUpdateFunc::rtype ST;
942     
943     assert( DataType<T>::depth == srcmat1.depth() );
944     Size size = getContinuousSize( srcmat1, srcmat2, maskmat );
945     ST s0 = 0;
946     WT s = 0;
947     int y, remaining = BLOCK_SIZE;
948
949     for( y = 0; y < size.height; y++ )
950     {
951         const T* src1 = (const T*)(srcmat1.data + srcmat1.step*y);
952         const T* src2 = (const T*)(srcmat2.data + srcmat2.step*y);
953         const uchar* mask = maskmat.data + maskmat.step*y;
954         int x = 0;
955         while( x < size.width )
956         {
957             int limit = std::min( remaining, size.width - x );
958             remaining -= limit;
959             limit += x;
960             for( ; x <= limit - 4; x += 4 )
961             {
962                 if( mask[x] )
963                     s = update(s, (WT)f(src1[x] - src2[x]));
964                 if( mask[x+1] )
965                     s = update(s, (WT)f(src1[x+1] - src2[x+1]));
966                 if( mask[x+2] )
967                     s = update(s, (WT)f(src1[x+2] - src2[x+2]));
968                 if( mask[x+3] )
969                     s = update(s, (WT)f(src1[x+3] - src2[x+3]));
970             }
971             for( ; x < limit; x++ )
972                 if( mask[x] )
973                     s = update(s, (WT)f(src1[x] - src2[x]));
974             if( remaining == 0 || (x == size.width && y == size.height-1) )
975             {
976                 s0 = globUpdate(s0, (ST)s);
977                 s = 0;
978                 remaining = BLOCK_SIZE;
979             }
980         }
981     }
982     return s0;
983 }
984
985 template<typename T, class ElemFunc, class UpdateFunc>
986 static double normDiffMask_( const Mat& srcmat1, const Mat& srcmat2, const Mat& maskmat )
987 {
988     ElemFunc f;
989     UpdateFunc update;
990     typedef typename UpdateFunc::rtype ST;
991     
992     assert( DataType<T>::depth == srcmat1.depth() );
993     Size size = getContinuousSize( srcmat1, srcmat2, maskmat );
994     ST s = 0;
995
996     for( int y = 0; y < size.height; y++ )
997     {
998         const T* src1 = (const T*)(srcmat1.data + srcmat1.step*y);
999         const T* src2 = (const T*)(srcmat2.data + srcmat2.step*y);
1000         const uchar* mask = maskmat.data + maskmat.step*y;
1001         int x = 0;
1002         for( ; x <= size.width - 4; x += 4 )
1003         {
1004             if( mask[x] )
1005                 s = update(s, (ST)f(src1[x] - src2[x]));
1006             if( mask[x+1] )
1007                 s = update(s, (ST)f(src1[x+1] - src2[x+1]));
1008             if( mask[x+2] )
1009                 s = update(s, (ST)f(src1[x+2] - src2[x+2]));
1010             if( mask[x+3] )
1011                 s = update(s, (ST)f(src1[x+3] - src2[x+3]));
1012         }
1013         for( ; x < size.width; x++ )
1014             if( mask[x] )
1015                 s = update(s, (ST)f(src1[x] - src2[x]));
1016
1017     }
1018     return s;
1019 }
1020
1021 typedef double (*NormFunc)(const Mat& src);
1022 typedef double (*NormDiffFunc)(const Mat& src1, const Mat& src2);
1023 typedef double (*NormMaskFunc)(const Mat& src1, const Mat& mask);
1024 typedef double (*NormDiffMaskFunc)(const Mat& src1, const Mat& src2, const Mat& mask);
1025
1026 double norm( const Mat& a, int normType )
1027 {
1028     static NormFunc tab[3][8] =
1029     {
1030         {
1031             norm_<OpAbs<uchar>, OpMax<int> >, 0,
1032             norm_<OpAbs<ushort>, OpMax<int> >,
1033             norm_<OpAbs<short, int>, OpMax<int> >,
1034             norm_<OpAbs<int>, OpMax<int> >,
1035             norm_<OpAbs<float>, OpMax<float> >,
1036             norm_<OpAbs<double>, OpMax<double> >
1037         },
1038         
1039         { 
1040             normBlock_<OpAbs<uchar>, OpAdd<unsigned>, OpAdd<double>, 1<<24>, 0,
1041             normBlock_<OpAbs<ushort>, OpAdd<unsigned>, OpAdd<double>, 1<<16>,
1042             normBlock_<OpAbs<short, int>, OpAdd<unsigned>, OpAdd<double>, 1<<16>,
1043             norm_<OpAbs<int>, OpAdd<double> >,
1044             norm_<OpAbs<float>, OpAdd<double> >,
1045             norm_<OpAbs<double>, OpAdd<double> >
1046         },
1047
1048         { 
1049             normBlock_<SqrC1<uchar, unsigned>, OpAdd<unsigned>, OpAdd<double>, 1<<16>, 0,
1050             norm_<SqrC1<ushort, double>, OpAdd<double> >,
1051             norm_<SqrC1<short, double>, OpAdd<double> >,
1052             norm_<SqrC1<int, double>, OpAdd<double> >,
1053             norm_<SqrC1<float, double>, OpAdd<double> >,
1054             norm_<SqrC1<double, double>, OpAdd<double> >
1055         }
1056     };
1057
1058     normType &= 7;
1059     CV_Assert(normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2);
1060     NormFunc func = tab[normType >> 1][a.depth()];
1061     CV_Assert(func != 0);
1062     double r = func(a);
1063     return normType == NORM_L2 ? std::sqrt(r) : r;
1064 }
1065
1066
1067 double norm( const Mat& a, int normType, const Mat& mask )
1068 {
1069     static NormMaskFunc tab[3][8] =
1070     {
1071         {
1072             normMask_<OpAbs<uchar>, OpMax<int> >, 0,
1073             normMask_<OpAbs<ushort>, OpMax<int> >,
1074             normMask_<OpAbs<short, int>, OpMax<int> >,
1075             normMask_<OpAbs<int>, OpMax<int> >,
1076             normMask_<OpAbs<float>, OpMax<float> >,
1077             normMask_<OpAbs<double>, OpMax<double> >
1078         },
1079         
1080         { 
1081             normMaskBlock_<OpAbs<uchar>, OpAdd<unsigned>, OpAdd<double>, 1<<24>, 0,
1082             normMaskBlock_<OpAbs<ushort>, OpAdd<unsigned>, OpAdd<double>, 1<<16>,
1083             normMaskBlock_<OpAbs<short, int>, OpAdd<unsigned>, OpAdd<double>, 1<<16>,
1084             normMask_<OpAbs<int>, OpAdd<double> >,
1085             normMask_<OpAbs<float>, OpAdd<double> >,
1086             normMask_<OpAbs<double>, OpAdd<double> >
1087         },
1088
1089         { 
1090             normMaskBlock_<SqrC1<uchar, unsigned>, OpAdd<unsigned>, OpAdd<double>, 1<<16>, 0,
1091             normMask_<SqrC1<ushort, double>, OpAdd<double> >,
1092             normMask_<SqrC1<short, double>, OpAdd<double> >,
1093             normMask_<SqrC1<int, double>, OpAdd<double> >,
1094             normMask_<SqrC1<float, double>, OpAdd<double> >,
1095             normMask_<SqrC1<double, double>, OpAdd<double> >
1096         }
1097     };
1098
1099     if( !mask.data )
1100         return norm(a, normType);
1101
1102     normType &= 7;
1103     CV_Assert((normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2) &&
1104         a.size() == mask.size() && mask.type() == CV_8U );
1105     NormMaskFunc func = tab[normType >> 1][a.depth()];
1106     CV_Assert(func != 0);
1107     double r = func(a, mask);
1108     return normType == NORM_L2 ? std::sqrt(r) : r;
1109 }
1110
1111
1112 double norm( const Mat& a, const Mat& b, int normType )
1113 {
1114     static NormDiffFunc tab[3][8] =
1115     {
1116         {
1117             normDiff_<uchar, OpAbs<int>, OpMax<int> >, 0,
1118             normDiff_<ushort, OpAbs<int>, OpMax<int> >,
1119             normDiff_<short, OpAbs<int>, OpMax<int> >,
1120             normDiff_<int, OpAbs<int>, OpMax<int> >,
1121             normDiff_<float, OpAbs<float>, OpMax<float> >,
1122             normDiff_<double, OpAbs<double>, OpMax<double> >
1123         },
1124         
1125         { 
1126             normDiffBlock_<uchar, OpAbs<int>, OpAdd<unsigned>, OpAdd<double>, 1<<24>, 0,
1127             normDiffBlock_<ushort, OpAbs<int>, OpAdd<unsigned>, OpAdd<double>, 1<<16>,
1128             normDiffBlock_<short, OpAbs<int>, OpAdd<unsigned>, OpAdd<double>, 1<<16>,
1129             normDiff_<int, OpAbs<int>, OpAdd<double> >,
1130             normDiff_<float, OpAbs<float>, OpAdd<double> >,
1131             normDiff_<double, OpAbs<double>, OpAdd<double> >
1132         },
1133
1134         { 
1135             normDiffBlock_<uchar, SqrC1<int, int>, OpAdd<unsigned>, OpAdd<double>, 1<<16>, 0,
1136             normDiff_<ushort, SqrC1<int, double>, OpAdd<double> >,
1137             normDiff_<short, SqrC1<int, double>, OpAdd<double> >,
1138             normDiff_<int, SqrC1<int, double>, OpAdd<double> >,
1139             normDiff_<float, SqrC1<float, double>, OpAdd<double> >,
1140             normDiff_<double, SqrC1<double, double>, OpAdd<double> >
1141         }
1142     };
1143     
1144     CV_Assert( a.type() == b.type() && a.size() == b.size() );
1145
1146     bool isRelative = (normType & NORM_RELATIVE) != 0;
1147     normType &= 7;
1148     CV_Assert(normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2);
1149
1150     NormDiffFunc func = tab[normType >> 1][a.depth()];
1151     CV_Assert(func != 0);
1152     double r = func( a, b );
1153     if( normType == NORM_L2 )
1154         r = std::sqrt(r);
1155     if( isRelative )
1156         r /= norm(b, normType);
1157     return r;
1158 }
1159
1160 double norm( const Mat& a, const Mat& b, int normType, const Mat& mask )
1161 {
1162     static NormDiffMaskFunc tab[3][8] =
1163     {
1164         {
1165             normDiffMask_<uchar, OpAbs<int>, OpMax<int> >, 0,
1166             normDiffMask_<ushort, OpAbs<int>, OpMax<int> >,
1167             normDiffMask_<short, OpAbs<int>, OpMax<int> >,
1168             normDiffMask_<int, OpAbs<int>, OpMax<int> >,
1169             normDiffMask_<float, OpAbs<float>, OpMax<float> >,
1170             normDiffMask_<double, OpAbs<double>, OpMax<double> >
1171         },
1172         
1173         { 
1174             normDiffMaskBlock_<uchar, OpAbs<int>, OpAdd<unsigned>, OpAdd<double>, 1<<24>, 0,
1175             normDiffMaskBlock_<ushort, OpAbs<int>, OpAdd<unsigned>, OpAdd<double>, 1<<16>,
1176             normDiffMaskBlock_<short, OpAbs<int>, OpAdd<unsigned>, OpAdd<double>, 1<<16>,
1177             normDiffMask_<int, OpAbs<int>, OpAdd<double> >,
1178             normDiffMask_<float, OpAbs<float>, OpAdd<double> >,
1179             normDiffMask_<double, OpAbs<double>, OpAdd<double> >
1180         },
1181
1182         { 
1183             normDiffMaskBlock_<uchar, SqrC1<int, int>, OpAdd<unsigned>, OpAdd<double>, 1<<16>, 0,
1184             normDiffMask_<ushort, SqrC1<int, double>, OpAdd<double> >,
1185             normDiffMask_<short, SqrC1<int, double>, OpAdd<double> >,
1186             normDiffMask_<int, SqrC1<int, double>, OpAdd<double> >,
1187             normDiffMask_<float, SqrC1<float, double>, OpAdd<double> >,
1188             normDiffMask_<double, SqrC1<double, double>, OpAdd<double> >
1189         }
1190     };
1191     
1192     if( !mask.data )
1193         return norm(a, b, normType);
1194
1195     CV_Assert( a.type() == b.type() && a.size() == b.size() &&
1196         a.size() == mask.size() && mask.type() == CV_8U );
1197
1198     bool isRelative = (normType & NORM_RELATIVE) != 0;
1199     normType &= 7;
1200     CV_Assert(normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2);
1201
1202     NormDiffMaskFunc func = tab[normType >> 1][a.depth()];
1203     CV_Assert(func != 0);
1204     double r = func( a, b, mask );
1205     if( normType == NORM_L2 )
1206         r = std::sqrt(r);
1207     if( isRelative )
1208         r /= std::max(norm(b, normType, mask), DBL_EPSILON);
1209     return r;
1210 }
1211
1212 }
1213
1214
1215 CV_IMPL CvScalar cvSum( const CvArr* srcarr )
1216 {
1217     cv::Scalar sum = cv::sum(cv::cvarrToMat(srcarr, false, true, 1));
1218     if( CV_IS_IMAGE(srcarr) )
1219     {
1220         int coi = cvGetImageCOI((IplImage*)srcarr);
1221         if( coi )
1222         {
1223             CV_Assert( 0 < coi && coi <= 4 );
1224             sum = cv::Scalar(sum[coi-1]);
1225         }
1226     }
1227     return sum;
1228 }
1229
1230 CV_IMPL int cvCountNonZero( const CvArr* imgarr )
1231 {
1232     cv::Mat img = cv::cvarrToMat(imgarr, false, true, 1);
1233     if( img.channels() > 1 )
1234         cv::extractImageCOI(imgarr, img);
1235     return countNonZero(img);
1236 }
1237
1238
1239 CV_IMPL  CvScalar
1240 cvAvg( const void* imgarr, const void* maskarr )
1241 {
1242     cv::Mat img = cv::cvarrToMat(imgarr, false, true, 1);
1243     cv::Scalar mean = !maskarr ? cv::mean(img) : cv::mean(img, cv::cvarrToMat(maskarr));
1244     if( CV_IS_IMAGE(imgarr) )
1245     {
1246         int coi = cvGetImageCOI((IplImage*)imgarr);
1247         if( coi )
1248         {
1249             CV_Assert( 0 < coi && coi <= 4 );
1250             mean = cv::Scalar(mean[coi-1]);
1251         }
1252     }
1253     return mean;
1254 }
1255
1256
1257 CV_IMPL  void
1258 cvAvgSdv( const CvArr* imgarr, CvScalar* _mean, CvScalar* _sdv, const void* maskarr )
1259 {
1260     cv::Scalar mean, sdv;
1261
1262     cv::Mat mask;
1263     if( maskarr )
1264         mask = cv::cvarrToMat(maskarr);
1265
1266     cv::meanStdDev(cv::cvarrToMat(imgarr, false, true, 1), mean, sdv, mask );
1267
1268     if( CV_IS_IMAGE(imgarr) )
1269     {
1270         int coi = cvGetImageCOI((IplImage*)imgarr);
1271         if( coi )
1272         {
1273             CV_Assert( 0 < coi && coi <= 4 );
1274             mean = cv::Scalar(mean[coi-1]);
1275             sdv = cv::Scalar(sdv[coi-1]);
1276         }
1277     }
1278
1279     if( _mean )
1280         *(cv::Scalar*)_mean = mean;
1281     if( _sdv )
1282         *(cv::Scalar*)_sdv = sdv;
1283 }
1284
1285
1286 CV_IMPL void
1287 cvMinMaxLoc( const void* imgarr, double* _minVal, double* _maxVal,
1288              CvPoint* _minLoc, CvPoint* _maxLoc, const void* maskarr )
1289 {
1290     cv::Mat mask, img = cv::cvarrToMat(imgarr, false, true, 1);
1291     if( maskarr )
1292         mask = cv::cvarrToMat(maskarr);
1293     if( img.channels() > 1 )
1294         cv::extractImageCOI(imgarr, img);
1295
1296     cv::minMaxLoc( img, _minVal, _maxVal,
1297         (cv::Point*)_minLoc, (cv::Point*)_maxLoc, mask );
1298 }
1299
1300
1301 CV_IMPL  double
1302 cvNorm( const void* imgA, const void* imgB, int normType, const void* maskarr )
1303 {
1304     cv::Mat a, mask;
1305     if( !imgA )
1306     {
1307         imgA = imgB;
1308         imgB = 0;
1309     }
1310
1311     a = cv::cvarrToMat(imgA, false, true, 1);
1312     if( maskarr )
1313         mask = cv::cvarrToMat(maskarr);
1314
1315     if( a.channels() > 1 && CV_IS_IMAGE(imgA) && cvGetImageCOI((const IplImage*)imgA) > 0 )
1316         cv::extractImageCOI(imgA, a);
1317
1318     if( !imgB )
1319         return !maskarr ? cv::norm(a, normType) : cv::norm(a, normType, mask);
1320
1321     cv::Mat b = cv::cvarrToMat(imgB, false, true, 1);
1322     if( b.channels() > 1 && CV_IS_IMAGE(imgB) && cvGetImageCOI((const IplImage*)imgB) > 0 )
1323         cv::extractImageCOI(imgB, b);
1324
1325     return !maskarr ? cv::norm(a, b, normType) : cv::norm(a, b, normType, mask);
1326 }