CLAHE Python bindings
[profile/ivi/opencv.git] / modules / core / test / test_arithm.cpp
1 #include "test_precomp.hpp"
2
3 using namespace cv;
4 using namespace std;
5
6 namespace cvtest
7 {
8
9 const int ARITHM_NTESTS = 1000;
10 const int ARITHM_RNG_SEED = -1;
11 const int ARITHM_MAX_CHANNELS = 4;
12 const int ARITHM_MAX_NDIMS = 4;
13 const int ARITHM_MAX_SIZE_LOG = 10;
14
15 struct BaseElemWiseOp
16 {
17     enum { FIX_ALPHA=1, FIX_BETA=2, FIX_GAMMA=4, REAL_GAMMA=8, SUPPORT_MASK=16, SCALAR_OUTPUT=32 };
18     BaseElemWiseOp(int _ninputs, int _flags, double _alpha, double _beta,
19                    Scalar _gamma=Scalar::all(0), int _context=1)
20     : ninputs(_ninputs), flags(_flags), alpha(_alpha), beta(_beta), gamma(_gamma), context(_context) {}
21     BaseElemWiseOp() { flags = 0; alpha = beta = 0; gamma = Scalar::all(0); }
22     virtual ~BaseElemWiseOp() {}
23     virtual void op(const vector<Mat>&, Mat&, const Mat&) {}
24     virtual void refop(const vector<Mat>&, Mat&, const Mat&) {}
25     virtual void getValueRange(int depth, double& minval, double& maxval)
26     {
27         minval = depth < CV_32S ? cvtest::getMinVal(depth) : depth == CV_32S ? -1000000 : -1000.;
28         maxval = depth < CV_32S ? cvtest::getMaxVal(depth) : depth == CV_32S ? 1000000 : 1000.;
29     }
30
31     virtual void getRandomSize(RNG& rng, vector<int>& size)
32     {
33         cvtest::randomSize(rng, 2, ARITHM_MAX_NDIMS, cvtest::ARITHM_MAX_SIZE_LOG, size);
34     }
35
36     virtual int getRandomType(RNG& rng)
37     {
38         return cvtest::randomType(rng, DEPTH_MASK_ALL_BUT_8S, 1,
39                                   ninputs > 1 ? ARITHM_MAX_CHANNELS : 4);
40     }
41
42     virtual double getMaxErr(int depth) { return depth < CV_32F ? 1 : depth == CV_32F ? 1e-5 : 1e-12; }
43     virtual void generateScalars(int depth, RNG& rng)
44     {
45         const double m = 3.;
46
47         if( !(flags & FIX_ALPHA) )
48         {
49             alpha = exp(rng.uniform(-0.5, 0.1)*m*2*CV_LOG2);
50             alpha *= rng.uniform(0, 2) ? 1 : -1;
51         }
52         if( !(flags & FIX_BETA) )
53         {
54             beta = exp(rng.uniform(-0.5, 0.1)*m*2*CV_LOG2);
55             beta *= rng.uniform(0, 2) ? 1 : -1;
56         }
57
58         if( !(flags & FIX_GAMMA) )
59         {
60             for( int i = 0; i < 4; i++ )
61             {
62                 gamma[i] = exp(rng.uniform(-1, 6)*m*CV_LOG2);
63                 gamma[i] *= rng.uniform(0, 2) ? 1 : -1;
64             }
65             if( flags & REAL_GAMMA )
66                 gamma = Scalar::all(gamma[0]);
67         }
68
69         if( depth == CV_32F )
70         {
71             Mat fl, db;
72
73             db = Mat(1, 1, CV_64F, &alpha);
74             db.convertTo(fl, CV_32F);
75             fl.convertTo(db, CV_64F);
76
77             db = Mat(1, 1, CV_64F, &beta);
78             db.convertTo(fl, CV_32F);
79             fl.convertTo(db, CV_64F);
80
81             db = Mat(1, 4, CV_64F, &gamma[0]);
82             db.convertTo(fl, CV_32F);
83             fl.convertTo(db, CV_64F);
84         }
85     }
86
87     int ninputs;
88     int flags;
89     double alpha;
90     double beta;
91     Scalar gamma;
92     int maxErr;
93     int context;
94 };
95
96
97 struct BaseAddOp : public BaseElemWiseOp
98 {
99     BaseAddOp(int _ninputs, int _flags, double _alpha, double _beta, Scalar _gamma=Scalar::all(0))
100     : BaseElemWiseOp(_ninputs, _flags, _alpha, _beta, _gamma) {}
101
102     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
103     {
104         Mat temp;
105         if( !mask.empty() )
106         {
107             cvtest::add(src[0], alpha, src.size() > 1 ? src[1] : Mat(), beta, gamma, temp, src[0].type());
108             cvtest::copy(temp, dst, mask);
109         }
110         else
111             cvtest::add(src[0], alpha, src.size() > 1 ? src[1] : Mat(), beta, gamma, dst, src[0].type());
112     }
113 };
114
115
116 struct AddOp : public BaseAddOp
117 {
118     AddOp() : BaseAddOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)) {};
119     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
120     {
121         if( mask.empty() )
122             add(src[0], src[1], dst);
123         else
124             add(src[0], src[1], dst, mask);
125     }
126 };
127
128
129 struct SubOp : public BaseAddOp
130 {
131     SubOp() : BaseAddOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, -1, Scalar::all(0)) {};
132     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
133     {
134         if( mask.empty() )
135             subtract(src[0], src[1], dst);
136         else
137             subtract(src[0], src[1], dst, mask);
138     }
139 };
140
141
142 struct AddSOp : public BaseAddOp
143 {
144     AddSOp() : BaseAddOp(1, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, 1, 0, Scalar::all(0)) {};
145     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
146     {
147         if( mask.empty() )
148             add(src[0], gamma, dst);
149         else
150             add(src[0], gamma, dst, mask);
151     }
152 };
153
154
155 struct SubRSOp : public BaseAddOp
156 {
157     SubRSOp() : BaseAddOp(1, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, -1, 0, Scalar::all(0)) {};
158     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
159     {
160         if( mask.empty() )
161             subtract(gamma, src[0], dst);
162         else
163             subtract(gamma, src[0], dst, mask);
164     }
165 };
166
167
168 struct ScaleAddOp : public BaseAddOp
169 {
170     ScaleAddOp() : BaseAddOp(2, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
171     void op(const vector<Mat>& src, Mat& dst, const Mat&)
172     {
173         scaleAdd(src[0], alpha, src[1], dst);
174     }
175     double getMaxErr(int depth)
176     {
177         return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-4 : 1e-12;
178     }
179 };
180
181
182 struct AddWeightedOp : public BaseAddOp
183 {
184     AddWeightedOp() : BaseAddOp(2, REAL_GAMMA, 1, 1, Scalar::all(0)) {};
185     void op(const vector<Mat>& src, Mat& dst, const Mat&)
186     {
187         addWeighted(src[0], alpha, src[1], beta, gamma[0], dst);
188     }
189     double getMaxErr(int depth)
190     {
191         return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-10;
192     }
193 };
194
195 struct MulOp : public BaseElemWiseOp
196 {
197     MulOp() : BaseElemWiseOp(2, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
198     void getValueRange(int depth, double& minval, double& maxval)
199     {
200         minval = depth < CV_32S ? cvtest::getMinVal(depth) : depth == CV_32S ? -1000000 : -1000.;
201         maxval = depth < CV_32S ? cvtest::getMaxVal(depth) : depth == CV_32S ? 1000000 : 1000.;
202         minval = std::max(minval, -30000.);
203         maxval = std::min(maxval, 30000.);
204     }
205     void op(const vector<Mat>& src, Mat& dst, const Mat&)
206     {
207         cv::multiply(src[0], src[1], dst, alpha);
208     }
209     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
210     {
211         cvtest::multiply(src[0], src[1], dst, alpha);
212     }
213     double getMaxErr(int depth)
214     {
215         return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12;
216     }
217 };
218
219 struct DivOp : public BaseElemWiseOp
220 {
221     DivOp() : BaseElemWiseOp(2, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
222     void op(const vector<Mat>& src, Mat& dst, const Mat&)
223     {
224         cv::divide(src[0], src[1], dst, alpha);
225     }
226     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
227     {
228         cvtest::divide(src[0], src[1], dst, alpha);
229     }
230     double getMaxErr(int depth)
231     {
232         return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12;
233     }
234 };
235
236 struct RecipOp : public BaseElemWiseOp
237 {
238     RecipOp() : BaseElemWiseOp(1, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
239     void op(const vector<Mat>& src, Mat& dst, const Mat&)
240     {
241         cv::divide(alpha, src[0], dst);
242     }
243     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
244     {
245         cvtest::divide(Mat(), src[0], dst, alpha);
246     }
247     double getMaxErr(int depth)
248     {
249         return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12;
250     }
251 };
252
253 struct AbsDiffOp : public BaseAddOp
254 {
255     AbsDiffOp() : BaseAddOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, -1, Scalar::all(0)) {};
256     void op(const vector<Mat>& src, Mat& dst, const Mat&)
257     {
258         absdiff(src[0], src[1], dst);
259     }
260     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
261     {
262         cvtest::add(src[0], 1, src[1], -1, Scalar::all(0), dst, src[0].type(), true);
263     }
264 };
265
266 struct AbsDiffSOp : public BaseAddOp
267 {
268     AbsDiffSOp() : BaseAddOp(1, FIX_ALPHA+FIX_BETA, 1, 0, Scalar::all(0)) {};
269     void op(const vector<Mat>& src, Mat& dst, const Mat&)
270     {
271         absdiff(src[0], gamma, dst);
272     }
273     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
274     {
275         cvtest::add(src[0], 1, Mat(), 0, -gamma, dst, src[0].type(), true);
276     }
277 };
278
279 struct LogicOp : public BaseElemWiseOp
280 {
281     LogicOp(char _opcode) : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)), opcode(_opcode) {};
282     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
283     {
284         if( opcode == '&' )
285             bitwise_and(src[0], src[1], dst, mask);
286         else if( opcode == '|' )
287             bitwise_or(src[0], src[1], dst, mask);
288         else
289             bitwise_xor(src[0], src[1], dst, mask);
290     }
291     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
292     {
293         Mat temp;
294         if( !mask.empty() )
295         {
296             cvtest::logicOp(src[0], src[1], temp, opcode);
297             cvtest::copy(temp, dst, mask);
298         }
299         else
300             cvtest::logicOp(src[0], src[1], dst, opcode);
301     }
302     double getMaxErr(int)
303     {
304         return 0;
305     }
306     char opcode;
307 };
308
309 struct LogicSOp : public BaseElemWiseOp
310 {
311     LogicSOp(char _opcode)
312     : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+(_opcode != '~' ? SUPPORT_MASK : 0), 1, 1, Scalar::all(0)), opcode(_opcode) {};
313     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
314     {
315         if( opcode == '&' )
316             bitwise_and(src[0], gamma, dst, mask);
317         else if( opcode == '|' )
318             bitwise_or(src[0], gamma, dst, mask);
319         else if( opcode == '^' )
320             bitwise_xor(src[0], gamma, dst, mask);
321         else
322             bitwise_not(src[0], dst);
323     }
324     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
325     {
326         Mat temp;
327         if( !mask.empty() )
328         {
329             cvtest::logicOp(src[0], gamma, temp, opcode);
330             cvtest::copy(temp, dst, mask);
331         }
332         else
333             cvtest::logicOp(src[0], gamma, dst, opcode);
334     }
335     double getMaxErr(int)
336     {
337         return 0;
338     }
339     char opcode;
340 };
341
342 struct MinOp : public BaseElemWiseOp
343 {
344     MinOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
345     void op(const vector<Mat>& src, Mat& dst, const Mat&)
346     {
347         cv::min(src[0], src[1], dst);
348     }
349     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
350     {
351         cvtest::min(src[0], src[1], dst);
352     }
353     double getMaxErr(int)
354     {
355         return 0;
356     }
357 };
358
359 struct MaxOp : public BaseElemWiseOp
360 {
361     MaxOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
362     void op(const vector<Mat>& src, Mat& dst, const Mat&)
363     {
364         cv::max(src[0], src[1], dst);
365     }
366     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
367     {
368         cvtest::max(src[0], src[1], dst);
369     }
370     double getMaxErr(int)
371     {
372         return 0;
373     }
374 };
375
376 struct MinSOp : public BaseElemWiseOp
377 {
378     MinSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {};
379     void op(const vector<Mat>& src, Mat& dst, const Mat&)
380     {
381         cv::min(src[0], gamma[0], dst);
382     }
383     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
384     {
385         cvtest::min(src[0], gamma[0], dst);
386     }
387     double getMaxErr(int)
388     {
389         return 0;
390     }
391 };
392
393 struct MaxSOp : public BaseElemWiseOp
394 {
395     MaxSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {};
396     void op(const vector<Mat>& src, Mat& dst, const Mat&)
397     {
398         cv::max(src[0], gamma[0], dst);
399     }
400     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
401     {
402         cvtest::max(src[0], gamma[0], dst);
403     }
404     double getMaxErr(int)
405     {
406         return 0;
407     }
408 };
409
410 struct CmpOp : public BaseElemWiseOp
411 {
412     CmpOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
413     void generateScalars(int depth, RNG& rng)
414     {
415         BaseElemWiseOp::generateScalars(depth, rng);
416         cmpop = rng.uniform(0, 6);
417     }
418     void op(const vector<Mat>& src, Mat& dst, const Mat&)
419     {
420         cv::compare(src[0], src[1], dst, cmpop);
421     }
422     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
423     {
424         cvtest::compare(src[0], src[1], dst, cmpop);
425     }
426     int getRandomType(RNG& rng)
427     {
428         return cvtest::randomType(rng, DEPTH_MASK_ALL_BUT_8S, 1, 1);
429     }
430
431     double getMaxErr(int)
432     {
433         return 0;
434     }
435     int cmpop;
436 };
437
438 struct CmpSOp : public BaseElemWiseOp
439 {
440     CmpSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {};
441     void generateScalars(int depth, RNG& rng)
442     {
443         BaseElemWiseOp::generateScalars(depth, rng);
444         cmpop = rng.uniform(0, 6);
445         if( depth < CV_32F )
446             gamma[0] = cvRound(gamma[0]);
447     }
448     void op(const vector<Mat>& src, Mat& dst, const Mat&)
449     {
450         cv::compare(src[0], gamma[0], dst, cmpop);
451     }
452     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
453     {
454         cvtest::compare(src[0], gamma[0], dst, cmpop);
455     }
456     int getRandomType(RNG& rng)
457     {
458         return cvtest::randomType(rng, DEPTH_MASK_ALL_BUT_8S, 1, 1);
459     }
460     double getMaxErr(int)
461     {
462         return 0;
463     }
464     int cmpop;
465 };
466
467
468 struct CopyOp : public BaseElemWiseOp
469 {
470     CopyOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)) {};
471     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
472     {
473         src[0].copyTo(dst, mask);
474     }
475     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
476     {
477         cvtest::copy(src[0], dst, mask);
478     }
479     int getRandomType(RNG& rng)
480     {
481         return cvtest::randomType(rng, DEPTH_MASK_ALL, 1, ARITHM_MAX_CHANNELS);
482     }
483     double getMaxErr(int)
484     {
485         return 0;
486     }
487     int cmpop;
488 };
489
490
491 struct SetOp : public BaseElemWiseOp
492 {
493     SetOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, 1, 1, Scalar::all(0)) {};
494     void op(const vector<Mat>&, Mat& dst, const Mat& mask)
495     {
496         dst.setTo(gamma, mask);
497     }
498     void refop(const vector<Mat>&, Mat& dst, const Mat& mask)
499     {
500         cvtest::set(dst, gamma, mask);
501     }
502     int getRandomType(RNG& rng)
503     {
504         return cvtest::randomType(rng, DEPTH_MASK_ALL, 1, ARITHM_MAX_CHANNELS);
505     }
506     double getMaxErr(int)
507     {
508         return 0;
509     }
510 };
511
512 template<typename _Tp, typename _WTp> static void
513 inRangeS_(const _Tp* src, const _WTp* a, const _WTp* b, uchar* dst, size_t total, int cn)
514 {
515     size_t i;
516     int c;
517     for( i = 0; i < total; i++ )
518     {
519         _Tp val = src[i*cn];
520         dst[i] = (a[0] <= val && val <= b[0]) ? uchar(255) : 0;
521     }
522     for( c = 1; c < cn; c++ )
523     {
524         for( i = 0; i < total; i++ )
525         {
526             _Tp val = src[i*cn + c];
527             dst[i] = a[c] <= val && val <= b[c] ? dst[i] : 0;
528         }
529     }
530 }
531
532 template<typename _Tp> static void inRange_(const _Tp* src, const _Tp* a, const _Tp* b, uchar* dst, size_t total, int cn)
533 {
534     size_t i;
535     int c;
536     for( i = 0; i < total; i++ )
537     {
538         _Tp val = src[i*cn];
539         dst[i] = a[i*cn] <= val && val <= b[i*cn] ? 255 : 0;
540     }
541     for( c = 1; c < cn; c++ )
542     {
543         for( i = 0; i < total; i++ )
544         {
545             _Tp val = src[i*cn + c];
546             dst[i] = a[i*cn + c] <= val && val <= b[i*cn + c] ? dst[i] : 0;
547         }
548     }
549 }
550
551
552 static void inRange(const Mat& src, const Mat& lb, const Mat& rb, Mat& dst)
553 {
554     CV_Assert( src.type() == lb.type() && src.type() == rb.type() &&
555               src.size == lb.size && src.size == rb.size );
556     dst.create( src.dims, &src.size[0], CV_8U );
557     const Mat *arrays[]={&src, &lb, &rb, &dst, 0};
558     Mat planes[4];
559
560     NAryMatIterator it(arrays, planes);
561     size_t total = planes[0].total();
562     size_t i, nplanes = it.nplanes;
563     int depth = src.depth(), cn = src.channels();
564
565     for( i = 0; i < nplanes; i++, ++it )
566     {
567         const uchar* sptr = planes[0].data;
568         const uchar* aptr = planes[1].data;
569         const uchar* bptr = planes[2].data;
570         uchar* dptr = planes[3].data;
571
572         switch( depth )
573         {
574         case CV_8U:
575             inRange_((const uchar*)sptr, (const uchar*)aptr, (const uchar*)bptr, dptr, total, cn);
576             break;
577         case CV_8S:
578             inRange_((const schar*)sptr, (const schar*)aptr, (const schar*)bptr, dptr, total, cn);
579             break;
580         case CV_16U:
581             inRange_((const ushort*)sptr, (const ushort*)aptr, (const ushort*)bptr, dptr, total, cn);
582             break;
583         case CV_16S:
584             inRange_((const short*)sptr, (const short*)aptr, (const short*)bptr, dptr, total, cn);
585             break;
586         case CV_32S:
587             inRange_((const int*)sptr, (const int*)aptr, (const int*)bptr, dptr, total, cn);
588             break;
589         case CV_32F:
590             inRange_((const float*)sptr, (const float*)aptr, (const float*)bptr, dptr, total, cn);
591             break;
592         case CV_64F:
593             inRange_((const double*)sptr, (const double*)aptr, (const double*)bptr, dptr, total, cn);
594             break;
595         default:
596             CV_Error(CV_StsUnsupportedFormat, "");
597         }
598     }
599 }
600
601
602 static void inRangeS(const Mat& src, const Scalar& lb, const Scalar& rb, Mat& dst)
603 {
604     dst.create( src.dims, &src.size[0], CV_8U );
605     const Mat *arrays[]={&src, &dst, 0};
606     Mat planes[2];
607
608     NAryMatIterator it(arrays, planes);
609     size_t total = planes[0].total();
610     size_t i, nplanes = it.nplanes;
611     int depth = src.depth(), cn = src.channels();
612     union { double d[4]; float f[4]; int i[4];} lbuf, rbuf;
613     int wtype = CV_MAKETYPE(depth <= CV_32S ? CV_32S : depth, cn);
614     scalarToRawData(lb, lbuf.d, wtype, cn);
615     scalarToRawData(rb, rbuf.d, wtype, cn);
616
617     for( i = 0; i < nplanes; i++, ++it )
618     {
619         const uchar* sptr = planes[0].data;
620         uchar* dptr = planes[1].data;
621
622         switch( depth )
623         {
624         case CV_8U:
625             inRangeS_((const uchar*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
626             break;
627         case CV_8S:
628             inRangeS_((const schar*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
629             break;
630         case CV_16U:
631             inRangeS_((const ushort*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
632             break;
633         case CV_16S:
634             inRangeS_((const short*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
635             break;
636         case CV_32S:
637             inRangeS_((const int*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
638             break;
639         case CV_32F:
640             inRangeS_((const float*)sptr, lbuf.f, rbuf.f, dptr, total, cn);
641             break;
642         case CV_64F:
643             inRangeS_((const double*)sptr, lbuf.d, rbuf.d, dptr, total, cn);
644             break;
645         default:
646             CV_Error(CV_StsUnsupportedFormat, "");
647         }
648     }
649 }
650
651
652 struct InRangeSOp : public BaseElemWiseOp
653 {
654     InRangeSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA, 1, 1, Scalar::all(0)) {};
655     void op(const vector<Mat>& src, Mat& dst, const Mat&)
656     {
657         cv::inRange(src[0], gamma, gamma1, dst);
658     }
659     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
660     {
661         cvtest::inRangeS(src[0], gamma, gamma1, dst);
662     }
663     double getMaxErr(int)
664     {
665         return 0;
666     }
667     void generateScalars(int depth, RNG& rng)
668     {
669         BaseElemWiseOp::generateScalars(depth, rng);
670         Scalar temp = gamma;
671         BaseElemWiseOp::generateScalars(depth, rng);
672         for( int i = 0; i < 4; i++ )
673         {
674             gamma1[i] = std::max(gamma[i], temp[i]);
675             gamma[i] = std::min(gamma[i], temp[i]);
676         }
677     }
678     Scalar gamma1;
679 };
680
681
682 struct InRangeOp : public BaseElemWiseOp
683 {
684     InRangeOp() : BaseElemWiseOp(3, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
685     void op(const vector<Mat>& src, Mat& dst, const Mat&)
686     {
687         Mat lb, rb;
688         cvtest::min(src[1], src[2], lb);
689         cvtest::max(src[1], src[2], rb);
690
691         cv::inRange(src[0], lb, rb, dst);
692     }
693     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
694     {
695         Mat lb, rb;
696         cvtest::min(src[1], src[2], lb);
697         cvtest::max(src[1], src[2], rb);
698
699         cvtest::inRange(src[0], lb, rb, dst);
700     }
701     double getMaxErr(int)
702     {
703         return 0;
704     }
705 };
706
707
708 struct ConvertScaleOp : public BaseElemWiseOp
709 {
710     ConvertScaleOp() : BaseElemWiseOp(1, FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)), ddepth(0) { };
711     void op(const vector<Mat>& src, Mat& dst, const Mat&)
712     {
713         src[0].convertTo(dst, ddepth, alpha, gamma[0]);
714     }
715     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
716     {
717         cvtest::convert(src[0], dst, CV_MAKETYPE(ddepth, src[0].channels()), alpha, gamma[0]);
718     }
719     int getRandomType(RNG& rng)
720     {
721         int srctype = cvtest::randomType(rng, DEPTH_MASK_ALL, 1, ARITHM_MAX_CHANNELS);
722         ddepth = cvtest::randomType(rng, DEPTH_MASK_ALL, 1, 1);
723         return srctype;
724     }
725     double getMaxErr(int)
726     {
727         return ddepth <= CV_32S ? 2 : ddepth < CV_64F ? 1e-3 : 1e-12;
728     }
729     void generateScalars(int depth, RNG& rng)
730     {
731         if( rng.uniform(0, 2) )
732             BaseElemWiseOp::generateScalars(depth, rng);
733         else
734         {
735             alpha = 1;
736             gamma = Scalar::all(0);
737         }
738     }
739     int ddepth;
740 };
741
742
743 struct ConvertScaleAbsOp : public BaseElemWiseOp
744 {
745     ConvertScaleAbsOp() : BaseElemWiseOp(1, FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {};
746     void op(const vector<Mat>& src, Mat& dst, const Mat&)
747     {
748         cv::convertScaleAbs(src[0], dst, alpha, gamma[0]);
749     }
750     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
751     {
752         cvtest::add(src[0], alpha, Mat(), 0, Scalar::all(gamma[0]), dst, CV_8UC(src[0].channels()), true);
753     }
754     double getMaxErr(int)
755     {
756         return 1;
757     }
758     void generateScalars(int depth, RNG& rng)
759     {
760         if( rng.uniform(0, 2) )
761             BaseElemWiseOp::generateScalars(depth, rng);
762         else
763         {
764             alpha = 1;
765             gamma = Scalar::all(0);
766         }
767     }
768 };
769
770
771 static void flip(const Mat& src, Mat& dst, int flipcode)
772 {
773     CV_Assert(src.dims == 2);
774     dst.create(src.size(), src.type());
775     int i, j, k, esz = (int)src.elemSize(), width = src.cols*esz;
776
777     for( i = 0; i < dst.rows; i++ )
778     {
779         const uchar* sptr = src.ptr(flipcode == 1 ? i : dst.rows - i - 1);
780         uchar* dptr = dst.ptr(i);
781         if( flipcode == 0 )
782             memcpy(dptr, sptr, width);
783         else
784         {
785             for( j = 0; j < width; j += esz )
786                 for( k = 0; k < esz; k++ )
787                     dptr[j + k] = sptr[width - j - esz + k];
788         }
789     }
790 }
791
792
793 static void setIdentity(Mat& dst, const Scalar& s)
794 {
795     CV_Assert( dst.dims == 2 && dst.channels() <= 4 );
796     double buf[4];
797     scalarToRawData(s, buf, dst.type(), 0);
798     int i, k, esz = (int)dst.elemSize(), width = dst.cols*esz;
799
800     for( i = 0; i < dst.rows; i++ )
801     {
802         uchar* dptr = dst.ptr(i);
803         memset( dptr, 0, width );
804         if( i < dst.cols )
805             for( k = 0; k < esz; k++ )
806                 dptr[i*esz + k] = ((uchar*)buf)[k];
807     }
808 }
809
810
811 struct FlipOp : public BaseElemWiseOp
812 {
813     FlipOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
814     void getRandomSize(RNG& rng, vector<int>& size)
815     {
816         cvtest::randomSize(rng, 2, 2, cvtest::ARITHM_MAX_SIZE_LOG, size);
817     }
818     void op(const vector<Mat>& src, Mat& dst, const Mat&)
819     {
820         cv::flip(src[0], dst, flipcode);
821     }
822     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
823     {
824         cvtest::flip(src[0], dst, flipcode);
825     }
826     void generateScalars(int, RNG& rng)
827     {
828         flipcode = rng.uniform(0, 3) - 1;
829     }
830     double getMaxErr(int)
831     {
832         return 0;
833     }
834     int flipcode;
835 };
836
837 struct TransposeOp : public BaseElemWiseOp
838 {
839     TransposeOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
840     void getRandomSize(RNG& rng, vector<int>& size)
841     {
842         cvtest::randomSize(rng, 2, 2, cvtest::ARITHM_MAX_SIZE_LOG, size);
843     }
844     void op(const vector<Mat>& src, Mat& dst, const Mat&)
845     {
846         cv::transpose(src[0], dst);
847     }
848     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
849     {
850         cvtest::transpose(src[0], dst);
851     }
852     double getMaxErr(int)
853     {
854         return 0;
855     }
856 };
857
858 struct SetIdentityOp : public BaseElemWiseOp
859 {
860     SetIdentityOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA, 1, 1, Scalar::all(0)) {};
861     void getRandomSize(RNG& rng, vector<int>& size)
862     {
863         cvtest::randomSize(rng, 2, 2, cvtest::ARITHM_MAX_SIZE_LOG, size);
864     }
865     void op(const vector<Mat>&, Mat& dst, const Mat&)
866     {
867         cv::setIdentity(dst, gamma);
868     }
869     void refop(const vector<Mat>&, Mat& dst, const Mat&)
870     {
871         cvtest::setIdentity(dst, gamma);
872     }
873     double getMaxErr(int)
874     {
875         return 0;
876     }
877 };
878
879 struct SetZeroOp : public BaseElemWiseOp
880 {
881     SetZeroOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
882     void op(const vector<Mat>&, Mat& dst, const Mat&)
883     {
884         dst = Scalar::all(0);
885     }
886     void refop(const vector<Mat>&, Mat& dst, const Mat&)
887     {
888         cvtest::set(dst, Scalar::all(0));
889     }
890     double getMaxErr(int)
891     {
892         return 0;
893     }
894 };
895
896
897 static void exp(const Mat& src, Mat& dst)
898 {
899     dst.create( src.dims, &src.size[0], src.type() );
900     const Mat *arrays[]={&src, &dst, 0};
901     Mat planes[2];
902
903     NAryMatIterator it(arrays, planes);
904     size_t j, total = planes[0].total()*src.channels();
905     size_t i, nplanes = it.nplanes;
906     int depth = src.depth();
907
908     for( i = 0; i < nplanes; i++, ++it )
909     {
910         const uchar* sptr = planes[0].data;
911         uchar* dptr = planes[1].data;
912
913         if( depth == CV_32F )
914         {
915             for( j = 0; j < total; j++ )
916                 ((float*)dptr)[j] = std::exp(((const float*)sptr)[j]);
917         }
918         else if( depth == CV_64F )
919         {
920             for( j = 0; j < total; j++ )
921                 ((double*)dptr)[j] = std::exp(((const double*)sptr)[j]);
922         }
923     }
924 }
925
926 static void log(const Mat& src, Mat& dst)
927 {
928     dst.create( src.dims, &src.size[0], src.type() );
929     const Mat *arrays[]={&src, &dst, 0};
930     Mat planes[2];
931
932     NAryMatIterator it(arrays, planes);
933     size_t j, total = planes[0].total()*src.channels();
934     size_t i, nplanes = it.nplanes;
935     int depth = src.depth();
936
937     for( i = 0; i < nplanes; i++, ++it )
938     {
939         const uchar* sptr = planes[0].data;
940         uchar* dptr = planes[1].data;
941
942         if( depth == CV_32F )
943         {
944             for( j = 0; j < total; j++ )
945                 ((float*)dptr)[j] = (float)std::log(fabs(((const float*)sptr)[j]));
946         }
947         else if( depth == CV_64F )
948         {
949             for( j = 0; j < total; j++ )
950                 ((double*)dptr)[j] = std::log(fabs(((const double*)sptr)[j]));
951         }
952     }
953 }
954
955 struct ExpOp : public BaseElemWiseOp
956 {
957     ExpOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
958     int getRandomType(RNG& rng)
959     {
960         return cvtest::randomType(rng, DEPTH_MASK_FLT, 1, ARITHM_MAX_CHANNELS);
961     }
962     void getValueRange(int depth, double& minval, double& maxval)
963     {
964         maxval = depth == CV_32F ? 50 : 100;
965         minval = -maxval;
966     }
967     void op(const vector<Mat>& src, Mat& dst, const Mat&)
968     {
969         cv::exp(src[0], dst);
970     }
971     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
972     {
973         cvtest::exp(src[0], dst);
974     }
975     double getMaxErr(int depth)
976     {
977         return depth == CV_32F ? 1e-5 : 1e-12;
978     }
979 };
980
981
982 struct LogOp : public BaseElemWiseOp
983 {
984     LogOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
985     int getRandomType(RNG& rng)
986     {
987         return cvtest::randomType(rng, DEPTH_MASK_FLT, 1, ARITHM_MAX_CHANNELS);
988     }
989     void getValueRange(int depth, double& minval, double& maxval)
990     {
991         maxval = depth == CV_32F ? 50 : 100;
992         minval = -maxval;
993     }
994     void op(const vector<Mat>& src, Mat& dst, const Mat&)
995     {
996         Mat temp;
997         cvtest::exp(src[0], temp);
998         cv::log(temp, dst);
999     }
1000     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
1001     {
1002         Mat temp;
1003         cvtest::exp(src[0], temp);
1004         cvtest::log(temp, dst);
1005     }
1006     double getMaxErr(int depth)
1007     {
1008         return depth == CV_32F ? 1e-5 : 1e-12;
1009     }
1010 };
1011
1012
1013 static void cartToPolar(const Mat& mx, const Mat& my, Mat& mmag, Mat& mangle, bool angleInDegrees)
1014 {
1015     CV_Assert( (mx.type() == CV_32F || mx.type() == CV_64F) &&
1016               mx.type() == my.type() && mx.size == my.size );
1017     mmag.create( mx.dims, &mx.size[0], mx.type() );
1018     mangle.create( mx.dims, &mx.size[0], mx.type() );
1019     const Mat *arrays[]={&mx, &my, &mmag, &mangle, 0};
1020     Mat planes[4];
1021
1022     NAryMatIterator it(arrays, planes);
1023     size_t j, total = planes[0].total();
1024     size_t i, nplanes = it.nplanes;
1025     int depth = mx.depth();
1026     double scale = angleInDegrees ? 180/CV_PI : 1;
1027
1028     for( i = 0; i < nplanes; i++, ++it )
1029     {
1030         if( depth == CV_32F )
1031         {
1032             const float* xptr = (const float*)planes[0].data;
1033             const float* yptr = (const float*)planes[1].data;
1034             float* mptr = (float*)planes[2].data;
1035             float* aptr = (float*)planes[3].data;
1036
1037             for( j = 0; j < total; j++ )
1038             {
1039                 mptr[j] = std::sqrt(xptr[j]*xptr[j] + yptr[j]*yptr[j]);
1040                 double a = atan2((double)yptr[j], (double)xptr[j]);
1041                 if( a < 0 ) a += CV_PI*2;
1042                 aptr[j] = (float)(a*scale);
1043             }
1044         }
1045         else
1046         {
1047             const double* xptr = (const double*)planes[0].data;
1048             const double* yptr = (const double*)planes[1].data;
1049             double* mptr = (double*)planes[2].data;
1050             double* aptr = (double*)planes[3].data;
1051
1052             for( j = 0; j < total; j++ )
1053             {
1054                 mptr[j] = std::sqrt(xptr[j]*xptr[j] + yptr[j]*yptr[j]);
1055                 double a = atan2(yptr[j], xptr[j]);
1056                 if( a < 0 ) a += CV_PI*2;
1057                 aptr[j] = a*scale;
1058             }
1059         }
1060     }
1061 }
1062
1063
1064 struct CartToPolarToCartOp : public BaseElemWiseOp
1065 {
1066     CartToPolarToCartOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0))
1067     {
1068         context = 3;
1069         angleInDegrees = true;
1070     }
1071     int getRandomType(RNG& rng)
1072     {
1073         return cvtest::randomType(rng, DEPTH_MASK_FLT, 1, 1);
1074     }
1075     void op(const vector<Mat>& src, Mat& dst, const Mat&)
1076     {
1077         Mat mag, angle, x, y;
1078
1079         cv::cartToPolar(src[0], src[1], mag, angle, angleInDegrees);
1080         cv::polarToCart(mag, angle, x, y, angleInDegrees);
1081
1082         Mat msrc[] = {mag, angle, x, y};
1083         int pairs[] = {0, 0, 1, 1, 2, 2, 3, 3};
1084         dst.create(src[0].dims, src[0].size, CV_MAKETYPE(src[0].depth(), 4));
1085         cv::mixChannels(msrc, 4, &dst, 1, pairs, 4);
1086     }
1087     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
1088     {
1089         Mat mag, angle;
1090         cvtest::cartToPolar(src[0], src[1], mag, angle, angleInDegrees);
1091         Mat msrc[] = {mag, angle, src[0], src[1]};
1092         int pairs[] = {0, 0, 1, 1, 2, 2, 3, 3};
1093         dst.create(src[0].dims, src[0].size, CV_MAKETYPE(src[0].depth(), 4));
1094         cv::mixChannels(msrc, 4, &dst, 1, pairs, 4);
1095     }
1096     void generateScalars(int, RNG& rng)
1097     {
1098         angleInDegrees = rng.uniform(0, 2) != 0;
1099     }
1100     double getMaxErr(int)
1101     {
1102         return 1e-3;
1103     }
1104     bool angleInDegrees;
1105 };
1106
1107
1108 struct MeanOp : public BaseElemWiseOp
1109 {
1110     MeanOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
1111     {
1112         context = 3;
1113     };
1114     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
1115     {
1116         dst.create(1, 1, CV_64FC4);
1117         dst.at<Scalar>(0,0) = cv::mean(src[0], mask);
1118     }
1119     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
1120     {
1121         dst.create(1, 1, CV_64FC4);
1122         dst.at<Scalar>(0,0) = cvtest::mean(src[0], mask);
1123     }
1124     double getMaxErr(int)
1125     {
1126         return 1e-6;
1127     }
1128 };
1129
1130
1131 struct SumOp : public BaseElemWiseOp
1132 {
1133     SumOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
1134     {
1135         context = 3;
1136     };
1137     void op(const vector<Mat>& src, Mat& dst, const Mat&)
1138     {
1139         dst.create(1, 1, CV_64FC4);
1140         dst.at<Scalar>(0,0) = cv::sum(src[0]);
1141     }
1142     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
1143     {
1144         dst.create(1, 1, CV_64FC4);
1145         dst.at<Scalar>(0,0) = cvtest::mean(src[0])*(double)src[0].total();
1146     }
1147     double getMaxErr(int)
1148     {
1149         return 1e-5;
1150     }
1151 };
1152
1153
1154 struct CountNonZeroOp : public BaseElemWiseOp
1155 {
1156     CountNonZeroOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SCALAR_OUTPUT+SUPPORT_MASK, 1, 1, Scalar::all(0))
1157     {}
1158     int getRandomType(RNG& rng)
1159     {
1160         return cvtest::randomType(rng, DEPTH_MASK_ALL, 1, 1);
1161     }
1162     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
1163     {
1164         Mat temp;
1165         src[0].copyTo(temp);
1166         if( !mask.empty() )
1167             temp.setTo(Scalar::all(0), mask);
1168         dst.create(1, 1, CV_32S);
1169         dst.at<int>(0,0) = cv::countNonZero(temp);
1170     }
1171     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
1172     {
1173         Mat temp;
1174         cvtest::compare(src[0], 0, temp, CMP_NE);
1175         if( !mask.empty() )
1176             cvtest::set(temp, Scalar::all(0), mask);
1177         dst.create(1, 1, CV_32S);
1178         dst.at<int>(0,0) = saturate_cast<int>(cvtest::mean(temp)[0]/255*temp.total());
1179     }
1180     double getMaxErr(int)
1181     {
1182         return 0;
1183     }
1184 };
1185
1186
1187 struct MeanStdDevOp : public BaseElemWiseOp
1188 {
1189     Scalar sqmeanRef;
1190     int cn;
1191
1192     MeanStdDevOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
1193     {
1194         cn = 0;
1195         context = 7;
1196     };
1197     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
1198     {
1199         dst.create(1, 2, CV_64FC4);
1200         cv::meanStdDev(src[0], dst.at<Scalar>(0,0), dst.at<Scalar>(0,1), mask);
1201     }
1202     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
1203     {
1204         Mat temp;
1205         cvtest::convert(src[0], temp, CV_64F);
1206         cvtest::multiply(temp, temp, temp);
1207         Scalar mean = cvtest::mean(src[0], mask);
1208         Scalar sqmean = cvtest::mean(temp, mask);
1209
1210         sqmeanRef = sqmean;
1211         cn = temp.channels();
1212
1213         for( int c = 0; c < 4; c++ )
1214             sqmean[c] = std::sqrt(std::max(sqmean[c] - mean[c]*mean[c], 0.));
1215
1216         dst.create(1, 2, CV_64FC4);
1217         dst.at<Scalar>(0,0) = mean;
1218         dst.at<Scalar>(0,1) = sqmean;
1219     }
1220     double getMaxErr(int)
1221     {
1222         CV_Assert(cn > 0);
1223         double err = sqmeanRef[0];
1224         for(int i = 1; i < cn; ++i)
1225             err = std::max(err, sqmeanRef[i]);
1226         return 3e-7 * err;
1227     }
1228 };
1229
1230
1231 struct NormOp : public BaseElemWiseOp
1232 {
1233     NormOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
1234     {
1235         context = 1;
1236         normType = 0;
1237     };
1238     int getRandomType(RNG& rng)
1239     {
1240         int type = cvtest::randomType(rng, DEPTH_MASK_ALL_BUT_8S, 1, 4);
1241         for(;;)
1242         {
1243             normType = rng.uniform(1, 8);
1244             if( normType == NORM_INF || normType == NORM_L1 ||
1245                 normType == NORM_L2 || normType == NORM_L2SQR ||
1246                 normType == NORM_HAMMING || normType == NORM_HAMMING2 )
1247                 break;
1248         }
1249         if( normType == NORM_HAMMING || normType == NORM_HAMMING2 )
1250         {
1251             type = CV_8U;
1252         }
1253         return type;
1254     }
1255     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
1256     {
1257         dst.create(1, 2, CV_64FC1);
1258         dst.at<double>(0,0) = cv::norm(src[0], normType, mask);
1259         dst.at<double>(0,1) = cv::norm(src[0], src[1], normType, mask);
1260     }
1261     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
1262     {
1263         dst.create(1, 2, CV_64FC1);
1264         dst.at<double>(0,0) = cvtest::norm(src[0], normType, mask);
1265         dst.at<double>(0,1) = cvtest::norm(src[0], src[1], normType, mask);
1266     }
1267     void generateScalars(int, RNG& /*rng*/)
1268     {
1269     }
1270     double getMaxErr(int)
1271     {
1272         return 1e-6;
1273     }
1274     int normType;
1275 };
1276
1277
1278 struct MinMaxLocOp : public BaseElemWiseOp
1279 {
1280     MinMaxLocOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
1281     {
1282         context = ARITHM_MAX_NDIMS*2 + 2;
1283     };
1284     int getRandomType(RNG& rng)
1285     {
1286         return cvtest::randomType(rng, DEPTH_MASK_ALL_BUT_8S, 1, 1);
1287     }
1288     void saveOutput(const vector<int>& minidx, const vector<int>& maxidx,
1289                     double minval, double maxval, Mat& dst)
1290     {
1291         int i, ndims = (int)minidx.size();
1292         dst.create(1, ndims*2 + 2, CV_64FC1);
1293
1294         for( i = 0; i < ndims; i++ )
1295         {
1296             dst.at<double>(0,i) = minidx[i];
1297             dst.at<double>(0,i+ndims) = maxidx[i];
1298         }
1299         dst.at<double>(0,ndims*2) = minval;
1300         dst.at<double>(0,ndims*2+1) = maxval;
1301     }
1302     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
1303     {
1304         int ndims = src[0].dims;
1305         vector<int> minidx(ndims), maxidx(ndims);
1306         double minval=0, maxval=0;
1307         cv::minMaxIdx(src[0], &minval, &maxval, &minidx[0], &maxidx[0], mask);
1308         saveOutput(minidx, maxidx, minval, maxval, dst);
1309     }
1310     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
1311     {
1312         int ndims=src[0].dims;
1313         vector<int> minidx(ndims), maxidx(ndims);
1314         double minval=0, maxval=0;
1315         cvtest::minMaxLoc(src[0], &minval, &maxval, &minidx, &maxidx, mask);
1316         saveOutput(minidx, maxidx, minval, maxval, dst);
1317     }
1318     double getMaxErr(int)
1319     {
1320         return 0;
1321     }
1322 };
1323
1324
1325 }
1326
1327 typedef Ptr<cvtest::BaseElemWiseOp> ElemWiseOpPtr;
1328 class ElemWiseTest : public ::testing::TestWithParam<ElemWiseOpPtr> {};
1329
1330 TEST_P(ElemWiseTest, accuracy)
1331 {
1332     ElemWiseOpPtr op = GetParam();
1333
1334     int testIdx = 0;
1335     RNG rng((uint64)cvtest::ARITHM_RNG_SEED);
1336     for( testIdx = 0; testIdx < cvtest::ARITHM_NTESTS; testIdx++ )
1337     {
1338         vector<int> size;
1339         op->getRandomSize(rng, size);
1340         int type = op->getRandomType(rng);
1341         int depth = CV_MAT_DEPTH(type);
1342         bool haveMask = (op->flags & cvtest::BaseElemWiseOp::SUPPORT_MASK) != 0 && rng.uniform(0, 4) == 0;
1343
1344         double minval=0, maxval=0;
1345         op->getValueRange(depth, minval, maxval);
1346         int i, ninputs = op->ninputs;
1347         vector<Mat> src(ninputs);
1348         for( i = 0; i < ninputs; i++ )
1349             src[i] = cvtest::randomMat(rng, size, type, minval, maxval, true);
1350         Mat dst0, dst, mask;
1351         if( haveMask )
1352             mask = cvtest::randomMat(rng, size, CV_8U, 0, 2, true);
1353
1354         if( (haveMask || ninputs == 0) && !(op->flags & cvtest::BaseElemWiseOp::SCALAR_OUTPUT))
1355         {
1356             dst0 = cvtest::randomMat(rng, size, type, minval, maxval, false);
1357             dst = cvtest::randomMat(rng, size, type, minval, maxval, true);
1358             cvtest::copy(dst, dst0);
1359         }
1360         op->generateScalars(depth, rng);
1361
1362         op->refop(src, dst0, mask);
1363         op->op(src, dst, mask);
1364
1365         double maxErr = op->getMaxErr(depth);
1366         vector<int> pos;
1367         ASSERT_PRED_FORMAT2(cvtest::MatComparator(maxErr, op->context), dst0, dst) << "\nsrc[0] ~ " << cvtest::MatInfo(!src.empty() ? src[0] : Mat()) << "\ntestCase #" << testIdx << "\n";
1368     }
1369 }
1370
1371
1372 INSTANTIATE_TEST_CASE_P(Core_Copy, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CopyOp)));
1373 INSTANTIATE_TEST_CASE_P(Core_Set, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SetOp)));
1374 INSTANTIATE_TEST_CASE_P(Core_SetZero, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SetZeroOp)));
1375 INSTANTIATE_TEST_CASE_P(Core_ConvertScale, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ConvertScaleOp)));
1376 INSTANTIATE_TEST_CASE_P(Core_ConvertScaleAbs, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ConvertScaleAbsOp)));
1377
1378 INSTANTIATE_TEST_CASE_P(Core_Add, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AddOp)));
1379 INSTANTIATE_TEST_CASE_P(Core_Sub, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SubOp)));
1380 INSTANTIATE_TEST_CASE_P(Core_AddS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AddSOp)));
1381 INSTANTIATE_TEST_CASE_P(Core_SubRS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SubRSOp)));
1382 INSTANTIATE_TEST_CASE_P(Core_ScaleAdd, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ScaleAddOp)));
1383 INSTANTIATE_TEST_CASE_P(Core_AddWeighted, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AddWeightedOp)));
1384 INSTANTIATE_TEST_CASE_P(Core_AbsDiff, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AbsDiffOp)));
1385
1386
1387 INSTANTIATE_TEST_CASE_P(Core_AbsDiffS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AbsDiffSOp)));
1388
1389 INSTANTIATE_TEST_CASE_P(Core_And, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicOp('&'))));
1390 INSTANTIATE_TEST_CASE_P(Core_AndS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('&'))));
1391 INSTANTIATE_TEST_CASE_P(Core_Or, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicOp('|'))));
1392 INSTANTIATE_TEST_CASE_P(Core_OrS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('|'))));
1393 INSTANTIATE_TEST_CASE_P(Core_Xor, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicOp('^'))));
1394 INSTANTIATE_TEST_CASE_P(Core_XorS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('^'))));
1395 INSTANTIATE_TEST_CASE_P(Core_Not, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('~'))));
1396
1397 INSTANTIATE_TEST_CASE_P(Core_Max, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MaxOp)));
1398 INSTANTIATE_TEST_CASE_P(Core_MaxS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MaxSOp)));
1399 INSTANTIATE_TEST_CASE_P(Core_Min, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MinOp)));
1400 INSTANTIATE_TEST_CASE_P(Core_MinS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MinSOp)));
1401
1402 INSTANTIATE_TEST_CASE_P(Core_Mul, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MulOp)));
1403 INSTANTIATE_TEST_CASE_P(Core_Div, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::DivOp)));
1404 INSTANTIATE_TEST_CASE_P(Core_Recip, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::RecipOp)));
1405
1406 INSTANTIATE_TEST_CASE_P(Core_Cmp, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CmpOp)));
1407 INSTANTIATE_TEST_CASE_P(Core_CmpS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CmpSOp)));
1408
1409 INSTANTIATE_TEST_CASE_P(Core_InRangeS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::InRangeSOp)));
1410 INSTANTIATE_TEST_CASE_P(Core_InRange, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::InRangeOp)));
1411
1412 INSTANTIATE_TEST_CASE_P(Core_Flip, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::FlipOp)));
1413 INSTANTIATE_TEST_CASE_P(Core_Transpose, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::TransposeOp)));
1414 INSTANTIATE_TEST_CASE_P(Core_SetIdentity, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SetIdentityOp)));
1415
1416 INSTANTIATE_TEST_CASE_P(Core_Exp, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ExpOp)));
1417 INSTANTIATE_TEST_CASE_P(Core_Log, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogOp)));
1418
1419 INSTANTIATE_TEST_CASE_P(Core_CountNonZero, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CountNonZeroOp)));
1420 INSTANTIATE_TEST_CASE_P(Core_Mean, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MeanOp)));
1421 INSTANTIATE_TEST_CASE_P(Core_MeanStdDev, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MeanStdDevOp)));
1422 INSTANTIATE_TEST_CASE_P(Core_Sum, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SumOp)));
1423 INSTANTIATE_TEST_CASE_P(Core_Norm, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::NormOp)));
1424 INSTANTIATE_TEST_CASE_P(Core_MinMaxLoc, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MinMaxLocOp)));
1425 INSTANTIATE_TEST_CASE_P(Core_CartToPolarToCart, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CartToPolarToCartOp)));
1426
1427
1428 class CV_ArithmMaskTest : public cvtest::BaseTest
1429 {
1430 public:
1431     CV_ArithmMaskTest() {}
1432     ~CV_ArithmMaskTest() {}
1433 protected:
1434     void run(int)
1435     {
1436         try
1437         {
1438             RNG& rng = theRNG();
1439             const int MAX_DIM=3;
1440             int sizes[MAX_DIM];
1441             for( int iter = 0; iter < 100; iter++ )
1442             {
1443                 //ts->printf(cvtest::TS::LOG, ".");
1444
1445                 ts->update_context(this, iter, true);
1446                 int k, dims = rng.uniform(1, MAX_DIM+1), p = 1;
1447                 int depth = rng.uniform(CV_8U, CV_64F+1);
1448                 int cn = rng.uniform(1, 6);
1449                 int type = CV_MAKETYPE(depth, cn);
1450                 int op = rng.uniform(0, 5);
1451                 int depth1 = op <= 1 ? CV_64F : depth;
1452                 for( k = 0; k < dims; k++ )
1453                 {
1454                     sizes[k] = rng.uniform(1, 30);
1455                     p *= sizes[k];
1456                 }
1457                 Mat a(dims, sizes, type), a1;
1458                 Mat b(dims, sizes, type), b1;
1459                 Mat mask(dims, sizes, CV_8U);
1460                 Mat mask1;
1461                 Mat c, d;
1462
1463                 rng.fill(a, RNG::UNIFORM, 0, 100);
1464                 rng.fill(b, RNG::UNIFORM, 0, 100);
1465
1466                 // [-2,2) range means that the each generated random number
1467                 // will be one of -2, -1, 0, 1. Saturated to [0,255], it will become
1468                 // 0, 0, 0, 1 => the mask will be filled by ~25%.
1469                 rng.fill(mask, RNG::UNIFORM, -2, 2);
1470
1471                 a.convertTo(a1, depth1);
1472                 b.convertTo(b1, depth1);
1473                 // invert the mask
1474                 compare(mask, 0, mask1, CMP_EQ);
1475                 a1.setTo(0, mask1);
1476                 b1.setTo(0, mask1);
1477
1478                 if( op == 0 )
1479                 {
1480                     add(a, b, c, mask);
1481                     add(a1, b1, d);
1482                 }
1483                 else if( op == 1 )
1484                 {
1485                     subtract(a, b, c, mask);
1486                     subtract(a1, b1, d);
1487                 }
1488                 else if( op == 2 )
1489                 {
1490                     bitwise_and(a, b, c, mask);
1491                     bitwise_and(a1, b1, d);
1492                 }
1493                 else if( op == 3 )
1494                 {
1495                     bitwise_or(a, b, c, mask);
1496                     bitwise_or(a1, b1, d);
1497                 }
1498                 else if( op == 4 )
1499                 {
1500                     bitwise_xor(a, b, c, mask);
1501                     bitwise_xor(a1, b1, d);
1502                 }
1503                 Mat d1;
1504                 d.convertTo(d1, depth);
1505                 CV_Assert( norm(c, d1, CV_C) <= DBL_EPSILON );
1506             }
1507
1508             Mat_<uchar> tmpSrc(100,100);
1509             tmpSrc = 124;
1510             Mat_<uchar> tmpMask(100,100);
1511             tmpMask = 255;
1512             Mat_<uchar> tmpDst(100,100);
1513             tmpDst = 2;
1514             tmpSrc.copyTo(tmpDst,tmpMask);
1515         }
1516         catch(...)
1517         {
1518            ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
1519         }
1520     }
1521 };
1522
1523 TEST(Core_ArithmMask, uninitialized) { CV_ArithmMaskTest test; test.safe_run(); }
1524
1525 TEST(Multiply, FloatingPointRounding)
1526 {
1527     cv::Mat src(1, 1, CV_8UC1, cv::Scalar::all(110)), dst;
1528     cv::Scalar s(147.286359696927, 1, 1 ,1);
1529
1530     cv::multiply(src, s, dst, 1, CV_16U);
1531     // with CV_32F this produce result 16202
1532     ASSERT_EQ(dst.at<ushort>(0,0), 16201);
1533 }
1534
1535 TEST(Core_Add, AddToColumnWhen3Rows)
1536 {
1537     cv::Mat m1 = (cv::Mat_<double>(3, 2) << 1, 2, 3, 4, 5, 6);
1538     m1.col(1) += 10;
1539
1540     cv::Mat m2 = (cv::Mat_<double>(3, 2) << 1, 12, 3, 14, 5, 16);
1541
1542     ASSERT_EQ(0, countNonZero(m1 - m2));
1543 }
1544
1545 TEST(Core_Add, AddToColumnWhen4Rows)
1546 {
1547     cv::Mat m1 = (cv::Mat_<double>(4, 2) << 1, 2, 3, 4, 5, 6, 7, 8);
1548     m1.col(1) += 10;
1549
1550     cv::Mat m2 = (cv::Mat_<double>(4, 2) << 1, 12, 3, 14, 5, 16, 7, 18);
1551
1552     ASSERT_EQ(0, countNonZero(m1 - m2));
1553 }
1554
1555 TEST(Core_round, CvRound)
1556 {
1557     ASSERT_EQ(2, cvRound(2.0));
1558     ASSERT_EQ(2, cvRound(2.1));
1559     ASSERT_EQ(-2, cvRound(-2.1));
1560     ASSERT_EQ(3, cvRound(2.8));
1561     ASSERT_EQ(-3, cvRound(-2.8));
1562     ASSERT_EQ(2, cvRound(2.5));
1563     ASSERT_EQ(4, cvRound(3.5));
1564     ASSERT_EQ(-2, cvRound(-2.5));
1565     ASSERT_EQ(-4, cvRound(-3.5));
1566 }