Update to 2.0.0 tree from current Fremantle build
[opencv] / src / cxcore / cxarithm.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 /* ////////////////////////////////////////////////////////////////////
44 //
45 //  Matrix arithmetic and logical operations: +, -, *, /, &, |, ^, ~, abs ...
46 //
47 // */
48
49 #include "_cxcore.h"
50
51 namespace cv
52 {
53
54 #if CV_SSE2
55
56 template<class Op8> struct VBinOp8
57 {
58     int operator()(const uchar* src1, const uchar* src2, uchar* dst, int len) const
59     {
60         int x = 0;
61         for( ; x <= len - 32; x += 32 )
62         {
63             __m128i r0 = _mm_loadu_si128((const __m128i*)(src1 + x));
64             __m128i r1 = _mm_loadu_si128((const __m128i*)(src1 + x + 16));
65             r0 = op(r0,_mm_loadu_si128((const __m128i*)(src2 + x)));
66             r1 = op(r1,_mm_loadu_si128((const __m128i*)(src2 + x + 16)));
67             _mm_storeu_si128((__m128i*)(dst + x), r0);
68             _mm_storeu_si128((__m128i*)(dst + x + 16), r1);
69         }
70         for( ; x <= len - 8; x += 8 )
71         {
72             __m128i r0 = _mm_loadl_epi64((const __m128i*)(src1 + x));
73             r0 = op(r0,_mm_loadl_epi64((const __m128i*)(src2 + x)));
74             _mm_storel_epi64((__m128i*)(dst + x), r0);
75         }
76         return x;
77     }
78     Op8 op;
79 };
80
81 template<typename T, class Op16> struct VBinOp16
82 {
83     int operator()(const T* src1, const T* src2, T* dst, int len) const
84     {
85         int x = 0;
86         for( ; x <= len - 16; x += 16 )
87         {
88             __m128i r0 = _mm_loadu_si128((const __m128i*)(src1 + x));
89             __m128i r1 = _mm_loadu_si128((const __m128i*)(src1 + x + 8));
90             r0 = op(r0,_mm_loadu_si128((const __m128i*)(src2 + x)));
91             r1 = op(r1,_mm_loadu_si128((const __m128i*)(src2 + x + 8)));
92             _mm_storeu_si128((__m128i*)(dst + x), r0);
93             _mm_storeu_si128((__m128i*)(dst + x + 8), r1);
94         }
95         for( ; x <= len - 4; x += 4 )
96         {
97             __m128i r0 = _mm_loadl_epi64((const __m128i*)(src1 + x));
98             r0 = op(r0,_mm_loadl_epi64((const __m128i*)(src2 + x)));
99             _mm_storel_epi64((__m128i*)(dst + x), r0);
100         }
101         return x;
102     }
103     Op16 op;
104 };
105
106 template<class Op32f> struct VBinOp32f
107 {
108     int operator()(const float* src1, const float* src2, float* dst, int len) const
109     {
110         int x = 0;
111         if( (((size_t)src1|(size_t)src2|(size_t)dst)&15) == 0 )
112             for( ; x <= len - 8; x += 8 )
113             {
114                 __m128 r0 = _mm_load_ps(src1 + x);
115                 __m128 r1 = _mm_load_ps(src1 + x + 4);
116                 r0 = op(r0,_mm_load_ps(src2 + x));
117                 r1 = op(r1,_mm_load_ps(src2 + x + 4));
118                 _mm_store_ps(dst + x, r0);
119                 _mm_store_ps(dst + x + 4, r1);
120             }
121         else
122             for( ; x <= len - 8; x += 8 )
123             {
124                 __m128 r0 = _mm_loadu_ps(src1 + x);
125                 __m128 r1 = _mm_loadu_ps(src1 + x + 4);
126                 r0 = op(r0,_mm_loadu_ps(src2 + x));
127                 r1 = op(r1,_mm_loadu_ps(src2 + x + 4));
128                 _mm_storeu_ps(dst + x, r0);
129                 _mm_storeu_ps(dst + x + 4, r1);
130             }
131         return x;
132     }
133     Op32f op;
134 };
135
136 struct _VAdd8u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_adds_epu8(a,b); }};
137 struct _VSub8u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_subs_epu8(a,b); }};
138 struct _VMin8u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_min_epu8(a,b); }};
139 struct _VMax8u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_max_epu8(a,b); }};
140 struct _VCmpGT8u { __m128i operator()(const __m128i& a, const __m128i& b) const
141 {
142     __m128i delta = _mm_set1_epi32(0x80808080);
143     return _mm_cmpgt_epi8(_mm_xor_si128(a,delta),_mm_xor_si128(b,delta));
144 }};
145 struct _VCmpEQ8u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_cmpeq_epi8(a,b); }};
146 struct _VAbsDiff8u
147 {
148     __m128i operator()(const __m128i& a, const __m128i& b) const
149     { return _mm_add_epi8(_mm_subs_epu8(a,b),_mm_subs_epu8(b,a)); }
150 };
151 struct _VAdd16u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_adds_epu16(a,b); }};
152 struct _VSub16u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_subs_epu16(a,b); }};
153 struct _VMin16u
154 {
155     __m128i operator()(const __m128i& a, const __m128i& b) const
156     { return _mm_subs_epu16(a,_mm_subs_epu16(a,b)); }
157 };
158 struct _VMax16u
159 {
160     __m128i operator()(const __m128i& a, const __m128i& b) const
161     { return _mm_adds_epu16(_mm_subs_epu16(a,b),b); }
162 };
163 struct _VAbsDiff16u
164 {
165     __m128i operator()(const __m128i& a, const __m128i& b) const
166     { return _mm_add_epi16(_mm_subs_epu16(a,b),_mm_subs_epu16(b,a)); }
167 };
168 struct _VAdd16s { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_adds_epi16(a,b); }};
169 struct _VSub16s { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_subs_epi16(a,b); }};
170 struct _VMin16s { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_min_epi16(a,b); }};
171 struct _VMax16s { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_max_epi16(a,b); }};
172 struct _VAbsDiff16s
173 {
174     __m128i operator()(const __m128i& a, const __m128i& b) const
175     {
176         __m128i M = _mm_max_epi16(a,b), m = _mm_min_epi16(a,b);
177         return _mm_subs_epi16(M, m);
178     }
179 };
180 struct _VAdd32f { __m128 operator()(const __m128& a, const __m128& b) const { return _mm_add_ps(a,b); }};
181 struct _VSub32f { __m128 operator()(const __m128& a, const __m128& b) const { return _mm_sub_ps(a,b); }};
182 struct _VMin32f { __m128 operator()(const __m128& a, const __m128& b) const { return _mm_min_ps(a,b); }};
183 struct _VMax32f { __m128 operator()(const __m128& a, const __m128& b) const { return _mm_max_ps(a,b); }};
184 static const __m128i v32f_absmask = _mm_set1_epi32(0x7fffffff);
185 struct _VAbsDiff32f
186 {
187     __m128 operator()(const __m128& a, const __m128& b) const
188     {
189         return _mm_and_ps(_mm_sub_ps(a,b), (__m128&)v32f_absmask);
190     }
191 };
192
193 struct _VAnd8u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_and_si128(a,b); }};
194 struct _VOr8u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_or_si128(a,b); }};
195 struct _VXor8u { __m128i operator()(const __m128i& a, const __m128i& b) const { return _mm_xor_si128(a,b); }};
196
197 typedef VBinOp8<_VAdd8u> VAdd8u;
198 typedef VBinOp8<_VSub8u> VSub8u;
199 typedef VBinOp8<_VMin8u> VMin8u;
200 typedef VBinOp8<_VMax8u> VMax8u;
201 typedef VBinOp8<_VAbsDiff8u> VAbsDiff8u;
202 typedef VBinOp8<_VCmpEQ8u> VCmpEQ8u;
203 typedef VBinOp8<_VCmpGT8u> VCmpGT8u;
204
205 typedef VBinOp16<ushort, _VAdd16u> VAdd16u;
206 typedef VBinOp16<ushort, _VSub16u> VSub16u;
207 typedef VBinOp16<ushort, _VMin16u> VMin16u;
208 typedef VBinOp16<ushort, _VMax16u> VMax16u;
209 typedef VBinOp16<ushort, _VAbsDiff16u> VAbsDiff16u;
210
211 typedef VBinOp16<short, _VAdd16s> VAdd16s;
212 typedef VBinOp16<short, _VSub16s> VSub16s;
213 typedef VBinOp16<short, _VMin16s> VMin16s;
214 typedef VBinOp16<short, _VMax16s> VMax16s;
215 typedef VBinOp16<short, _VAbsDiff16s> VAbsDiff16s;
216
217 typedef VBinOp32f<_VAdd32f> VAdd32f;
218 typedef VBinOp32f<_VSub32f> VSub32f;
219 typedef VBinOp32f<_VMin32f> VMin32f;
220 typedef VBinOp32f<_VMax32f> VMax32f;
221 typedef VBinOp32f<_VAbsDiff32f> VAbsDiff32f;
222
223 typedef VBinOp8<_VAnd8u> VAnd8u;
224 typedef VBinOp8<_VOr8u> VOr8u;
225 typedef VBinOp8<_VXor8u> VXor8u;
226
227 #else
228
229 typedef NoVec VAdd8u;
230 typedef NoVec VSub8u;
231 typedef NoVec VMin8u;
232 typedef NoVec VMax8u;
233 typedef NoVec VAbsDiff8u;
234 typedef NoVec VCmpEQ8u;
235 typedef NoVec VCmpGT8u;
236
237 typedef NoVec VAdd16u;
238 typedef NoVec VSub16u;
239 typedef NoVec VMin16u;
240 typedef NoVec VMax16u;
241 typedef NoVec VAbsDiff16u;
242
243 typedef NoVec VAdd16s;
244 typedef NoVec VSub16s;
245 typedef NoVec VMin16s;
246 typedef NoVec VMax16s;
247 typedef NoVec VAbsDiff16s;
248
249 typedef NoVec VAdd32f;
250 typedef NoVec VSub32f;
251 typedef NoVec VMin32f;
252 typedef NoVec VMax32f;
253 typedef NoVec VAbsDiff32f;
254
255 typedef NoVec VAnd8u;
256 typedef NoVec VOr8u;
257 typedef NoVec VXor8u;
258
259 #endif
260
261 /****************************************************************************************\
262 *                                   logical operations                                   *
263 \****************************************************************************************/
264
265 template<typename T> struct AndOp
266 {
267     typedef T type1;
268     typedef T type2;
269     typedef T rtype;
270     T operator()( T a, T b ) const { return a & b; }
271 };
272
273 template<typename T> struct OrOp
274 {
275     typedef T type1;
276     typedef T type2;
277     typedef T rtype;
278     T operator()( T a, T b ) const { return a | b; }
279 };
280
281 template<typename T> struct XorOp
282 {
283     typedef T type1;
284     typedef T type2;
285     typedef T rtype;
286     T operator()( T a, T b ) const { return a ^ b; }
287 };
288
289 template<class OPB, class OPI, class OPV> static void
290 bitwiseOp_( const Mat& srcmat1, const Mat& srcmat2, Mat& dstmat )
291 {
292     OPB opb; OPI opi; OPV opv;
293     const uchar* src1 = srcmat1.data;
294     const uchar* src2 = srcmat2.data;
295     uchar* dst = dstmat.data;
296     size_t step1 = srcmat1.step, step2 = srcmat2.step, step = dstmat.step;
297     Size size = getContinuousSize( srcmat1, srcmat2, dstmat, (int)srcmat1.elemSize() );
298
299     for( ; size.height--; src1 += step1, src2 += step2, dst += step )
300     {
301         int i = opv(src1, src2, dst, size.width);
302
303         if( (((size_t)src1 | (size_t)src2 | (size_t)dst) & 3) == 0 )
304         {
305             for( ; i <= size.width - 16; i += 16 )
306             {
307                 int t0 = opi(((const int*)(src1+i))[0], ((const int*)(src2+i))[0]);
308                 int t1 = opi(((const int*)(src1+i))[1], ((const int*)(src2+i))[1]);
309
310                 ((int*)(dst+i))[0] = t0;
311                 ((int*)(dst+i))[1] = t1;
312
313                 t0 = opi(((const int*)(src1+i))[2], ((const int*)(src2+i))[2]);
314                 t1 = opi(((const int*)(src1+i))[3], ((const int*)(src2+i))[3]);
315
316                 ((int*)(dst+i))[2] = t0;
317                 ((int*)(dst+i))[3] = t1;
318             }
319
320             for( ; i <= size.width - 4; i += 4 )
321             {
322                 int t = opi(*(const int*)(src1+i), *(const int*)(src2+i));
323                 *(int*)(dst+i) = t;
324             }
325         }
326
327         for( ; i < size.width; i++ )
328             dst[i] = opb(src1[i], src2[i]);
329     }
330 }
331
332
333 template<class OPB, class OPI, class OPV> static void
334 bitwiseSOp_( const Mat& srcmat, Mat& dstmat, const Scalar& _scalar )
335 {
336     OPB opb; OPI opi; OPV opv;
337     const uchar* src0 = srcmat.data;
338     uchar* dst0 = dstmat.data;
339     size_t step1 = srcmat.step, step = dstmat.step;
340     Size size = getContinuousSize( srcmat, dstmat, (int)srcmat.elemSize() );
341     const int delta = 96;
342     uchar scalar[delta];
343     scalarToRawData(_scalar, scalar, srcmat.type(), (int)(delta/srcmat.elemSize1()) );
344
345     for( ; size.height--; src0 += step1, dst0 += step )
346     {
347         const uchar* src = (const uchar*)src0;
348         uchar* dst = dst0;
349         int i, len = size.width;
350
351         if( (((size_t)src|(size_t)dst) & 3) == 0 )
352         {
353             while( (len -= delta) >= 0 )
354             {
355                 i = opv(src, scalar, dst, delta);
356                 for( ; i < delta; i += 16 )
357                 {
358                     int t0 = opi(((const int*)(src+i))[0], ((const int*)(scalar+i))[0]);
359                     int t1 = opi(((const int*)(src+i))[1], ((const int*)(scalar+i))[1]);
360                     ((int*)(dst+i))[0] = t0;
361                     ((int*)(dst+i))[1] = t1;
362
363                     t0 = opi(((const int*)(src+i))[2], ((const int*)(scalar+i))[2]);
364                     t1 = opi(((const int*)(src+i))[3], ((const int*)(scalar+i))[3]);
365                     ((int*)(dst+i))[2] = t0;
366                     ((int*)(dst+i))[3] = t1;
367                 }
368                 src += delta;
369                 dst += delta;
370             }
371         }
372         else
373         {
374             while( (len -= delta) >= 0 )
375             {
376                 for( i = 0; i < delta; i += 4 )
377                 {
378                     uchar t0 = opb(src[i], scalar[i]);
379                     uchar t1 = opb(src[i+1], scalar[i+1]);
380                     dst[i] = t0; dst[i+1] = t1;
381
382                     t0 = opb(src[i+2], scalar[i+2]);
383                     t1 = opb(src[i+3], scalar[i+3]);
384                     dst[i+2] = t0; dst[i+3] = t1;
385                 }
386                 src += delta;
387                 dst += delta;
388             }
389         }
390
391         for( len += delta, i = 0; i < len; i++ )
392             dst[i] = opb(src[i],scalar[i]);
393     }
394 }
395
396 static void
397 binaryMaskOp( const Mat& src1, const Mat& src2, Mat& dst,
398               const Mat& mask, BinaryFunc func )
399 {
400     CV_Assert( src1.size() == src2.size() && src1.type() == src2.type() && func != 0 );
401     dst.create( src1.size(), src1.type() );
402
403     if( !mask.data )
404         func(src1, src2, dst);
405     else
406     {
407         AutoBuffer<uchar> buf;
408         size_t esz = dst.elemSize(), buf_step = dst.cols*esz;
409         CopyMaskFunc copym_func = getCopyMaskFunc((int)esz);
410         int y, dy;
411
412         CV_Assert(mask.type() == CV_8UC1 && mask.size() == dst.size());
413         dy = std::min(std::max((int)(CV_MAX_LOCAL_SIZE/buf_step), 1), dst.rows);
414         buf.allocate( buf_step*dy );
415
416         for( y = 0; y < dst.rows; y += dy )
417         {
418             dy = std::min(dy, dst.rows - y);
419             Mat dstpart = dst.rowRange(y, y + dy);
420             Mat temp(dy, dst.cols, dst.type(), (uchar*)buf );
421             func( src1.rowRange(y, y + dy), src2.rowRange(y, y + dy), temp );
422             copym_func( temp, dstpart, mask.rowRange(y, y + dy) );
423         }
424     }
425 }
426
427
428 static void
429 binarySMaskOp( const Mat& src1, const Scalar& s, Mat& dst,
430                const Mat& mask, BinarySFuncCn func )
431 {
432     CV_Assert( func != 0 );
433     dst.create( src1.size(), src1.type() );
434
435     if( !mask.data )
436         func(src1, dst, s);
437     else
438     {
439         AutoBuffer<uchar> buf;
440         size_t esz = dst.elemSize(), buf_step = dst.cols*esz;
441         CopyMaskFunc copym_func = getCopyMaskFunc((int)esz);
442         int y, dy;
443
444         CV_Assert(mask.type() == CV_8UC1 && mask.size() == dst.size());
445         dy = std::min(std::max((int)(CV_MAX_LOCAL_SIZE/buf_step), 1), dst.rows);
446         buf.allocate( buf_step*dy );
447
448         for( y = 0; y < dst.rows; y += dy )
449         {
450             dy = std::min(dy, dst.rows - y);
451             Mat dstpart = dst.rowRange(y, y + dy);
452             Mat temp(dy, dst.cols, dst.type(), (uchar*)buf);
453             func( src1.rowRange(y, y + dy), temp, s );
454             copym_func( temp, dstpart, mask.rowRange(y, y + dy) );
455         }
456     }
457 }
458
459
460 void bitwise_and(const Mat& a, const Mat& b, Mat& c, const Mat& mask)
461 {
462     binaryMaskOp(a, b, c, mask, bitwiseOp_<AndOp<uchar>, AndOp<int>, VAnd8u>);
463 }
464
465 void bitwise_or(const Mat& a, const Mat& b, Mat& c, const Mat& mask)
466 {
467     binaryMaskOp(a, b, c, mask, bitwiseOp_<OrOp<uchar>, OrOp<int>, VOr8u>);
468 }
469
470 void bitwise_xor(const Mat& a, const Mat& b, Mat& c, const Mat& mask)
471 {
472     binaryMaskOp(a, b, c, mask, bitwiseOp_<XorOp<uchar>, XorOp<int>, VXor8u>);
473 }
474
475 void bitwise_and(const Mat& a, const Scalar& s, Mat& c, const Mat& mask)
476 {
477     binarySMaskOp(a, s, c, mask,
478         bitwiseSOp_<AndOp<uchar>, AndOp<int>, VAnd8u>);
479 }
480
481 void bitwise_or(const Mat& a, const Scalar& s, Mat& c, const Mat& mask)
482 {
483     binarySMaskOp(a, s, c, mask,
484         bitwiseSOp_<OrOp<uchar>, OrOp<int>, VOr8u>);
485 }
486
487 void bitwise_xor(const Mat& a, const Scalar& s, Mat& c, const Mat& mask)
488 {
489     binarySMaskOp(a, s, c, mask,
490         bitwiseSOp_<XorOp<uchar>, XorOp<int>, VXor8u>);
491 }
492
493
494 void bitwise_not(const Mat& src, Mat& dst)
495 {
496     const uchar* sptr = src.data;
497     uchar* dptr = dst.data;
498     dst.create( src.size(), src.type() );
499     Size size = getContinuousSize( src, dst, (int)src.elemSize() );
500
501     for( ; size.height--; sptr += src.step, dptr += dst.step )
502     {
503         int i = 0;
504         if( (((size_t)sptr | (size_t)dptr) & 3) == 0 )
505         {
506             for( ; i <= size.width - 16; i += 16 )
507             {
508                 int t0 = ~((const int*)(sptr+i))[0];
509                 int t1 = ~((const int*)(sptr+i))[1];
510
511                 ((int*)(dptr+i))[0] = t0;
512                 ((int*)(dptr+i))[1] = t1;
513
514                 t0 = ~((const int*)(sptr+i))[2];
515                 t1 = ~((const int*)(sptr+i))[3];
516
517                 ((int*)(dptr+i))[2] = t0;
518                 ((int*)(dptr+i))[3] = t1;
519             }
520
521             for( ; i <= size.width - 4; i += 4 )
522                 *(int*)(dptr+i) = ~*(const int*)(sptr+i);
523         }
524
525         for( ; i < size.width; i++ )
526         {
527             dptr[i] = (uchar)(~sptr[i]);
528         }
529     }
530 }
531
532 /****************************************************************************************\
533 *                                      add/subtract                                      *
534 \****************************************************************************************/
535
536 template<> inline uchar OpAdd<uchar>::operator ()(uchar a, uchar b) const
537 { return CV_FAST_CAST_8U(a + b); }
538 template<> inline uchar OpSub<uchar>::operator ()(uchar a, uchar b) const
539 { return CV_FAST_CAST_8U(a - b); }
540
541 static BinaryFunc addTab[] =
542 {
543     binaryOpC1_<OpAdd<uchar>,VAdd8u>, 0,
544     binaryOpC1_<OpAdd<ushort>,VAdd16u>,
545     binaryOpC1_<OpAdd<short>,VAdd16s>,
546     binaryOpC1_<OpAdd<int>,NoVec>,
547     binaryOpC1_<OpAdd<float>,VAdd32f>,
548     binaryOpC1_<OpAdd<double>,NoVec>, 0
549 };
550
551 static BinaryFunc subTab[] =
552 {
553     binaryOpC1_<OpSub<uchar>,VSub8u>, 0,
554     binaryOpC1_<OpSub<ushort>,VSub16u>,
555     binaryOpC1_<OpSub<short>,VSub16s>,
556     binaryOpC1_<OpSub<int>,NoVec>,
557     binaryOpC1_<OpSub<float>,VSub32f>,
558     binaryOpC1_<OpSub<double>,NoVec>, 0
559 };
560
561
562 void add( const Mat& src1, const Mat& src2, Mat& dst )
563 {
564     Size size = src1.size(); int type = src1.type();
565     BinaryFunc func = addTab[CV_MAT_DEPTH(type)];
566     CV_Assert( size == src2.size() && type == src2.type() && func != 0 );
567     dst.create( size, type );
568     func(src1, src2, dst);
569 }
570
571 void subtract( const Mat& src1, const Mat& src2, Mat& dst )
572 {
573     Size size = src1.size(); int type = src1.type();
574     BinaryFunc func = subTab[CV_MAT_DEPTH(type)];
575     CV_Assert( size == src2.size() && type == src2.type() && func != 0 );
576     dst.create( size, type );
577     func(src1, src2, dst);
578 }
579
580 void subtract(const Mat& a, const Scalar& s, Mat& c, const Mat& mask)
581 {
582     add(a, -s, c, mask);
583 }
584
585 void add(const Mat& src1, const Mat& src2, Mat& dst, const Mat& mask)
586 {
587     binaryMaskOp(src1, src2, dst, mask, addTab[src1.depth()] );
588 }
589
590 void subtract(const Mat& src1, const Mat& src2, Mat& dst, const Mat& mask)
591 {
592     binaryMaskOp(src1, src2, dst, mask, subTab[src1.depth()] );
593 }
594
595 void add(const Mat& src1, const Scalar& s, Mat& dst, const Mat& mask)
596 {
597     static BinarySFuncCn addSTab[] =
598     {
599         binarySOpCn_<OpAdd<uchar, int, uchar> >, 0,
600         binarySOpCn_<OpAdd<ushort, int, ushort> >,
601         binarySOpCn_<OpAdd<short, int, short> >,
602         binarySOpCn_<OpAdd<int> >,
603         binarySOpCn_<OpAdd<float> >,
604         binarySOpCn_<OpAdd<double> >, 0
605     };
606     int depth = src1.depth();
607     binarySMaskOp(src1, s, dst, mask, addSTab[depth]);
608 }
609
610 void subtract(const Scalar& s, const Mat& src1, Mat& dst, const Mat& mask)
611 {
612     static BinarySFuncCn rsubSTab[] =
613     {
614         binarySOpCn_<OpRSub<uchar, int, uchar> >, 0,
615         binarySOpCn_<OpRSub<ushort, int, ushort> >,
616         binarySOpCn_<OpRSub<short, int, short> >,
617         binarySOpCn_<OpRSub<int> >,
618         binarySOpCn_<OpRSub<float> >,
619         binarySOpCn_<OpRSub<double> >, 0
620     };
621     int depth = src1.depth();
622     binarySMaskOp(src1, s, dst, mask, rsubSTab[depth]);
623 }
624
625 /****************************************************************************************\
626 *                                    multiply/divide                                     *
627 \****************************************************************************************/
628
629 template<typename T, typename WT> static void
630 mul_( const Mat& srcmat1, const Mat& srcmat2, Mat& dstmat, double _scale )
631 {
632     const T* src1 = (const T*)srcmat1.data;
633     const T* src2 = (const T*)srcmat2.data;
634     T* dst = (T*)dstmat.data;
635     size_t step1 = srcmat1.step/sizeof(src1[0]);
636     size_t step2 = srcmat2.step/sizeof(src2[0]);
637     size_t step = dstmat.step/sizeof(dst[0]);
638     Size size = getContinuousSize( srcmat1, srcmat2, dstmat, dstmat.channels() );
639
640     if( fabs(_scale - 1.) < DBL_EPSILON )
641     {
642         for( ; size.height--; src1+=step1, src2+=step2, dst+=step )
643         {
644             int i;
645             for( i = 0; i <= size.width - 4; i += 4 )
646             {
647                 T t0 = saturate_cast<T>(src1[i] * src2[i]);
648                 T t1 = saturate_cast<T>(src1[i+1] * src2[i+1]);
649                 dst[i] = t0; dst[i+1] = t1;
650
651                 t0 = saturate_cast<T>(src1[i+2] * src2[i+2]);
652                 t1 = saturate_cast<T>(src1[i+3] * src2[i+3]);
653                 dst[i+2] = t0; dst[i+3] = t1;
654             }
655
656             for( ; i < size.width; i++ )
657                 dst[i] = saturate_cast<T>(src1[i] * src2[i]);
658         }
659     }
660     else
661     {
662         WT scale = (WT)_scale;
663         for( ; size.height--; src1+=step1, src2+=step2, dst+=step )
664         {
665             int i;
666             for( i = 0; i <= size.width - 4; i += 4 )
667             {
668                 T t0 = saturate_cast<T>(scale*(WT)src1[i]*src2[i]);
669                 T t1 = saturate_cast<T>(scale*(WT)src1[i+1]*src2[i+1]);
670                 dst[i] = t0; dst[i+1] = t1;
671
672                 t0 = saturate_cast<T>(scale*(WT)src1[i+2]*src2[i+2]);
673                 t1 = saturate_cast<T>(scale*(WT)src1[i+3]*src2[i+3]);
674                 dst[i+2] = t0; dst[i+3] = t1;
675             }
676
677             for( ; i < size.width; i++ )
678                 dst[i] = saturate_cast<T>(scale*(WT)src1[i]*src2[i]);
679         }
680     }
681 }
682
683 typedef void (*MulDivFunc)( const Mat& src1, const Mat& src2,
684                             Mat& dst, double scale );
685
686 void multiply(const Mat& src1, const Mat& src2, Mat& dst, double scale)
687 {
688     static MulDivFunc tab[] =
689     {
690         mul_<uchar, float>, 0, mul_<ushort, float>, mul_<short, float>,
691         mul_<int, double>, mul_<float, float>, mul_<double, double>, 0
692     };
693
694     MulDivFunc func = tab[src1.depth()];
695     CV_Assert( src1.size() == src2.size() && src1.type() == src2.type() && func != 0 );
696     dst.create( src1.size(), src1.type() );
697     func( src1, src2, dst, scale );
698 }
699
700
701 template<typename T> static void
702 div_( const Mat& srcmat1, const Mat& srcmat2, Mat& dstmat, double scale )
703 {
704     const T* src1 = (const T*)srcmat1.data;
705     const T* src2 = (const T*)srcmat2.data;
706     T* dst = (T*)dstmat.data;
707     size_t step1 = srcmat1.step/sizeof(src1[0]);
708     size_t step2 = srcmat2.step/sizeof(src2[0]);
709     size_t step = dstmat.step/sizeof(dst[0]);
710     Size size = getContinuousSize( srcmat1, srcmat2, dstmat, dstmat.channels() );
711
712     for( ; size.height--; src1+=step1, src2+=step2, dst+=step )
713     {
714         int i = 0;
715         for( ; i <= size.width - 4; i += 4 )
716         {
717             if( src2[i] != 0 && src2[i+1] != 0 && src2[i+2] != 0 && src2[i+3] != 0 )
718             {
719                 double a = (double)src2[i] * src2[i+1];
720                 double b = (double)src2[i+2] * src2[i+3];
721                 double d = scale/(a * b);
722                 b *= d;
723                 a *= d;
724
725                 T z0 = saturate_cast<T>(src2[i+1] * src1[i] * b);
726                 T z1 = saturate_cast<T>(src2[i] * src1[i+1] * b);
727                 T z2 = saturate_cast<T>(src2[i+3] * src1[i+2] * a);
728                 T z3 = saturate_cast<T>(src2[i+2] * src1[i+3] * a);
729
730                 dst[i] = z0; dst[i+1] = z1;
731                 dst[i+2] = z2; dst[i+3] = z3;
732             }
733             else
734             {
735                 T z0 = src2[i] != 0 ? saturate_cast<T>(src1[i]*scale/src2[i]) : 0;
736                 T z1 = src2[i+1] != 0 ? saturate_cast<T>(src1[i+1]*scale/src2[i+1]) : 0;
737                 T z2 = src2[i+2] != 0 ? saturate_cast<T>(src1[i+2]*scale/src2[i+2]) : 0;
738                 T z3 = src2[i+3] != 0 ? saturate_cast<T>(src1[i+3]*scale/src2[i+3]) : 0;
739
740                 dst[i] = z0; dst[i+1] = z1;
741                 dst[i+2] = z2; dst[i+3] = z3;
742             }
743         }
744
745         for( ; i < size.width; i++ )
746             dst[i] = src2[i] != 0 ? saturate_cast<T>(src1[i]*scale/src2[i]) : 0;
747     }
748 }
749
750
751 void divide(const Mat& src1, const Mat& src2, Mat& dst, double scale)
752 {
753     static MulDivFunc tab[] =
754     {
755         div_<uchar>, 0, div_<ushort>, div_<short>,
756         div_<int>, div_<float>, div_<double>, 0
757     };
758
759     MulDivFunc func = tab[src1.depth()];
760     CV_Assert( src1.size() == src2.size() && src1.type() == src2.type() && func != 0 );
761     dst.create( src1.size(), src1.type() );
762     func( src1, src2, dst, scale );
763 }
764
765 template<typename T> static void
766 recip_( double scale, const Mat& srcmat2, Mat& dstmat )
767 {
768     const T* src2 = (const T*)srcmat2.data;
769     T* dst = (T*)dstmat.data;
770     size_t step2 = srcmat2.step/sizeof(src2[0]);
771     size_t step = dstmat.step/sizeof(dst[0]);
772     Size size = getContinuousSize( srcmat2, dstmat, dstmat.channels() );
773
774     for( ; size.height--; src2+=step2, dst+=step )
775     {
776         int i = 0;
777         for( ; i <= size.width - 4; i += 4 )
778         {
779             if( src2[i] != 0 && src2[i+1] != 0 && src2[i+2] != 0 && src2[i+3] != 0 )
780             {
781                 double a = (double)src2[i] * src2[i+1];
782                 double b = (double)src2[i+2] * src2[i+3];
783                 double d = scale/(a * b);
784                 b *= d;
785                 a *= d;
786
787                 T z0 = saturate_cast<T>(src2[i+1] * b);
788                 T z1 = saturate_cast<T>(src2[i] * b);
789                 T z2 = saturate_cast<T>(src2[i+3] * a);
790                 T z3 = saturate_cast<T>(src2[i+2] * a);
791
792                 dst[i] = z0; dst[i+1] = z1;
793                 dst[i+2] = z2; dst[i+3] = z3;
794             }
795             else
796             {
797                 T z0 = src2[i] != 0 ? saturate_cast<T>(scale/src2[i]) : 0;
798                 T z1 = src2[i+1] != 0 ? saturate_cast<T>(scale/src2[i+1]) : 0;
799                 T z2 = src2[i+2] != 0 ? saturate_cast<T>(scale/src2[i+2]) : 0;
800                 T z3 = src2[i+3] != 0 ? saturate_cast<T>(scale/src2[i+3]) : 0;
801
802                 dst[i] = z0; dst[i+1] = z1;
803                 dst[i+2] = z2; dst[i+3] = z3;
804             }
805         }
806
807         for( ; i < size.width; i++ )
808             dst[i] = src2[i] != 0 ? saturate_cast<T>(scale/src2[i]) : 0;
809     }
810 }
811
812 typedef void (*RecipFunc)( double scale, const Mat& src, Mat& dst );
813
814 void divide(double scale, const Mat& src, Mat& dst)
815 {
816     static RecipFunc tab[] =
817     {
818         recip_<uchar>, 0, recip_<ushort>, recip_<short>,
819         recip_<int>, recip_<float>, recip_<double>, 0
820     };
821
822     RecipFunc func = tab[src.depth()];
823     CV_Assert( func != 0 );
824     dst.create( src.size(), src.type() );
825     func( scale, src, dst );
826 }
827
828 /****************************************************************************************\
829 *                                      addWeighted                                       *
830 \****************************************************************************************/
831
832 template<typename T, typename WT> static void
833 addWeighted_( const Mat& srcmat1, double _alpha, const Mat& srcmat2,
834               double _beta, double _gamma, Mat& dstmat )
835 {
836     const T* src1 = (const T*)srcmat1.data;
837     const T* src2 = (const T*)srcmat2.data;
838     T* dst = (T*)dstmat.data;
839     size_t step1 = srcmat1.step/sizeof(src1[0]);
840     size_t step2 = srcmat2.step/sizeof(src2[0]);
841     size_t step = dstmat.step/sizeof(dst[0]);
842     Size size = getContinuousSize( srcmat1, srcmat2, dstmat, dstmat.channels() );
843     WT alpha = (WT)_alpha, beta = (WT)_beta, gamma = (WT)_gamma;
844
845     for( ; size.height--; src1+=step1, src2+=step2, dst+=step )
846     {
847         int i = 0;
848         for( ; i <= size.width - 4; i += 4 )
849         {
850             T t0 = saturate_cast<T>(src1[i]*alpha + src2[i]*beta + gamma);
851             T t1 = saturate_cast<T>(src1[i+1]*alpha + src2[i+1]*beta + gamma);
852             dst[i] = t0; dst[i+1] = t1;
853
854             t0 = saturate_cast<T>(src1[i+2]*alpha + src2[i+2]*beta + gamma);
855             t1 = saturate_cast<T>(src1[i+3]*alpha + src2[i+3]*beta + gamma);
856             dst[i+2] = t0; dst[i+3] = t1;
857         }
858
859         for( ; i < size.width; i++ )
860             dst[i] = saturate_cast<T>(src1[i]*alpha + src2[i]*beta + gamma);
861     }
862 }
863
864
865 static void
866 addWeighted8u( const Mat& srcmat1, double alpha,
867                const Mat& srcmat2, double beta,
868                double gamma, Mat& dstmat )
869 {
870     const int shift = 14;
871     if( srcmat1.rows*srcmat1.cols*srcmat1.channels() <= 256 ||
872         fabs(alpha) > 256 || fabs(beta) > 256 || fabs(gamma) > 256*256 )
873     {
874         addWeighted_<uchar, float>(srcmat1, alpha, srcmat2, beta, gamma, dstmat);
875         return;
876     }
877     const uchar* src1 = srcmat1.data;
878     const uchar* src2 = srcmat2.data;
879     uchar* dst = dstmat.data;
880     size_t step1 = srcmat1.step;
881     size_t step2 = srcmat2.step;
882     size_t step = dstmat.step;
883     Size size = getContinuousSize( srcmat1, srcmat2, dstmat, dstmat.channels() );
884
885     int tab1[256], tab2[256];
886     double t = 0;
887     int j, t0, t1, t2, t3;
888
889     alpha *= 1 << shift;
890     gamma = gamma*(1 << shift) + (1 << (shift - 1));
891     beta *= 1 << shift;
892
893     for( j = 0; j < 256; j++ )
894     {
895         tab1[j] = cvRound(t);
896         tab2[j] = cvRound(gamma);
897         t += alpha;
898         gamma += beta;
899     }
900
901     t0 = (tab1[0] + tab2[0]) >> shift;
902     t1 = (tab1[0] + tab2[255]) >> shift;
903     t2 = (tab1[255] + tab2[0]) >> shift;
904     t3 = (tab1[255] + tab2[255]) >> shift;
905
906     if( (unsigned)(t0+256) < 768 && (unsigned)(t1+256) < 768 &&
907         (unsigned)(t2+256) < 768 && (unsigned)(t3+256) < 768 )
908     {
909         // use faster table-based convertion back to 8u
910         for( ; size.height--; src1 += step1, src2 += step2, dst += step )
911         {
912             int i;
913
914             for( i = 0; i <= size.width - 4; i += 4 )
915             {
916                 t0 = CV_FAST_CAST_8U((tab1[src1[i]] + tab2[src2[i]]) >> shift);
917                 t1 = CV_FAST_CAST_8U((tab1[src1[i+1]] + tab2[src2[i+1]]) >> shift);
918
919                 dst[i] = (uchar)t0;
920                 dst[i+1] = (uchar)t1;
921
922                 t0 = CV_FAST_CAST_8U((tab1[src1[i+2]] + tab2[src2[i+2]]) >> shift);
923                 t1 = CV_FAST_CAST_8U((tab1[src1[i+3]] + tab2[src2[i+3]]) >> shift);
924
925                 dst[i+2] = (uchar)t0;
926                 dst[i+3] = (uchar)t1;
927             }
928
929             for( ; i < size.width; i++ )
930             {
931                 t0 = CV_FAST_CAST_8U((tab1[src1[i]] + tab2[src2[i]]) >> shift);
932                 dst[i] = (uchar)t0;
933             }
934         }
935     }
936     else
937     {
938         // use universal macro for convertion back to 8u
939         for( ; size.height--; src1 += step1, src2 += step2, dst += step )
940         {
941             int i;
942
943             for( i = 0; i <= size.width - 4; i += 4 )
944             {
945                 t0 = (tab1[src1[i]] + tab2[src2[i]]) >> shift;
946                 t1 = (tab1[src1[i+1]] + tab2[src2[i+1]]) >> shift;
947
948                 dst[i] = CV_CAST_8U( t0 );
949                 dst[i+1] = CV_CAST_8U( t1 );
950
951                 t0 = (tab1[src1[i+2]] + tab2[src2[i+2]]) >> shift;
952                 t1 = (tab1[src1[i+3]] + tab2[src2[i+3]]) >> shift;
953
954                 dst[i+2] = CV_CAST_8U( t0 );
955                 dst[i+3] = CV_CAST_8U( t1 );
956             }
957
958             for( ; i < size.width; i++ )
959             {
960                 t0 = (tab1[src1[i]] + tab2[src2[i]]) >> shift;
961                 dst[i] = CV_CAST_8U( t0 );
962             }
963         }
964     }
965 }
966
967 typedef void (*AddWeightedFunc)( const Mat& src1, double alpha, const Mat& src2,
968                                  double beta, double gamma, Mat& dst );
969
970 void addWeighted( const Mat& src1, double alpha, const Mat& src2,
971                   double beta, double gamma, Mat& dst )
972 {
973     static AddWeightedFunc tab[]=
974     {
975         addWeighted8u, 0, addWeighted_<ushort, float>, addWeighted_<short, float>,
976         addWeighted_<int, double>, addWeighted_<float, float>, addWeighted_<double, double>, 0
977     };
978
979     AddWeightedFunc func = tab[src1.depth()];
980     CV_Assert( src1.size() == src2.size() && src1.type() == src2.type() && func != 0 );
981     dst.create( src1.size(), src1.type() );
982     func( src1, alpha, src2, beta, gamma, dst );
983 }
984
985
986 /****************************************************************************************\
987 *                                      absdiff                                           *
988 \****************************************************************************************/
989
990 template<typename T> struct OpAbsDiff
991 {
992     typedef T type1;
993     typedef T type2;
994     typedef T rtype;
995     T operator()(T a, T b) { return (T)std::abs(a - b); }
996 };
997
998 template<> inline short OpAbsDiff<short>::operator ()(short a, short b)
999 { return saturate_cast<short>(std::abs(a - b)); }
1000
1001 template<typename T, typename WT=T> struct OpAbsDiffS
1002 {
1003     typedef T type1;
1004     typedef WT type2;
1005     typedef T rtype;
1006     T operator()(T a, WT b) { return saturate_cast<T>(std::abs(a - b)); }
1007 };
1008
1009 void absdiff( const Mat& src1, const Mat& src2, Mat& dst )
1010 {
1011     static BinaryFunc tab[] =
1012     {
1013         binaryOpC1_<OpAbsDiff<uchar>,VAbsDiff8u>, 0,
1014         binaryOpC1_<OpAbsDiff<ushort>,VAbsDiff16u>,
1015         binaryOpC1_<OpAbsDiff<short>,VAbsDiff16s>,
1016         binaryOpC1_<OpAbsDiff<int>,NoVec>,
1017         binaryOpC1_<OpAbsDiff<float>,VAbsDiff32f>,
1018         binaryOpC1_<OpAbsDiff<double>,NoVec>, 0
1019     };
1020
1021     dst.create(src1.size(), src1.type());
1022     BinaryFunc func = tab[src1.depth()];
1023     CV_Assert(src1.size() == src2.size() && src1.type() == src2.type() && func != 0);
1024     func( src1, src2, dst );
1025 }
1026
1027
1028 void absdiff( const Mat& src1, const Scalar& s, Mat& dst )
1029 {
1030     static BinarySFuncCn tab[] =
1031     {
1032         binarySOpCn_<OpAbsDiffS<uchar, int> >, 0,
1033         binarySOpCn_<OpAbsDiffS<ushort, int> >,
1034         binarySOpCn_<OpAbsDiffS<short, int> >,
1035         binarySOpCn_<OpAbsDiffS<int> >,
1036         binarySOpCn_<OpAbsDiffS<float> >,
1037         binarySOpCn_<OpAbsDiffS<double> >, 0
1038     };
1039
1040     dst.create(src1.size(), src1.type());
1041     BinarySFuncCn func = tab[src1.depth()];
1042     CV_Assert(src1.channels() <= 4 && func != 0);
1043     func( src1, dst, s );
1044 }
1045
1046 /****************************************************************************************\
1047 *                                      inRange[S]                                        *
1048 \****************************************************************************************/
1049
1050 template<typename T, typename WT> struct InRangeC1
1051 {
1052     typedef T xtype;
1053     typedef WT btype;
1054     uchar operator()(xtype x, btype a, btype b) const
1055     { return (uchar)-(a <= x && x < b); }
1056 };
1057
1058 template<typename T, typename WT> struct InRangeC2
1059 {
1060     typedef Vec<T,2> xtype;
1061     typedef Vec<WT,2> btype;
1062     uchar operator()(const xtype& x, const btype& a, const btype& b) const
1063     {
1064         return (uchar)-(a[0] <= x[0] && x[0] < b[0] &&
1065                         a[1] <= x[1] && x[1] < b[1]);
1066     }
1067 };
1068
1069 template<typename T, typename WT> struct InRangeC3
1070 {
1071     typedef Vec<T,3> xtype;
1072     typedef Vec<WT,3> btype;
1073     uchar operator()(const xtype& x, const btype& a, const btype& b) const
1074     {
1075         return (uchar)-(a[0] <= x[0] && x[0] < b[0] &&
1076                         a[1] <= x[1] && x[1] < b[1] &&
1077                         a[2] <= x[2] && x[2] < b[2]);
1078     }
1079 };
1080
1081 template<typename T, typename WT> struct InRangeC4
1082 {
1083     typedef Vec<T,4> xtype;
1084     typedef Vec<WT,4> btype;
1085     uchar operator()(const xtype& x, const btype& a, const btype& b) const
1086     {
1087         return (uchar)-(a[0] <= x[0] && x[0] < b[0] &&
1088                         a[1] <= x[1] && x[1] < b[1] &&
1089                         a[2] <= x[2] && x[2] < b[2] &&
1090                         a[3] <= x[3] && x[3] < b[3]);
1091     }
1092 };
1093
1094 template<class Op> static void
1095 inRange_( const Mat& srcmat1, const Mat& srcmat2, const Mat& srcmat3, Mat& dstmat )
1096 {
1097     Op op;
1098     uchar* dst = dstmat.data;
1099     size_t dstep = dstmat.step;
1100     Size size = getContinuousSize( srcmat1, srcmat2, srcmat3, dstmat );
1101
1102     for( int y = 0; y < size.height; y++, dst += dstep )
1103     {
1104         const typename Op::xtype* src1 = (const typename Op::xtype*)(srcmat1.data + srcmat1.step*y);
1105         const typename Op::xtype* src2 = (const typename Op::xtype*)(srcmat2.data + srcmat2.step*y);
1106         const typename Op::xtype* src3 = (const typename Op::xtype*)(srcmat3.data + srcmat3.step*y);
1107         for( int x = 0; x < size.width; x++ )
1108             dst[x] = op( src1[x], src2[x], src3[x] );
1109     }
1110 }
1111
1112 template<class Op> static void
1113 inRangeS_( const Mat& srcmat1, const Scalar& _a, const Scalar& _b, Mat& dstmat )
1114 {
1115     Op op;
1116     typedef typename Op::btype WT;
1117     typedef typename DataType<WT>::channel_type WT1;
1118     WT a, b;
1119     uchar* dst = dstmat.data;
1120     size_t dstep = dstmat.step;
1121     Size size = getContinuousSize( srcmat1, dstmat );
1122     int cn = srcmat1.channels();
1123     _a.convertTo((WT1*)&a, cn);
1124     _b.convertTo((WT1*)&b, cn);
1125
1126     for( int y = 0; y < size.height; y++, dst += dstep )
1127     {
1128         const typename Op::xtype* src1 = (const typename Op::xtype*)(srcmat1.data + srcmat1.step*y);
1129         for( int x = 0; x < size.width; x++ )
1130             dst[x] = op( src1[x], a, b );
1131     }
1132 }
1133
1134 typedef void (*InRangeFunc)( const Mat& src1, const Mat& src2, const Mat& src3, Mat& dst );
1135 typedef void (*InRangeSFunc)( const Mat& src1, const Scalar& a, const Scalar& b, Mat& dst );
1136
1137 void inRange(const Mat& src, const Mat& lowerb,
1138              const Mat& upperb, Mat& dst)
1139 {
1140     static InRangeFunc tab[] =
1141     {
1142         inRange_<InRangeC1<uchar, uchar> >, 0,
1143         inRange_<InRangeC1<ushort, ushort> >,
1144         inRange_<InRangeC1<short, short> >,
1145         inRange_<InRangeC1<int, int> >,
1146         inRange_<InRangeC1<float, float> >,
1147         inRange_<InRangeC1<double, double> >, 0,
1148
1149         inRange_<InRangeC2<uchar, uchar> >, 0,
1150         inRange_<InRangeC2<ushort, ushort> >,
1151         inRange_<InRangeC2<short, short> >,
1152         inRange_<InRangeC2<int, int> >,
1153         inRange_<InRangeC2<float, float> >,
1154         inRange_<InRangeC2<double, double> >, 0,
1155
1156         inRange_<InRangeC3<uchar, uchar> >, 0,
1157         inRange_<InRangeC3<ushort, ushort> >,
1158         inRange_<InRangeC3<short, short> >,
1159         inRange_<InRangeC3<int, int> >,
1160         inRange_<InRangeC3<float, float> >,
1161         inRange_<InRangeC3<double, double> >, 0,
1162
1163         inRange_<InRangeC4<uchar, uchar> >, 0,
1164         inRange_<InRangeC4<ushort, ushort> >,
1165         inRange_<InRangeC4<short, short> >,
1166         inRange_<InRangeC4<int, int> >,
1167         inRange_<InRangeC4<float, float> >,
1168         inRange_<InRangeC4<double, double> >, 0
1169     };
1170
1171     CV_Assert( src.size() == lowerb.size() && src.size() == upperb.size() &&
1172         src.type() == lowerb.type() && src.type() == upperb.type() &&
1173         src.channels() <= 4 );
1174
1175     InRangeFunc func = tab[src.type()];
1176     CV_Assert( func != 0 );
1177
1178     dst.create(src.size(), CV_8U);
1179     func( src, lowerb, upperb, dst );
1180 }
1181
1182 void inRange(const Mat& src, const Scalar& lowerb,
1183              const Scalar& upperb, Mat& dst)
1184 {
1185     static InRangeSFunc tab[] =
1186     {
1187         inRangeS_<InRangeC1<uchar, int> >, 0,
1188         inRangeS_<InRangeC1<ushort, int> >,
1189         inRangeS_<InRangeC1<short, int> >,
1190         inRangeS_<InRangeC1<int, int> >,
1191         inRangeS_<InRangeC1<float, float> >,
1192         inRangeS_<InRangeC1<double, double> >, 0,
1193
1194         inRangeS_<InRangeC2<uchar, int> >, 0,
1195         inRangeS_<InRangeC2<ushort, int> >,
1196         inRangeS_<InRangeC2<short, int> >,
1197         inRangeS_<InRangeC2<int, int> >,
1198         inRangeS_<InRangeC2<float, float> >,
1199         inRangeS_<InRangeC2<double, double> >, 0,
1200
1201         inRangeS_<InRangeC3<uchar, int> >, 0,
1202         inRangeS_<InRangeC3<ushort, int> >,
1203         inRangeS_<InRangeC3<short, int> >,
1204         inRangeS_<InRangeC3<int, int> >,
1205         inRangeS_<InRangeC3<float, float> >,
1206         inRangeS_<InRangeC3<double, double> >, 0,
1207
1208         inRangeS_<InRangeC4<uchar, int> >, 0,
1209         inRangeS_<InRangeC4<ushort, int> >,
1210         inRangeS_<InRangeC4<short, int> >,
1211         inRangeS_<InRangeC4<int, int> >,
1212         inRangeS_<InRangeC4<float, float> >,
1213         inRangeS_<InRangeC4<double, double> >, 0
1214     };
1215
1216     CV_Assert( src.channels() <= 4 );
1217
1218     InRangeSFunc func = tab[src.type()];
1219     CV_Assert( func != 0 );
1220
1221     dst.create(src.size(), CV_8U);
1222     func( src, lowerb, upperb, dst );
1223 }
1224
1225 /****************************************************************************************\
1226 *                                          compare                                       *
1227 \****************************************************************************************/
1228
1229 template<typename T, typename WT=T> struct CmpEQ
1230 {
1231     typedef T type1;
1232     typedef WT type2;
1233     typedef uchar rtype;
1234     uchar operator()(T a, WT b) const { return (uchar)-(a == b); }
1235 };
1236
1237 template<typename T, typename WT=T> struct CmpGT
1238 {
1239     typedef T type1;
1240     typedef WT type2;
1241     typedef uchar rtype;
1242     uchar operator()(T a, WT b) const { return (uchar)-(a > b); }
1243 };
1244
1245 template<typename T, typename WT=T> struct CmpGE
1246 {
1247     typedef T type1;
1248     typedef WT type2;
1249     typedef uchar rtype;
1250     uchar operator()(T a, WT b) const { return (uchar)-(a >= b); }
1251 };
1252
1253 void compare( const Mat& src1, const Mat& src2, Mat& dst, int cmpOp )
1254 {
1255     static BinaryFunc tab[][8] =
1256     {
1257         {binaryOpC1_<CmpGT<uchar>,VCmpGT8u>, 0,
1258         binaryOpC1_<CmpGT<ushort>,NoVec>,
1259         binaryOpC1_<CmpGT<short>,NoVec>,
1260         binaryOpC1_<CmpGT<int>,NoVec>,
1261         binaryOpC1_<CmpGT<float>,NoVec>,
1262         binaryOpC1_<CmpGT<double>,NoVec>, 0},
1263
1264         {binaryOpC1_<CmpEQ<uchar>,VCmpEQ8u>, 0,
1265         binaryOpC1_<CmpEQ<ushort>,NoVec>,
1266         binaryOpC1_<CmpEQ<ushort>,NoVec>, // same function as for ushort's
1267         binaryOpC1_<CmpEQ<int>,NoVec>,
1268         binaryOpC1_<CmpEQ<float>,NoVec>,
1269         binaryOpC1_<CmpEQ<double>,NoVec>, 0},
1270     };
1271
1272     dst.create(src1.rows, src1.cols, CV_8U);
1273     CV_Assert(src1.size() == src2.size() && src1.type() == src2.type() && src1.channels() == 1);
1274
1275     int depth = src1.depth();
1276     const Mat *psrc1 = &src1, *psrc2 = &src2;
1277     bool invflag = false;
1278
1279     switch( cmpOp )
1280     {
1281     case CMP_GT:
1282     case CMP_EQ:
1283         break;
1284     case CMP_GE:
1285         std::swap( psrc1, psrc2 );
1286         invflag = true;
1287         break;
1288     case CMP_LT:
1289         std::swap( psrc1, psrc2 );
1290         break;
1291     case CMP_LE:
1292         invflag = true;
1293         break;
1294     case CMP_NE:
1295         cmpOp = CMP_EQ;
1296         invflag = true;
1297         break;
1298     default:
1299         CV_Error(CV_StsBadArg, "Unknown comparison method");
1300     }
1301
1302     BinaryFunc func = tab[cmpOp == CMP_EQ][depth];
1303     CV_Assert( func != 0 );
1304     func( *psrc1, *psrc2, dst );
1305     if( invflag )
1306         bitwise_not(dst, dst);
1307 }
1308
1309
1310 void compare( const Mat& src1, double value, Mat& dst, int cmpOp )
1311 {
1312     static BinarySFuncC1 tab[][8] =
1313     {
1314         {binarySOpC1_<CmpEQ<uchar, int> >, 0,
1315         binarySOpC1_<CmpEQ<ushort, int> >,
1316         binarySOpC1_<CmpEQ<short, int> >,
1317         binarySOpC1_<CmpEQ<int> >,
1318         binarySOpC1_<CmpEQ<float> >,
1319         binarySOpC1_<CmpEQ<double> >, 0},
1320
1321         {binarySOpC1_<CmpGT<uchar, int> >, 0,
1322         binarySOpC1_<CmpGT<ushort, int> >,
1323         binarySOpC1_<CmpGT<short, int> >,
1324         binarySOpC1_<CmpGT<int> >,
1325         binarySOpC1_<CmpGT<float> >,
1326         binarySOpC1_<CmpGT<double> >, 0},
1327
1328         {binarySOpC1_<CmpGE<uchar, int> >, 0,
1329         binarySOpC1_<CmpGE<ushort, int> >,
1330         binarySOpC1_<CmpGE<short, int> >,
1331         binarySOpC1_<CmpGE<int> >,
1332         binarySOpC1_<CmpGE<float> >,
1333         binarySOpC1_<CmpGE<double> >, 0},
1334     };
1335
1336     dst.create(src1.rows, src1.cols, CV_8U);
1337     CV_Assert(src1.channels() == 1);
1338     int depth = src1.depth();
1339     bool invflag = false;
1340
1341     switch( cmpOp )
1342     {
1343     case CMP_GT:
1344     case CMP_EQ:
1345     case CMP_GE:
1346         break;
1347     case CMP_LT:
1348         invflag = true;
1349         cmpOp = CMP_GE;
1350         break;
1351     case CMP_LE:
1352         invflag = true;
1353         cmpOp = CMP_GT;
1354         break;
1355     case CMP_NE:
1356         invflag = true;
1357         cmpOp = CMP_EQ;
1358         break;
1359     default:
1360         CV_Error(CV_StsBadArg, "Unknown comparison method");
1361     }
1362
1363     BinarySFuncC1 func = tab[cmpOp == CMP_EQ ? 0 : cmpOp == CMP_GT ? 1 : 2][depth];
1364     CV_Assert( func != 0 );
1365     func( src1, dst, value );
1366     if( invflag )
1367         bitwise_not(dst, dst);
1368 }
1369
1370 /****************************************************************************************\
1371 *                                       min/max                                          *
1372 \****************************************************************************************/
1373
1374 template<typename T> struct MinOp
1375 {
1376     typedef T type1;
1377     typedef T type2;
1378     typedef T rtype;
1379     T operator ()(T a, T b) const { return std::min(a, b); }
1380 };
1381
1382 template<typename T> struct MaxOp
1383 {
1384     typedef T type1;
1385     typedef T type2;
1386     typedef T rtype;
1387     T operator ()(T a, T b) const { return std::max(a, b); }
1388 };
1389
1390 template<> inline uchar MinOp<uchar>::operator ()(uchar a, uchar b) const { return CV_MIN_8U(a, b); }
1391 template<> inline uchar MaxOp<uchar>::operator ()(uchar a, uchar b) const { return CV_MAX_8U(a, b); }
1392
1393 void min( const Mat& src1, const Mat& src2, Mat& dst )
1394 {
1395     static BinaryFunc tab[] =
1396     {
1397         binaryOpC1_<MinOp<uchar>,VMin8u>, 0, binaryOpC1_<MinOp<ushort>,VMin16u>,
1398         binaryOpC1_<MinOp<short>,VMin16s>, binaryOpC1_<MinOp<int>,NoVec>,
1399         binaryOpC1_<MinOp<float>,VMin32f>, binaryOpC1_<MinOp<double>,NoVec>, 0
1400     };
1401
1402     BinaryFunc func = tab[src1.depth()];
1403     CV_Assert(src1.size() == src2.size() && src1.type() == src2.type() && func != 0);
1404     dst.create(src1.size(), src1.type());
1405
1406     return func( src1, src2, dst );
1407 }
1408
1409 void max( const Mat& src1, const Mat& src2, Mat& dst )
1410 {
1411     static BinaryFunc tab[] =
1412     {
1413         binaryOpC1_<MaxOp<uchar>,VMax8u>, 0, binaryOpC1_<MaxOp<ushort>,VMax16u>,
1414         binaryOpC1_<MaxOp<short>,VMax16s>, binaryOpC1_<MaxOp<int>,NoVec>,
1415         binaryOpC1_<MaxOp<float>,VMax32f>, binaryOpC1_<MaxOp<double>,NoVec>, 0
1416     };
1417
1418     BinaryFunc func = tab[src1.depth()];
1419     CV_Assert(src1.size() == src2.size() && src1.type() == src2.type() && func != 0);
1420     dst.create(src1.size(), src1.type());
1421
1422     return func( src1, src2, dst );
1423 }
1424
1425 void min( const Mat& src1, double value, Mat& dst )
1426 {
1427     static BinarySFuncC1 tab[] =
1428     {
1429         binarySOpC1_<MinOp<uchar> >, 0,
1430         binarySOpC1_<MinOp<ushort> >,
1431         binarySOpC1_<MinOp<short> >,
1432         binarySOpC1_<MinOp<int> >,
1433         binarySOpC1_<MinOp<float> >,
1434         binarySOpC1_<MinOp<double> >, 0
1435     };
1436
1437     BinarySFuncC1 func = tab[src1.depth()];
1438     CV_Assert(func != 0);
1439     dst.create(src1.size(), src1.type());
1440     return func( src1, dst, value );
1441 }
1442
1443 void max( const Mat& src1, double value, Mat& dst )
1444 {
1445     static BinarySFuncC1 tab[] =
1446     {
1447         binarySOpC1_<MaxOp<uchar> >, 0,
1448         binarySOpC1_<MaxOp<ushort> >,
1449         binarySOpC1_<MaxOp<short> >,
1450         binarySOpC1_<MaxOp<int> >,
1451         binarySOpC1_<MaxOp<float> >,
1452         binarySOpC1_<MaxOp<double> >, 0
1453     };
1454
1455     BinarySFuncC1 func = tab[src1.depth()];
1456     CV_Assert(func != 0);
1457     dst.create(src1.size(), src1.type());
1458     return func( src1, dst, value );
1459 }
1460
1461 }
1462
1463 /****************************************************************************************\
1464 *                                Earlier API: cvAdd etc.                                 *
1465 \****************************************************************************************/
1466
1467 CV_IMPL void
1468 cvNot( const CvArr* srcarr, CvArr* dstarr )
1469 {
1470     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
1471     CV_Assert( src.size() == dst.size() && src.type() == dst.type() );
1472     cv::bitwise_not( src, dst );
1473 }
1474
1475
1476 CV_IMPL void
1477 cvAnd( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr, const CvArr* maskarr )
1478 {
1479     cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2),
1480         dst = cv::cvarrToMat(dstarr), mask;
1481     CV_Assert( src1.size() == dst.size() && src1.type() == dst.type() );
1482     if( maskarr )
1483         mask = cv::cvarrToMat(maskarr);
1484     cv::bitwise_and( src1, src2, dst, mask );
1485 }
1486
1487 CV_IMPL void
1488 cvOr( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr, const CvArr* maskarr )
1489 {
1490     cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2),
1491         dst = cv::cvarrToMat(dstarr), mask;
1492     CV_Assert( src1.size() == dst.size() && src1.type() == dst.type() );
1493     if( maskarr )
1494         mask = cv::cvarrToMat(maskarr);
1495     cv::bitwise_or( src1, src2, dst, mask );
1496 }
1497
1498
1499 CV_IMPL void
1500 cvXor( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr, const CvArr* maskarr )
1501 {
1502     cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2),
1503         dst = cv::cvarrToMat(dstarr), mask;
1504     CV_Assert( src1.size() == dst.size() && src1.type() == dst.type() );
1505     if( maskarr )
1506         mask = cv::cvarrToMat(maskarr);
1507     cv::bitwise_xor( src1, src2, dst, mask );
1508 }
1509
1510
1511 CV_IMPL void
1512 cvAndS( const CvArr* srcarr, CvScalar s, CvArr* dstarr, const CvArr* maskarr )
1513 {
1514     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), mask;
1515     CV_Assert( src.size() == dst.size() && src.type() == dst.type() );
1516     if( maskarr )
1517         mask = cv::cvarrToMat(maskarr);
1518     cv::bitwise_and( src, s, dst, mask );
1519 }
1520
1521
1522 CV_IMPL void
1523 cvOrS( const CvArr* srcarr, CvScalar s, CvArr* dstarr, const CvArr* maskarr )
1524 {
1525     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), mask;
1526     CV_Assert( src.size() == dst.size() && src.type() == dst.type() );
1527     if( maskarr )
1528         mask = cv::cvarrToMat(maskarr);
1529     cv::bitwise_or( src, s, dst, mask );
1530 }
1531
1532
1533 CV_IMPL void
1534 cvXorS( const CvArr* srcarr, CvScalar s, CvArr* dstarr, const CvArr* maskarr )
1535 {
1536     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), mask;
1537     CV_Assert( src.size() == dst.size() && src.type() == dst.type() );
1538     if( maskarr )
1539         mask = cv::cvarrToMat(maskarr);
1540     cv::bitwise_xor( src, s, dst, mask );
1541 }
1542
1543 CV_IMPL void cvAdd( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr, const CvArr* maskarr )
1544 {
1545     cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2),
1546         dst = cv::cvarrToMat(dstarr), mask;
1547     CV_Assert( src1.size() == dst.size() && src1.type() == dst.type() );
1548     if( maskarr )
1549         mask = cv::cvarrToMat(maskarr);
1550     cv::add( src1, src2, dst, mask );
1551 }
1552
1553 CV_IMPL void cvSub( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr, const CvArr* maskarr )
1554 {
1555     cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2),
1556         dst = cv::cvarrToMat(dstarr), mask;
1557     CV_Assert( src1.size() == dst.size() && src1.type() == dst.type() );
1558     if( maskarr )
1559         mask = cv::cvarrToMat(maskarr);
1560     cv::subtract( src1, src2, dst, mask );
1561 }
1562
1563 CV_IMPL void cvAddS( const CvArr* srcarr1, CvScalar value, CvArr* dstarr, const CvArr* maskarr )
1564 {
1565     cv::Mat src1 = cv::cvarrToMat(srcarr1),
1566         dst = cv::cvarrToMat(dstarr), mask;
1567     CV_Assert( src1.size() == dst.size() && src1.type() == dst.type() );
1568     if( maskarr )
1569         mask = cv::cvarrToMat(maskarr);
1570     cv::add( src1, value, dst, mask );
1571 }
1572
1573 CV_IMPL void cvSubRS( const CvArr* srcarr1, CvScalar value, CvArr* dstarr, const CvArr* maskarr )
1574 {
1575     cv::Mat src1 = cv::cvarrToMat(srcarr1),
1576         dst = cv::cvarrToMat(dstarr), mask;
1577     CV_Assert( src1.size() == dst.size() && src1.type() == dst.type() );
1578     if( maskarr )
1579         mask = cv::cvarrToMat(maskarr);
1580     cv::subtract( value, src1, dst, mask );
1581 }
1582
1583 CV_IMPL void cvMul( const CvArr* srcarr1, const CvArr* srcarr2,
1584                     CvArr* dstarr, double scale )
1585 {
1586     cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2),
1587         dst = cv::cvarrToMat(dstarr);
1588     CV_Assert( src1.size() == dst.size() && src1.type() == dst.type() );
1589     cv::multiply( src1, src2, dst, scale );
1590 }
1591
1592 CV_IMPL void cvDiv( const CvArr* srcarr1, const CvArr* srcarr2,
1593                     CvArr* dstarr, double scale )
1594 {
1595     cv::Mat src2 = cv::cvarrToMat(srcarr2),
1596         dst = cv::cvarrToMat(dstarr), mask;
1597     CV_Assert( src2.size() == dst.size() && src2.type() == dst.type() );
1598
1599     if( srcarr1 )
1600         cv::divide( cv::cvarrToMat(srcarr1), src2, dst, scale );
1601     else
1602         cv::divide( scale, src2, dst );
1603 }
1604
1605
1606 CV_IMPL void
1607 cvAddWeighted( const CvArr* srcarr1, double alpha,
1608                const CvArr* srcarr2, double beta,
1609                double gamma, CvArr* dstarr )
1610 {
1611     cv::Mat src1 = cv::cvarrToMat(srcarr1), src2 = cv::cvarrToMat(srcarr2),
1612         dst = cv::cvarrToMat(dstarr);
1613     CV_Assert( src1.size() == dst.size() && src1.type() == dst.type() );
1614     cv::addWeighted( src1, alpha, src2, beta, gamma, dst );
1615 }
1616
1617
1618 CV_IMPL  void
1619 cvAbsDiff( const CvArr* srcarr1, const CvArr* srcarr2, CvArr* dstarr )
1620 {
1621     cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
1622     CV_Assert( src1.size() == dst.size() && src1.type() == dst.type() );
1623
1624     cv::absdiff( src1, cv::cvarrToMat(srcarr2), dst );
1625 }
1626
1627
1628 CV_IMPL void
1629 cvAbsDiffS( const CvArr* srcarr1, CvArr* dstarr, CvScalar scalar )
1630 {
1631     cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
1632     CV_Assert( src1.size() == dst.size() && src1.type() == dst.type() );
1633
1634     cv::absdiff( src1, scalar, dst );
1635 }
1636
1637 CV_IMPL void
1638 cvInRange( const void* srcarr1, const void* srcarr2,
1639            const void* srcarr3, void* dstarr )
1640 {
1641     cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
1642     CV_Assert( src1.size() == dst.size() && dst.type() == CV_8U );
1643
1644     cv::inRange( src1, cv::cvarrToMat(srcarr2), cv::cvarrToMat(srcarr3), dst );
1645 }
1646
1647 CV_IMPL void
1648 cvInRangeS( const void* srcarr1, CvScalar lowerb, CvScalar upperb, void* dstarr )
1649 {
1650     cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
1651     CV_Assert( src1.size() == dst.size() && dst.type() == CV_8U );
1652
1653     cv::inRange( src1, lowerb, upperb, dst );
1654 }
1655
1656
1657 CV_IMPL void
1658 cvCmp( const void* srcarr1, const void* srcarr2, void* dstarr, int cmp_op )
1659 {
1660     cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
1661     CV_Assert( src1.size() == dst.size() && dst.type() == CV_8U );
1662
1663     cv::compare( src1, cv::cvarrToMat(srcarr2), dst, cmp_op );
1664 }
1665
1666
1667 CV_IMPL void
1668 cvCmpS( const void* srcarr1, double value, void* dstarr, int cmp_op )
1669 {
1670     cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
1671     CV_Assert( src1.size() == dst.size() && dst.type() == CV_8U );
1672
1673     cv::compare( src1, value, dst, cmp_op );
1674 }
1675
1676
1677 CV_IMPL void
1678 cvMin( const void* srcarr1, const void* srcarr2, void* dstarr )
1679 {
1680     cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
1681     CV_Assert( src1.size() == dst.size() && src1.type() == dst.type() );
1682
1683     cv::min( src1, cv::cvarrToMat(srcarr2), dst );
1684 }
1685
1686
1687 CV_IMPL void
1688 cvMax( const void* srcarr1, const void* srcarr2, void* dstarr )
1689 {
1690     cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
1691     CV_Assert( src1.size() == dst.size() && src1.type() == dst.type() );
1692
1693     cv::max( src1, cv::cvarrToMat(srcarr2), dst );
1694 }
1695
1696 CV_IMPL void
1697 cvMinS( const void* srcarr1, double value, void* dstarr )
1698 {
1699     cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
1700     CV_Assert( src1.size() == dst.size() && src1.type() == dst.type() );
1701
1702     cv::min( src1, value, dst );
1703 }
1704
1705
1706 CV_IMPL void
1707 cvMaxS( const void* srcarr1, double value, void* dstarr )
1708 {
1709     cv::Mat src1 = cv::cvarrToMat(srcarr1), dst = cv::cvarrToMat(dstarr);
1710     CV_Assert( src1.size() == dst.size() && src1.type() == dst.type() );
1711
1712     cv::max( src1, value, dst );
1713 }
1714
1715
1716 /* End of file. */