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