dd2ed9a86ef493943ca0fea1bf6507f892cd2faf
[platform/upstream/opencv.git] / modules / core / test / test_arithm.cpp
1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4 #include "test_precomp.hpp"
5
6 namespace opencv_test { namespace {
7
8 const int ARITHM_NTESTS = 1000;
9 const int ARITHM_RNG_SEED = -1;
10 const int ARITHM_MAX_CHANNELS = 4;
11 const int ARITHM_MAX_NDIMS = 4;
12 const int ARITHM_MAX_SIZE_LOG = 10;
13
14 struct BaseElemWiseOp
15 {
16     enum { FIX_ALPHA=1, FIX_BETA=2, FIX_GAMMA=4, REAL_GAMMA=8, SUPPORT_MASK=16, SCALAR_OUTPUT=32, SUPPORT_MULTICHANNELMASK=64 };
17     BaseElemWiseOp(int _ninputs, int _flags, double _alpha, double _beta,
18                    Scalar _gamma=Scalar::all(0), int _context=1)
19     : ninputs(_ninputs), flags(_flags), alpha(_alpha), beta(_beta), gamma(_gamma), context(_context) {}
20     BaseElemWiseOp() { flags = 0; alpha = beta = 0; gamma = Scalar::all(0); ninputs = 0; context = 1; }
21     virtual ~BaseElemWiseOp() {}
22     virtual void op(const vector<Mat>&, Mat&, const Mat&) {}
23     virtual void refop(const vector<Mat>&, Mat&, const Mat&) {}
24     virtual void getValueRange(int depth, double& minval, double& maxval)
25     {
26         minval = depth < CV_32S ? cvtest::getMinVal(depth) : depth == CV_32S ? -1000000 : -1000.;
27         maxval = depth < CV_32S ? cvtest::getMaxVal(depth) : depth == CV_32S ? 1000000 : 1000.;
28     }
29
30     virtual void getRandomSize(RNG& rng, vector<int>& size)
31     {
32         cvtest::randomSize(rng, 2, ARITHM_MAX_NDIMS, ARITHM_MAX_SIZE_LOG, size);
33     }
34
35     virtual int getRandomType(RNG& rng)
36     {
37         return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL_BUT_8S, 1,
38                                   ninputs > 1 ? ARITHM_MAX_CHANNELS : 4);
39     }
40
41     virtual double getMaxErr(int depth) { return depth < CV_32F ? 1 : depth == CV_32F ? 1e-5 : 1e-12; }
42     virtual void generateScalars(int depth, RNG& rng)
43     {
44         const double m = 3.;
45
46         if( !(flags & FIX_ALPHA) )
47         {
48             alpha = exp(rng.uniform(-0.5, 0.1)*m*2*CV_LOG2);
49             alpha *= rng.uniform(0, 2) ? 1 : -1;
50         }
51         if( !(flags & FIX_BETA) )
52         {
53             beta = exp(rng.uniform(-0.5, 0.1)*m*2*CV_LOG2);
54             beta *= rng.uniform(0, 2) ? 1 : -1;
55         }
56
57         if( !(flags & FIX_GAMMA) )
58         {
59             for( int i = 0; i < 4; i++ )
60             {
61                 gamma[i] = exp(rng.uniform(-1, 6)*m*CV_LOG2);
62                 gamma[i] *= rng.uniform(0, 2) ? 1 : -1;
63             }
64             if( flags & REAL_GAMMA )
65                 gamma = Scalar::all(gamma[0]);
66         }
67
68         if( depth == CV_32F )
69         {
70             Mat fl, db;
71
72             db = Mat(1, 1, CV_64F, &alpha);
73             db.convertTo(fl, CV_32F);
74             fl.convertTo(db, CV_64F);
75
76             db = Mat(1, 1, CV_64F, &beta);
77             db.convertTo(fl, CV_32F);
78             fl.convertTo(db, CV_64F);
79
80             db = Mat(1, 4, CV_64F, &gamma[0]);
81             db.convertTo(fl, CV_32F);
82             fl.convertTo(db, CV_64F);
83         }
84     }
85
86     int ninputs;
87     int flags;
88     double alpha;
89     double beta;
90     Scalar gamma;
91     int context;
92 };
93
94
95 struct BaseAddOp : public BaseElemWiseOp
96 {
97     BaseAddOp(int _ninputs, int _flags, double _alpha, double _beta, Scalar _gamma=Scalar::all(0))
98     : BaseElemWiseOp(_ninputs, _flags, _alpha, _beta, _gamma) {}
99
100     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
101     {
102         Mat temp;
103         if( !mask.empty() )
104         {
105             cvtest::add(src[0], alpha, src.size() > 1 ? src[1] : Mat(), beta, gamma, temp, src[0].type());
106             cvtest::copy(temp, dst, mask);
107         }
108         else
109             cvtest::add(src[0], alpha, src.size() > 1 ? src[1] : Mat(), beta, gamma, dst, src[0].type());
110     }
111 };
112
113
114 struct AddOp : public BaseAddOp
115 {
116     AddOp() : BaseAddOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)) {}
117     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
118     {
119         if( mask.empty() )
120             cv::add(src[0], src[1], dst);
121         else
122             cv::add(src[0], src[1], dst, mask);
123     }
124 };
125
126
127 struct SubOp : public BaseAddOp
128 {
129     SubOp() : BaseAddOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, -1, Scalar::all(0)) {}
130     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
131     {
132         if( mask.empty() )
133             cv::subtract(src[0], src[1], dst);
134         else
135             cv::subtract(src[0], src[1], dst, mask);
136     }
137 };
138
139
140 struct AddSOp : public BaseAddOp
141 {
142     AddSOp() : BaseAddOp(1, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, 1, 0, Scalar::all(0)) {}
143     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
144     {
145         if( mask.empty() )
146             cv::add(src[0], gamma, dst);
147         else
148             cv::add(src[0], gamma, dst, mask);
149     }
150 };
151
152
153 struct SubRSOp : public BaseAddOp
154 {
155     SubRSOp() : BaseAddOp(1, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, -1, 0, Scalar::all(0)) {}
156     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
157     {
158         if( mask.empty() )
159             cv::subtract(gamma, src[0], dst);
160         else
161             cv::subtract(gamma, src[0], dst, mask);
162     }
163 };
164
165
166 struct ScaleAddOp : public BaseAddOp
167 {
168     ScaleAddOp() : BaseAddOp(2, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
169     void op(const vector<Mat>& src, Mat& dst, const Mat&)
170     {
171         cv::scaleAdd(src[0], alpha, src[1], dst);
172     }
173     double getMaxErr(int depth)
174     {
175         return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-4 : 1e-12;
176     }
177 };
178
179
180 struct AddWeightedOp : public BaseAddOp
181 {
182     AddWeightedOp() : BaseAddOp(2, REAL_GAMMA, 1, 1, Scalar::all(0)) {}
183     void op(const vector<Mat>& src, Mat& dst, const Mat&)
184     {
185         cv::addWeighted(src[0], alpha, src[1], beta, gamma[0], dst);
186     }
187     double getMaxErr(int depth)
188     {
189         return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-10;
190     }
191 };
192
193 struct MulOp : public BaseElemWiseOp
194 {
195     MulOp() : BaseElemWiseOp(2, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
196     void getValueRange(int depth, double& minval, double& maxval)
197     {
198         minval = depth < CV_32S ? cvtest::getMinVal(depth) : depth == CV_32S ? -1000000 : -1000.;
199         maxval = depth < CV_32S ? cvtest::getMaxVal(depth) : depth == CV_32S ? 1000000 : 1000.;
200         minval = std::max(minval, -30000.);
201         maxval = std::min(maxval, 30000.);
202     }
203     void op(const vector<Mat>& src, Mat& dst, const Mat&)
204     {
205         cv::multiply(src[0], src[1], dst, alpha);
206     }
207     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
208     {
209         cvtest::multiply(src[0], src[1], dst, alpha);
210     }
211     double getMaxErr(int depth)
212     {
213         return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12;
214     }
215 };
216
217 struct DivOp : public BaseElemWiseOp
218 {
219     DivOp() : BaseElemWiseOp(2, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
220     void op(const vector<Mat>& src, Mat& dst, const Mat&)
221     {
222         cv::divide(src[0], src[1], dst, alpha);
223     }
224     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
225     {
226         cvtest::divide(src[0], src[1], dst, alpha);
227     }
228     double getMaxErr(int depth)
229     {
230         return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12;
231     }
232 };
233
234 struct RecipOp : public BaseElemWiseOp
235 {
236     RecipOp() : BaseElemWiseOp(1, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
237     void op(const vector<Mat>& src, Mat& dst, const Mat&)
238     {
239         cv::divide(alpha, src[0], dst);
240     }
241     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
242     {
243         cvtest::divide(Mat(), src[0], dst, alpha);
244     }
245     double getMaxErr(int depth)
246     {
247         return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12;
248     }
249 };
250
251 struct AbsDiffOp : public BaseAddOp
252 {
253     AbsDiffOp() : BaseAddOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, -1, Scalar::all(0)) {}
254     void op(const vector<Mat>& src, Mat& dst, const Mat&)
255     {
256         absdiff(src[0], src[1], dst);
257     }
258     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
259     {
260         cvtest::add(src[0], 1, src[1], -1, Scalar::all(0), dst, src[0].type(), true);
261     }
262 };
263
264 struct AbsDiffSOp : public BaseAddOp
265 {
266     AbsDiffSOp() : BaseAddOp(1, FIX_ALPHA+FIX_BETA, 1, 0, Scalar::all(0)) {}
267     void op(const vector<Mat>& src, Mat& dst, const Mat&)
268     {
269         absdiff(src[0], gamma, dst);
270     }
271     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
272     {
273         cvtest::add(src[0], 1, Mat(), 0, -gamma, dst, src[0].type(), true);
274     }
275 };
276
277 struct LogicOp : public BaseElemWiseOp
278 {
279     LogicOp(char _opcode) : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)), opcode(_opcode) {}
280     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
281     {
282         if( opcode == '&' )
283             cv::bitwise_and(src[0], src[1], dst, mask);
284         else if( opcode == '|' )
285             cv::bitwise_or(src[0], src[1], dst, mask);
286         else
287             cv::bitwise_xor(src[0], src[1], dst, mask);
288     }
289     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
290     {
291         Mat temp;
292         if( !mask.empty() )
293         {
294             cvtest::logicOp(src[0], src[1], temp, opcode);
295             cvtest::copy(temp, dst, mask);
296         }
297         else
298             cvtest::logicOp(src[0], src[1], dst, opcode);
299     }
300     double getMaxErr(int)
301     {
302         return 0;
303     }
304     char opcode;
305 };
306
307 struct LogicSOp : public BaseElemWiseOp
308 {
309     LogicSOp(char _opcode)
310     : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+(_opcode != '~' ? SUPPORT_MASK : 0), 1, 1, Scalar::all(0)), opcode(_opcode) {}
311     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
312     {
313         if( opcode == '&' )
314             cv::bitwise_and(src[0], gamma, dst, mask);
315         else if( opcode == '|' )
316             cv::bitwise_or(src[0], gamma, dst, mask);
317         else if( opcode == '^' )
318             cv::bitwise_xor(src[0], gamma, dst, mask);
319         else
320             cv::bitwise_not(src[0], dst);
321     }
322     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
323     {
324         Mat temp;
325         if( !mask.empty() )
326         {
327             cvtest::logicOp(src[0], gamma, temp, opcode);
328             cvtest::copy(temp, dst, mask);
329         }
330         else
331             cvtest::logicOp(src[0], gamma, dst, opcode);
332     }
333     double getMaxErr(int)
334     {
335         return 0;
336     }
337     char opcode;
338 };
339
340 struct MinOp : public BaseElemWiseOp
341 {
342     MinOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
343     void op(const vector<Mat>& src, Mat& dst, const Mat&)
344     {
345         cv::min(src[0], src[1], dst);
346     }
347     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
348     {
349         cvtest::min(src[0], src[1], dst);
350     }
351     double getMaxErr(int)
352     {
353         return 0;
354     }
355 };
356
357 struct MaxOp : public BaseElemWiseOp
358 {
359     MaxOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
360     void op(const vector<Mat>& src, Mat& dst, const Mat&)
361     {
362         cv::max(src[0], src[1], dst);
363     }
364     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
365     {
366         cvtest::max(src[0], src[1], dst);
367     }
368     double getMaxErr(int)
369     {
370         return 0;
371     }
372 };
373
374 struct MinSOp : public BaseElemWiseOp
375 {
376     MinSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {}
377     void op(const vector<Mat>& src, Mat& dst, const Mat&)
378     {
379         cv::min(src[0], gamma[0], dst);
380     }
381     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
382     {
383         cvtest::min(src[0], gamma[0], dst);
384     }
385     double getMaxErr(int)
386     {
387         return 0;
388     }
389 };
390
391 struct MaxSOp : public BaseElemWiseOp
392 {
393     MaxSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {}
394     void op(const vector<Mat>& src, Mat& dst, const Mat&)
395     {
396         cv::max(src[0], gamma[0], dst);
397     }
398     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
399     {
400         cvtest::max(src[0], gamma[0], dst);
401     }
402     double getMaxErr(int)
403     {
404         return 0;
405     }
406 };
407
408 struct CmpOp : public BaseElemWiseOp
409 {
410     CmpOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) { cmpop = 0; }
411     void generateScalars(int depth, RNG& rng)
412     {
413         BaseElemWiseOp::generateScalars(depth, rng);
414         cmpop = rng.uniform(0, 6);
415     }
416     void op(const vector<Mat>& src, Mat& dst, const Mat&)
417     {
418         cv::compare(src[0], src[1], dst, cmpop);
419     }
420     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
421     {
422         cvtest::compare(src[0], src[1], dst, cmpop);
423     }
424     int getRandomType(RNG& rng)
425     {
426         return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL_BUT_8S, 1, 1);
427     }
428
429     double getMaxErr(int)
430     {
431         return 0;
432     }
433     int cmpop;
434 };
435
436 struct CmpSOp : public BaseElemWiseOp
437 {
438     CmpSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) { cmpop = 0; }
439     void generateScalars(int depth, RNG& rng)
440     {
441         BaseElemWiseOp::generateScalars(depth, rng);
442         cmpop = rng.uniform(0, 6);
443         if( depth < CV_32F )
444             gamma[0] = cvRound(gamma[0]);
445     }
446     void op(const vector<Mat>& src, Mat& dst, const Mat&)
447     {
448         cv::compare(src[0], gamma[0], dst, cmpop);
449     }
450     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
451     {
452         cvtest::compare(src[0], gamma[0], dst, cmpop);
453     }
454     int getRandomType(RNG& rng)
455     {
456         return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL_BUT_8S, 1, 1);
457     }
458     double getMaxErr(int)
459     {
460         return 0;
461     }
462     int cmpop;
463 };
464
465
466 struct CopyOp : public BaseElemWiseOp
467 {
468     CopyOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SUPPORT_MULTICHANNELMASK, 1, 1, Scalar::all(0)) {  }
469     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
470     {
471         src[0].copyTo(dst, mask);
472     }
473     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
474     {
475         cvtest::copy(src[0], dst, mask);
476     }
477     int getRandomType(RNG& rng)
478     {
479         return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL, 1, ARITHM_MAX_CHANNELS);
480     }
481     double getMaxErr(int)
482     {
483         return 0;
484     }
485 };
486
487
488 struct SetOp : public BaseElemWiseOp
489 {
490     SetOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA+SUPPORT_MASK+SUPPORT_MULTICHANNELMASK, 1, 1, Scalar::all(0)) {}
491     void op(const vector<Mat>&, Mat& dst, const Mat& mask)
492     {
493         dst.setTo(gamma, mask);
494     }
495     void refop(const vector<Mat>&, Mat& dst, const Mat& mask)
496     {
497         cvtest::set(dst, gamma, mask);
498     }
499     int getRandomType(RNG& rng)
500     {
501         return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL, 1, ARITHM_MAX_CHANNELS);
502     }
503     double getMaxErr(int)
504     {
505         return 0;
506     }
507 };
508
509 template<typename _Tp, typename _WTp> static void
510 inRangeS_(const _Tp* src, const _WTp* a, const _WTp* b, uchar* dst, size_t total, int cn)
511 {
512     size_t i;
513     int c;
514     for( i = 0; i < total; i++ )
515     {
516         _Tp val = src[i*cn];
517         dst[i] = (a[0] <= val && val <= b[0]) ? uchar(255) : 0;
518     }
519     for( c = 1; c < cn; c++ )
520     {
521         for( i = 0; i < total; i++ )
522         {
523             _Tp val = src[i*cn + c];
524             dst[i] = a[c] <= val && val <= b[c] ? dst[i] : 0;
525         }
526     }
527 }
528
529 template<typename _Tp> static void inRange_(const _Tp* src, const _Tp* a, const _Tp* b, uchar* dst, size_t total, int cn)
530 {
531     size_t i;
532     int c;
533     for( i = 0; i < total; i++ )
534     {
535         _Tp val = src[i*cn];
536         dst[i] = a[i*cn] <= val && val <= b[i*cn] ? 255 : 0;
537     }
538     for( c = 1; c < cn; c++ )
539     {
540         for( i = 0; i < total; i++ )
541         {
542             _Tp val = src[i*cn + c];
543             dst[i] = a[i*cn + c] <= val && val <= b[i*cn + c] ? dst[i] : 0;
544         }
545     }
546 }
547
548 namespace reference {
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 static void inRangeS(const Mat& src, const Scalar& lb, const Scalar& rb, Mat& dst)
600 {
601     dst.create( src.dims, &src.size[0], CV_8U );
602     const Mat *arrays[]={&src, &dst, 0};
603     Mat planes[2];
604
605     NAryMatIterator it(arrays, planes);
606     size_t total = planes[0].total();
607     size_t i, nplanes = it.nplanes;
608     int depth = src.depth(), cn = src.channels();
609     union { double d[4]; float f[4]; int i[4];} lbuf, rbuf;
610     int wtype = CV_MAKETYPE(depth <= CV_32S ? CV_32S : depth, cn);
611     scalarToRawData(lb, lbuf.d, wtype, cn);
612     scalarToRawData(rb, rbuf.d, wtype, cn);
613
614     for( i = 0; i < nplanes; i++, ++it )
615     {
616         const uchar* sptr = planes[0].ptr();
617         uchar* dptr = planes[1].ptr();
618
619         switch( depth )
620         {
621         case CV_8U:
622             inRangeS_((const uchar*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
623             break;
624         case CV_8S:
625             inRangeS_((const schar*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
626             break;
627         case CV_16U:
628             inRangeS_((const ushort*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
629             break;
630         case CV_16S:
631             inRangeS_((const short*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
632             break;
633         case CV_32S:
634             inRangeS_((const int*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
635             break;
636         case CV_32F:
637             inRangeS_((const float*)sptr, lbuf.f, rbuf.f, dptr, total, cn);
638             break;
639         case CV_64F:
640             inRangeS_((const double*)sptr, lbuf.d, rbuf.d, dptr, total, cn);
641             break;
642         default:
643             CV_Error(CV_StsUnsupportedFormat, "");
644         }
645     }
646 }
647
648 } // namespace
649 CVTEST_GUARD_SYMBOL(inRange);
650
651 struct InRangeSOp : public BaseElemWiseOp
652 {
653     InRangeSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA, 1, 1, Scalar::all(0)) {}
654     void op(const vector<Mat>& src, Mat& dst, const Mat&)
655     {
656         cv::inRange(src[0], gamma, gamma1, dst);
657     }
658     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
659     {
660         reference::inRangeS(src[0], gamma, gamma1, dst);
661     }
662     double getMaxErr(int)
663     {
664         return 0;
665     }
666     void generateScalars(int depth, RNG& rng)
667     {
668         BaseElemWiseOp::generateScalars(depth, rng);
669         Scalar temp = gamma;
670         BaseElemWiseOp::generateScalars(depth, rng);
671         for( int i = 0; i < 4; i++ )
672         {
673             gamma1[i] = std::max(gamma[i], temp[i]);
674             gamma[i] = std::min(gamma[i], temp[i]);
675         }
676     }
677     Scalar gamma1;
678 };
679
680
681 struct InRangeOp : public BaseElemWiseOp
682 {
683     InRangeOp() : BaseElemWiseOp(3, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
684     void op(const vector<Mat>& src, Mat& dst, const Mat&)
685     {
686         Mat lb, rb;
687         cvtest::min(src[1], src[2], lb);
688         cvtest::max(src[1], src[2], rb);
689
690         cv::inRange(src[0], lb, rb, dst);
691     }
692     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
693     {
694         Mat lb, rb;
695         cvtest::min(src[1], src[2], lb);
696         cvtest::max(src[1], src[2], rb);
697
698         reference::inRange(src[0], lb, rb, dst);
699     }
700     double getMaxErr(int)
701     {
702         return 0;
703     }
704 };
705
706
707 struct ConvertScaleOp : public BaseElemWiseOp
708 {
709     ConvertScaleOp() : BaseElemWiseOp(1, FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)), ddepth(0) { }
710     void op(const vector<Mat>& src, Mat& dst, const Mat&)
711     {
712         src[0].convertTo(dst, ddepth, alpha, gamma[0]);
713     }
714     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
715     {
716         cvtest::convert(src[0], dst, CV_MAKETYPE(ddepth, src[0].channels()), alpha, gamma[0]);
717     }
718     int getRandomType(RNG& rng)
719     {
720         int srctype = cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL, 1, ARITHM_MAX_CHANNELS);
721         ddepth = cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL, 1, 1);
722         return srctype;
723     }
724     double getMaxErr(int)
725     {
726         return ddepth <= CV_32S ? 2 : ddepth < CV_64F ? 1e-3 : 1e-12;
727     }
728     void generateScalars(int depth, RNG& rng)
729     {
730         if( rng.uniform(0, 2) )
731             BaseElemWiseOp::generateScalars(depth, rng);
732         else
733         {
734             alpha = 1;
735             gamma = Scalar::all(0);
736         }
737     }
738     int ddepth;
739 };
740
741 struct ConvertScaleFp16Op : public BaseElemWiseOp
742 {
743     ConvertScaleFp16Op() : BaseElemWiseOp(1, FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)), nextRange(0) { }
744     void op(const vector<Mat>& src, Mat& dst, const Mat&)
745     {
746         Mat m;
747         convertFp16(src[0], m);
748         convertFp16(m, dst);
749     }
750     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
751     {
752         cvtest::copy(src[0], dst);
753     }
754     int getRandomType(RNG&)
755     {
756         // 0: FP32 -> FP16 -> FP32
757         // 1: FP16 -> FP32 -> FP16
758         int srctype = (nextRange & 1) == 0 ? CV_32F : CV_16S;
759         return srctype;
760     }
761     void getValueRange(int, double& minval, double& maxval)
762     {
763         // 0: FP32 -> FP16 -> FP32
764         // 1: FP16 -> FP32 -> FP16
765         if( (nextRange & 1) == 0 )
766         {
767             // largest integer number that fp16 can express exactly
768             maxval = 2048.f;
769             minval = -maxval;
770         }
771         else
772         {
773             // 0: positive number range
774             // 1: negative number range
775             if( (nextRange & 2) == 0 )
776             {
777                 minval = 0;      // 0x0000 +0
778                 maxval = 31744;  // 0x7C00 +Inf
779             }
780             else
781             {
782                 minval = -32768; // 0x8000 -0
783                 maxval = -1024;  // 0xFC00 -Inf
784             }
785         }
786     }
787     double getMaxErr(int)
788     {
789         return 0.5f;
790     }
791     void generateScalars(int, RNG& rng)
792     {
793         nextRange = rng.next();
794     }
795     int nextRange;
796 };
797
798 struct ConvertScaleAbsOp : public BaseElemWiseOp
799 {
800     ConvertScaleAbsOp() : BaseElemWiseOp(1, FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {}
801     void op(const vector<Mat>& src, Mat& dst, const Mat&)
802     {
803         cv::convertScaleAbs(src[0], dst, alpha, gamma[0]);
804     }
805     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
806     {
807         cvtest::add(src[0], alpha, Mat(), 0, Scalar::all(gamma[0]), dst, CV_8UC(src[0].channels()), true);
808     }
809     int getRandomType(RNG& rng)
810     {
811         return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL, 1,
812             ninputs > 1 ? ARITHM_MAX_CHANNELS : 4);
813     }
814     double getMaxErr(int)
815     {
816         return 1;
817     }
818     void generateScalars(int depth, RNG& rng)
819     {
820         if( rng.uniform(0, 2) )
821             BaseElemWiseOp::generateScalars(depth, rng);
822         else
823         {
824             alpha = 1;
825             gamma = Scalar::all(0);
826         }
827     }
828 };
829
830 namespace reference {
831
832 static void flip(const Mat& src, Mat& dst, int flipcode)
833 {
834     CV_Assert(src.dims == 2);
835     dst.create(src.size(), src.type());
836     int i, j, k, esz = (int)src.elemSize(), width = src.cols*esz;
837
838     for( i = 0; i < dst.rows; i++ )
839     {
840         const uchar* sptr = src.ptr(flipcode == 1 ? i : dst.rows - i - 1);
841         uchar* dptr = dst.ptr(i);
842         if( flipcode == 0 )
843             memcpy(dptr, sptr, width);
844         else
845         {
846             for( j = 0; j < width; j += esz )
847                 for( k = 0; k < esz; k++ )
848                     dptr[j + k] = sptr[width - j - esz + k];
849         }
850     }
851 }
852
853
854 static void setIdentity(Mat& dst, const Scalar& s)
855 {
856     CV_Assert( dst.dims == 2 && dst.channels() <= 4 );
857     double buf[4];
858     scalarToRawData(s, buf, dst.type(), 0);
859     int i, k, esz = (int)dst.elemSize(), width = dst.cols*esz;
860
861     for( i = 0; i < dst.rows; i++ )
862     {
863         uchar* dptr = dst.ptr(i);
864         memset( dptr, 0, width );
865         if( i < dst.cols )
866             for( k = 0; k < esz; k++ )
867                 dptr[i*esz + k] = ((uchar*)buf)[k];
868     }
869 }
870
871 } // namespace
872
873 struct FlipOp : public BaseElemWiseOp
874 {
875     FlipOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) { flipcode = 0; }
876     void getRandomSize(RNG& rng, vector<int>& size)
877     {
878         cvtest::randomSize(rng, 2, 2, ARITHM_MAX_SIZE_LOG, size);
879     }
880     void op(const vector<Mat>& src, Mat& dst, const Mat&)
881     {
882         cv::flip(src[0], dst, flipcode);
883     }
884     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
885     {
886         reference::flip(src[0], dst, flipcode);
887     }
888     void generateScalars(int, RNG& rng)
889     {
890         flipcode = rng.uniform(0, 3) - 1;
891     }
892     double getMaxErr(int)
893     {
894         return 0;
895     }
896     int flipcode;
897 };
898
899 struct TransposeOp : public BaseElemWiseOp
900 {
901     TransposeOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
902     void getRandomSize(RNG& rng, vector<int>& size)
903     {
904         cvtest::randomSize(rng, 2, 2, ARITHM_MAX_SIZE_LOG, size);
905     }
906     void op(const vector<Mat>& src, Mat& dst, const Mat&)
907     {
908         cv::transpose(src[0], dst);
909     }
910     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
911     {
912         cvtest::transpose(src[0], dst);
913     }
914     double getMaxErr(int)
915     {
916         return 0;
917     }
918 };
919
920 struct SetIdentityOp : public BaseElemWiseOp
921 {
922     SetIdentityOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA, 1, 1, Scalar::all(0)) {}
923     void getRandomSize(RNG& rng, vector<int>& size)
924     {
925         cvtest::randomSize(rng, 2, 2, ARITHM_MAX_SIZE_LOG, size);
926     }
927     void op(const vector<Mat>&, Mat& dst, const Mat&)
928     {
929         cv::setIdentity(dst, gamma);
930     }
931     void refop(const vector<Mat>&, Mat& dst, const Mat&)
932     {
933         reference::setIdentity(dst, gamma);
934     }
935     double getMaxErr(int)
936     {
937         return 0;
938     }
939 };
940
941 struct SetZeroOp : public BaseElemWiseOp
942 {
943     SetZeroOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
944     void op(const vector<Mat>&, Mat& dst, const Mat&)
945     {
946         dst = Scalar::all(0);
947     }
948     void refop(const vector<Mat>&, Mat& dst, const Mat&)
949     {
950         cvtest::set(dst, Scalar::all(0));
951     }
952     double getMaxErr(int)
953     {
954         return 0;
955     }
956 };
957
958 namespace reference {
959 static void exp(const Mat& src, Mat& dst)
960 {
961     dst.create( src.dims, &src.size[0], src.type() );
962     const Mat *arrays[]={&src, &dst, 0};
963     Mat planes[2];
964
965     NAryMatIterator it(arrays, planes);
966     size_t j, total = planes[0].total()*src.channels();
967     size_t i, nplanes = it.nplanes;
968     int depth = src.depth();
969
970     for( i = 0; i < nplanes; i++, ++it )
971     {
972         const uchar* sptr = planes[0].ptr();
973         uchar* dptr = planes[1].ptr();
974
975         if( depth == CV_32F )
976         {
977             for( j = 0; j < total; j++ )
978                 ((float*)dptr)[j] = std::exp(((const float*)sptr)[j]);
979         }
980         else if( depth == CV_64F )
981         {
982             for( j = 0; j < total; j++ )
983                 ((double*)dptr)[j] = std::exp(((const double*)sptr)[j]);
984         }
985     }
986 }
987
988 static void log(const Mat& src, Mat& dst)
989 {
990     dst.create( src.dims, &src.size[0], src.type() );
991     const Mat *arrays[]={&src, &dst, 0};
992     Mat planes[2];
993
994     NAryMatIterator it(arrays, planes);
995     size_t j, total = planes[0].total()*src.channels();
996     size_t i, nplanes = it.nplanes;
997     int depth = src.depth();
998
999     for( i = 0; i < nplanes; i++, ++it )
1000     {
1001         const uchar* sptr = planes[0].ptr();
1002         uchar* dptr = planes[1].ptr();
1003
1004         if( depth == CV_32F )
1005         {
1006             for( j = 0; j < total; j++ )
1007                 ((float*)dptr)[j] = (float)std::log(fabs(((const float*)sptr)[j]));
1008         }
1009         else if( depth == CV_64F )
1010         {
1011             for( j = 0; j < total; j++ )
1012                 ((double*)dptr)[j] = std::log(fabs(((const double*)sptr)[j]));
1013         }
1014     }
1015 }
1016
1017 } // namespace
1018
1019 struct ExpOp : public BaseElemWiseOp
1020 {
1021     ExpOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
1022     int getRandomType(RNG& rng)
1023     {
1024         return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_FLT, 1, ARITHM_MAX_CHANNELS);
1025     }
1026     void getValueRange(int depth, double& minval, double& maxval)
1027     {
1028         maxval = depth == CV_32F ? 50 : 100;
1029         minval = -maxval;
1030     }
1031     void op(const vector<Mat>& src, Mat& dst, const Mat&)
1032     {
1033         cv::exp(src[0], dst);
1034     }
1035     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
1036     {
1037         reference::exp(src[0], dst);
1038     }
1039     double getMaxErr(int depth)
1040     {
1041         return depth == CV_32F ? 1e-5 : 1e-12;
1042     }
1043 };
1044
1045
1046 struct LogOp : public BaseElemWiseOp
1047 {
1048     LogOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
1049     int getRandomType(RNG& rng)
1050     {
1051         return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_FLT, 1, ARITHM_MAX_CHANNELS);
1052     }
1053     void getValueRange(int depth, double& minval, double& maxval)
1054     {
1055         maxval = depth == CV_32F ? 50 : 100;
1056         minval = -maxval;
1057     }
1058     void op(const vector<Mat>& src, Mat& dst, const Mat&)
1059     {
1060         Mat temp;
1061         reference::exp(src[0], temp);
1062         cv::log(temp, dst);
1063     }
1064     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
1065     {
1066         Mat temp;
1067         reference::exp(src[0], temp);
1068         reference::log(temp, dst);
1069     }
1070     double getMaxErr(int depth)
1071     {
1072         return depth == CV_32F ? 1e-5 : 1e-12;
1073     }
1074 };
1075
1076
1077 namespace reference {
1078 static void cartToPolar(const Mat& mx, const Mat& my, Mat& mmag, Mat& mangle, bool angleInDegrees)
1079 {
1080     CV_Assert( (mx.type() == CV_32F || mx.type() == CV_64F) &&
1081               mx.type() == my.type() && mx.size == my.size );
1082     mmag.create( mx.dims, &mx.size[0], mx.type() );
1083     mangle.create( mx.dims, &mx.size[0], mx.type() );
1084     const Mat *arrays[]={&mx, &my, &mmag, &mangle, 0};
1085     Mat planes[4];
1086
1087     NAryMatIterator it(arrays, planes);
1088     size_t j, total = planes[0].total();
1089     size_t i, nplanes = it.nplanes;
1090     int depth = mx.depth();
1091     double scale = angleInDegrees ? 180/CV_PI : 1;
1092
1093     for( i = 0; i < nplanes; i++, ++it )
1094     {
1095         if( depth == CV_32F )
1096         {
1097             const float* xptr = planes[0].ptr<float>();
1098             const float* yptr = planes[1].ptr<float>();
1099             float* mptr = planes[2].ptr<float>();
1100             float* aptr = planes[3].ptr<float>();
1101
1102             for( j = 0; j < total; j++ )
1103             {
1104                 mptr[j] = std::sqrt(xptr[j]*xptr[j] + yptr[j]*yptr[j]);
1105                 double a = atan2((double)yptr[j], (double)xptr[j]);
1106                 if( a < 0 ) a += CV_PI*2;
1107                 aptr[j] = (float)(a*scale);
1108             }
1109         }
1110         else
1111         {
1112             const double* xptr = planes[0].ptr<double>();
1113             const double* yptr = planes[1].ptr<double>();
1114             double* mptr = planes[2].ptr<double>();
1115             double* aptr = planes[3].ptr<double>();
1116
1117             for( j = 0; j < total; j++ )
1118             {
1119                 mptr[j] = std::sqrt(xptr[j]*xptr[j] + yptr[j]*yptr[j]);
1120                 double a = atan2(yptr[j], xptr[j]);
1121                 if( a < 0 ) a += CV_PI*2;
1122                 aptr[j] = a*scale;
1123             }
1124         }
1125     }
1126 }
1127
1128 } // namespace
1129
1130 struct CartToPolarToCartOp : public BaseElemWiseOp
1131 {
1132     CartToPolarToCartOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0))
1133     {
1134         context = 3;
1135         angleInDegrees = true;
1136     }
1137     int getRandomType(RNG& rng)
1138     {
1139         return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_FLT, 1, 1);
1140     }
1141     void op(const vector<Mat>& src, Mat& dst, const Mat&)
1142     {
1143         Mat mag, angle, x, y;
1144
1145         cv::cartToPolar(src[0], src[1], mag, angle, angleInDegrees);
1146         cv::polarToCart(mag, angle, x, y, angleInDegrees);
1147
1148         Mat msrc[] = {mag, angle, x, y};
1149         int pairs[] = {0, 0, 1, 1, 2, 2, 3, 3};
1150         dst.create(src[0].dims, src[0].size, CV_MAKETYPE(src[0].depth(), 4));
1151         cv::mixChannels(msrc, 4, &dst, 1, pairs, 4);
1152     }
1153     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
1154     {
1155         Mat mag, angle;
1156         reference::cartToPolar(src[0], src[1], mag, angle, angleInDegrees);
1157         Mat msrc[] = {mag, angle, src[0], src[1]};
1158         int pairs[] = {0, 0, 1, 1, 2, 2, 3, 3};
1159         dst.create(src[0].dims, src[0].size, CV_MAKETYPE(src[0].depth(), 4));
1160         cv::mixChannels(msrc, 4, &dst, 1, pairs, 4);
1161     }
1162     void generateScalars(int, RNG& rng)
1163     {
1164         angleInDegrees = rng.uniform(0, 2) != 0;
1165     }
1166     double getMaxErr(int)
1167     {
1168         return 1e-3;
1169     }
1170     bool angleInDegrees;
1171 };
1172
1173
1174 struct MeanOp : public BaseElemWiseOp
1175 {
1176     MeanOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
1177     {
1178         context = 3;
1179     };
1180     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
1181     {
1182         dst.create(1, 1, CV_64FC4);
1183         dst.at<Scalar>(0,0) = cv::mean(src[0], mask);
1184     }
1185     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
1186     {
1187         dst.create(1, 1, CV_64FC4);
1188         dst.at<Scalar>(0,0) = cvtest::mean(src[0], mask);
1189     }
1190     double getMaxErr(int)
1191     {
1192         return 1e-5;
1193     }
1194 };
1195
1196
1197 struct SumOp : public BaseElemWiseOp
1198 {
1199     SumOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
1200     {
1201         context = 3;
1202     };
1203     void op(const vector<Mat>& src, Mat& dst, const Mat&)
1204     {
1205         dst.create(1, 1, CV_64FC4);
1206         dst.at<Scalar>(0,0) = cv::sum(src[0]);
1207     }
1208     void refop(const vector<Mat>& src, Mat& dst, const Mat&)
1209     {
1210         dst.create(1, 1, CV_64FC4);
1211         dst.at<Scalar>(0,0) = cvtest::mean(src[0])*(double)src[0].total();
1212     }
1213     double getMaxErr(int)
1214     {
1215         return 1e-5;
1216     }
1217 };
1218
1219
1220 struct CountNonZeroOp : public BaseElemWiseOp
1221 {
1222     CountNonZeroOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SCALAR_OUTPUT+SUPPORT_MASK, 1, 1, Scalar::all(0))
1223     {}
1224     int getRandomType(RNG& rng)
1225     {
1226         return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL, 1, 1);
1227     }
1228     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
1229     {
1230         Mat temp;
1231         src[0].copyTo(temp);
1232         if( !mask.empty() )
1233             temp.setTo(Scalar::all(0), mask);
1234         dst.create(1, 1, CV_32S);
1235         dst.at<int>(0,0) = cv::countNonZero(temp);
1236     }
1237     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
1238     {
1239         Mat temp;
1240         cvtest::compare(src[0], 0, temp, CMP_NE);
1241         if( !mask.empty() )
1242             cvtest::set(temp, Scalar::all(0), mask);
1243         dst.create(1, 1, CV_32S);
1244         dst.at<int>(0,0) = saturate_cast<int>(cvtest::mean(temp)[0]/255*temp.total());
1245     }
1246     double getMaxErr(int)
1247     {
1248         return 0;
1249     }
1250 };
1251
1252
1253 struct MeanStdDevOp : public BaseElemWiseOp
1254 {
1255     Scalar sqmeanRef;
1256     int cn;
1257
1258     MeanStdDevOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
1259     {
1260         cn = 0;
1261         context = 7;
1262     };
1263     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
1264     {
1265         dst.create(1, 2, CV_64FC4);
1266         cv::meanStdDev(src[0], dst.at<Scalar>(0,0), dst.at<Scalar>(0,1), mask);
1267     }
1268     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
1269     {
1270         Mat temp;
1271         cvtest::convert(src[0], temp, CV_64F);
1272         cvtest::multiply(temp, temp, temp);
1273         Scalar mean = cvtest::mean(src[0], mask);
1274         Scalar sqmean = cvtest::mean(temp, mask);
1275
1276         sqmeanRef = sqmean;
1277         cn = temp.channels();
1278
1279         for( int c = 0; c < 4; c++ )
1280             sqmean[c] = std::sqrt(std::max(sqmean[c] - mean[c]*mean[c], 0.));
1281
1282         dst.create(1, 2, CV_64FC4);
1283         dst.at<Scalar>(0,0) = mean;
1284         dst.at<Scalar>(0,1) = sqmean;
1285     }
1286     double getMaxErr(int)
1287     {
1288         CV_Assert(cn > 0);
1289         double err = sqmeanRef[0];
1290         for(int i = 1; i < cn; ++i)
1291             err = std::max(err, sqmeanRef[i]);
1292         return 3e-7 * err;
1293     }
1294 };
1295
1296
1297 struct NormOp : public BaseElemWiseOp
1298 {
1299     NormOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
1300     {
1301         context = 1;
1302         normType = 0;
1303     };
1304     int getRandomType(RNG& rng)
1305     {
1306         int type = cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL_BUT_8S, 1, 4);
1307         for(;;)
1308         {
1309             normType = rng.uniform(1, 8);
1310             if( normType == NORM_INF || normType == NORM_L1 ||
1311                 normType == NORM_L2 || normType == NORM_L2SQR ||
1312                 normType == NORM_HAMMING || normType == NORM_HAMMING2 )
1313                 break;
1314         }
1315         if( normType == NORM_HAMMING || normType == NORM_HAMMING2 )
1316         {
1317             type = CV_8U;
1318         }
1319         return type;
1320     }
1321     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
1322     {
1323         dst.create(1, 2, CV_64FC1);
1324         dst.at<double>(0,0) = cv::norm(src[0], normType, mask);
1325         dst.at<double>(0,1) = cv::norm(src[0], src[1], normType, mask);
1326     }
1327     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
1328     {
1329         dst.create(1, 2, CV_64FC1);
1330         dst.at<double>(0,0) = cvtest::norm(src[0], normType, mask);
1331         dst.at<double>(0,1) = cvtest::norm(src[0], src[1], normType, mask);
1332     }
1333     void generateScalars(int, RNG& /*rng*/)
1334     {
1335     }
1336     double getMaxErr(int)
1337     {
1338         return 1e-6;
1339     }
1340     int normType;
1341 };
1342
1343
1344 struct MinMaxLocOp : public BaseElemWiseOp
1345 {
1346     MinMaxLocOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
1347     {
1348         context = ARITHM_MAX_NDIMS*2 + 2;
1349     };
1350     int getRandomType(RNG& rng)
1351     {
1352         return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL_BUT_8S, 1, 1);
1353     }
1354     void saveOutput(const vector<int>& minidx, const vector<int>& maxidx,
1355                     double minval, double maxval, Mat& dst)
1356     {
1357         int i, ndims = (int)minidx.size();
1358         dst.create(1, ndims*2 + 2, CV_64FC1);
1359
1360         for( i = 0; i < ndims; i++ )
1361         {
1362             dst.at<double>(0,i) = minidx[i];
1363             dst.at<double>(0,i+ndims) = maxidx[i];
1364         }
1365         dst.at<double>(0,ndims*2) = minval;
1366         dst.at<double>(0,ndims*2+1) = maxval;
1367     }
1368     void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
1369     {
1370         int ndims = src[0].dims;
1371         vector<int> minidx(ndims), maxidx(ndims);
1372         double minval=0, maxval=0;
1373         cv::minMaxIdx(src[0], &minval, &maxval, &minidx[0], &maxidx[0], mask);
1374         saveOutput(minidx, maxidx, minval, maxval, dst);
1375     }
1376     void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
1377     {
1378         int ndims=src[0].dims;
1379         vector<int> minidx(ndims), maxidx(ndims);
1380         double minval=0, maxval=0;
1381         cvtest::minMaxLoc(src[0], &minval, &maxval, &minidx, &maxidx, mask);
1382         saveOutput(minidx, maxidx, minval, maxval, dst);
1383     }
1384     double getMaxErr(int)
1385     {
1386         return 0;
1387     }
1388 };
1389
1390
1391 typedef Ptr<BaseElemWiseOp> ElemWiseOpPtr;
1392 class ElemWiseTest : public ::testing::TestWithParam<ElemWiseOpPtr> {};
1393
1394 TEST_P(ElemWiseTest, accuracy)
1395 {
1396     ElemWiseOpPtr op = GetParam();
1397
1398     int testIdx = 0;
1399     RNG rng((uint64)ARITHM_RNG_SEED);
1400     for( testIdx = 0; testIdx < ARITHM_NTESTS; testIdx++ )
1401     {
1402         vector<int> size;
1403         op->getRandomSize(rng, size);
1404         int type = op->getRandomType(rng);
1405         int depth = CV_MAT_DEPTH(type);
1406         bool haveMask = ((op->flags & BaseElemWiseOp::SUPPORT_MASK) != 0
1407                 || (op->flags & BaseElemWiseOp::SUPPORT_MULTICHANNELMASK) != 0) && rng.uniform(0, 4) == 0;
1408
1409         double minval=0, maxval=0;
1410         op->getValueRange(depth, minval, maxval);
1411         int i, ninputs = op->ninputs;
1412         vector<Mat> src(ninputs);
1413         for( i = 0; i < ninputs; i++ )
1414             src[i] = cvtest::randomMat(rng, size, type, minval, maxval, true);
1415         Mat dst0, dst, mask;
1416         if( haveMask ) {
1417             bool multiChannelMask = (op->flags & BaseElemWiseOp::SUPPORT_MULTICHANNELMASK) != 0
1418                     && rng.uniform(0, 2) == 0;
1419             int masktype = CV_8UC(multiChannelMask ? CV_MAT_CN(type) : 1);
1420             mask = cvtest::randomMat(rng, size, masktype, 0, 2, true);
1421         }
1422
1423         if( (haveMask || ninputs == 0) && !(op->flags & BaseElemWiseOp::SCALAR_OUTPUT))
1424         {
1425             dst0 = cvtest::randomMat(rng, size, type, minval, maxval, false);
1426             dst = cvtest::randomMat(rng, size, type, minval, maxval, true);
1427             cvtest::copy(dst, dst0);
1428         }
1429         op->generateScalars(depth, rng);
1430
1431         op->refop(src, dst0, mask);
1432         op->op(src, dst, mask);
1433
1434         double maxErr = op->getMaxErr(depth);
1435         ASSERT_PRED_FORMAT2(cvtest::MatComparator(maxErr, op->context), dst0, dst) << "\nsrc[0] ~ " <<
1436             cvtest::MatInfo(!src.empty() ? src[0] : Mat()) << "\ntestCase #" << testIdx << "\n";
1437     }
1438 }
1439
1440
1441 INSTANTIATE_TEST_CASE_P(Core_Copy, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new CopyOp)));
1442 INSTANTIATE_TEST_CASE_P(Core_Set, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new SetOp)));
1443 INSTANTIATE_TEST_CASE_P(Core_SetZero, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new SetZeroOp)));
1444 INSTANTIATE_TEST_CASE_P(Core_ConvertScale, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new ConvertScaleOp)));
1445 INSTANTIATE_TEST_CASE_P(Core_ConvertScaleFp16, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new ConvertScaleFp16Op)));
1446 INSTANTIATE_TEST_CASE_P(Core_ConvertScaleAbs, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new ConvertScaleAbsOp)));
1447
1448 INSTANTIATE_TEST_CASE_P(Core_Add, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new AddOp)));
1449 INSTANTIATE_TEST_CASE_P(Core_Sub, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new SubOp)));
1450 INSTANTIATE_TEST_CASE_P(Core_AddS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new AddSOp)));
1451 INSTANTIATE_TEST_CASE_P(Core_SubRS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new SubRSOp)));
1452 INSTANTIATE_TEST_CASE_P(Core_ScaleAdd, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new ScaleAddOp)));
1453 INSTANTIATE_TEST_CASE_P(Core_AddWeighted, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new AddWeightedOp)));
1454 INSTANTIATE_TEST_CASE_P(Core_AbsDiff, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new AbsDiffOp)));
1455
1456
1457 INSTANTIATE_TEST_CASE_P(Core_AbsDiffS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new AbsDiffSOp)));
1458
1459 INSTANTIATE_TEST_CASE_P(Core_And, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new LogicOp('&'))));
1460 INSTANTIATE_TEST_CASE_P(Core_AndS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new LogicSOp('&'))));
1461 INSTANTIATE_TEST_CASE_P(Core_Or, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new LogicOp('|'))));
1462 INSTANTIATE_TEST_CASE_P(Core_OrS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new LogicSOp('|'))));
1463 INSTANTIATE_TEST_CASE_P(Core_Xor, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new LogicOp('^'))));
1464 INSTANTIATE_TEST_CASE_P(Core_XorS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new LogicSOp('^'))));
1465 INSTANTIATE_TEST_CASE_P(Core_Not, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new LogicSOp('~'))));
1466
1467 INSTANTIATE_TEST_CASE_P(Core_Max, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new MaxOp)));
1468 INSTANTIATE_TEST_CASE_P(Core_MaxS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new MaxSOp)));
1469 INSTANTIATE_TEST_CASE_P(Core_Min, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new MinOp)));
1470 INSTANTIATE_TEST_CASE_P(Core_MinS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new MinSOp)));
1471
1472 INSTANTIATE_TEST_CASE_P(Core_Mul, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new MulOp)));
1473 INSTANTIATE_TEST_CASE_P(Core_Div, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new DivOp)));
1474 INSTANTIATE_TEST_CASE_P(Core_Recip, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new RecipOp)));
1475
1476 INSTANTIATE_TEST_CASE_P(Core_Cmp, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new CmpOp)));
1477 INSTANTIATE_TEST_CASE_P(Core_CmpS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new CmpSOp)));
1478
1479 INSTANTIATE_TEST_CASE_P(Core_InRangeS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new InRangeSOp)));
1480 INSTANTIATE_TEST_CASE_P(Core_InRange, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new InRangeOp)));
1481
1482 INSTANTIATE_TEST_CASE_P(Core_Flip, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new FlipOp)));
1483 INSTANTIATE_TEST_CASE_P(Core_Transpose, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new TransposeOp)));
1484 INSTANTIATE_TEST_CASE_P(Core_SetIdentity, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new SetIdentityOp)));
1485
1486 INSTANTIATE_TEST_CASE_P(Core_Exp, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new ExpOp)));
1487 INSTANTIATE_TEST_CASE_P(Core_Log, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new LogOp)));
1488
1489 INSTANTIATE_TEST_CASE_P(Core_CountNonZero, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new CountNonZeroOp)));
1490 INSTANTIATE_TEST_CASE_P(Core_Mean, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new MeanOp)));
1491 INSTANTIATE_TEST_CASE_P(Core_MeanStdDev, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new MeanStdDevOp)));
1492 INSTANTIATE_TEST_CASE_P(Core_Sum, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new SumOp)));
1493 INSTANTIATE_TEST_CASE_P(Core_Norm, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new NormOp)));
1494 INSTANTIATE_TEST_CASE_P(Core_MinMaxLoc, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new MinMaxLocOp)));
1495 INSTANTIATE_TEST_CASE_P(Core_CartToPolarToCart, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new CartToPolarToCartOp)));
1496
1497
1498 TEST(Core_ArithmMask, uninitialized)
1499 {
1500             RNG& rng = theRNG();
1501             const int MAX_DIM=3;
1502             int sizes[MAX_DIM];
1503             for( int iter = 0; iter < 100; iter++ )
1504             {
1505                 int dims = rng.uniform(1, MAX_DIM+1);
1506                 int depth = rng.uniform(CV_8U, CV_64F+1);
1507                 int cn = rng.uniform(1, 6);
1508                 int type = CV_MAKETYPE(depth, cn);
1509                 int op = rng.uniform(0, depth < CV_32F ? 5 : 2); // don't run binary operations between floating-point values
1510                 int depth1 = op <= 1 ? CV_64F : depth;
1511                 for (int k = 0; k < MAX_DIM; k++)
1512                 {
1513                     sizes[k] = k < dims ? rng.uniform(1, 30) : 0;
1514                 }
1515                 SCOPED_TRACE(cv::format("iter=%d dims=%d depth=%d cn=%d type=%d op=%d depth1=%d dims=[%d; %d; %d]",
1516                                          iter,   dims,   depth,   cn,   type,   op,   depth1, sizes[0], sizes[1], sizes[2]));
1517
1518                 Mat a(dims, sizes, type), a1;
1519                 Mat b(dims, sizes, type), b1;
1520                 Mat mask(dims, sizes, CV_8U);
1521                 Mat mask1;
1522                 Mat c, d;
1523
1524                 rng.fill(a, RNG::UNIFORM, 0, 100);
1525                 rng.fill(b, RNG::UNIFORM, 0, 100);
1526
1527                 // [-2,2) range means that the each generated random number
1528                 // will be one of -2, -1, 0, 1. Saturated to [0,255], it will become
1529                 // 0, 0, 0, 1 => the mask will be filled by ~25%.
1530                 rng.fill(mask, RNG::UNIFORM, -2, 2);
1531
1532                 a.convertTo(a1, depth1);
1533                 b.convertTo(b1, depth1);
1534                 // invert the mask
1535                 cv::compare(mask, 0, mask1, CMP_EQ);
1536                 a1.setTo(0, mask1);
1537                 b1.setTo(0, mask1);
1538
1539                 if( op == 0 )
1540                 {
1541                     cv::add(a, b, c, mask);
1542                     cv::add(a1, b1, d);
1543                 }
1544                 else if( op == 1 )
1545                 {
1546                     cv::subtract(a, b, c, mask);
1547                     cv::subtract(a1, b1, d);
1548                 }
1549                 else if( op == 2 )
1550                 {
1551                     cv::bitwise_and(a, b, c, mask);
1552                     cv::bitwise_and(a1, b1, d);
1553                 }
1554                 else if( op == 3 )
1555                 {
1556                     cv::bitwise_or(a, b, c, mask);
1557                     cv::bitwise_or(a1, b1, d);
1558                 }
1559                 else if( op == 4 )
1560                 {
1561                     cv::bitwise_xor(a, b, c, mask);
1562                     cv::bitwise_xor(a1, b1, d);
1563                 }
1564                 Mat d1;
1565                 d.convertTo(d1, depth);
1566                 EXPECT_LE(cvtest::norm(c, d1, CV_C), DBL_EPSILON);
1567             }
1568
1569             Mat_<uchar> tmpSrc(100,100);
1570             tmpSrc = 124;
1571             Mat_<uchar> tmpMask(100,100);
1572             tmpMask = 255;
1573             Mat_<uchar> tmpDst(100,100);
1574             tmpDst = 2;
1575             tmpSrc.copyTo(tmpDst,tmpMask);
1576 }
1577
1578 TEST(Multiply, FloatingPointRounding)
1579 {
1580     cv::Mat src(1, 1, CV_8UC1, cv::Scalar::all(110)), dst;
1581     cv::Scalar s(147.286359696927, 1, 1 ,1);
1582
1583     cv::multiply(src, s, dst, 1, CV_16U);
1584     // with CV_32F this produce result 16202
1585     ASSERT_EQ(dst.at<ushort>(0,0), 16201);
1586 }
1587
1588 TEST(Core_Add, AddToColumnWhen3Rows)
1589 {
1590     cv::Mat m1 = (cv::Mat_<double>(3, 2) << 1, 2, 3, 4, 5, 6);
1591     m1.col(1) += 10;
1592
1593     cv::Mat m2 = (cv::Mat_<double>(3, 2) << 1, 12, 3, 14, 5, 16);
1594
1595     ASSERT_EQ(0, countNonZero(m1 - m2));
1596 }
1597
1598 TEST(Core_Add, AddToColumnWhen4Rows)
1599 {
1600     cv::Mat m1 = (cv::Mat_<double>(4, 2) << 1, 2, 3, 4, 5, 6, 7, 8);
1601     m1.col(1) += 10;
1602
1603     cv::Mat m2 = (cv::Mat_<double>(4, 2) << 1, 12, 3, 14, 5, 16, 7, 18);
1604
1605     ASSERT_EQ(0, countNonZero(m1 - m2));
1606 }
1607
1608 TEST(Core_round, CvRound)
1609 {
1610     ASSERT_EQ(2, cvRound(2.0));
1611     ASSERT_EQ(2, cvRound(2.1));
1612     ASSERT_EQ(-2, cvRound(-2.1));
1613     ASSERT_EQ(3, cvRound(2.8));
1614     ASSERT_EQ(-3, cvRound(-2.8));
1615     ASSERT_EQ(2, cvRound(2.5));
1616     ASSERT_EQ(4, cvRound(3.5));
1617     ASSERT_EQ(-2, cvRound(-2.5));
1618     ASSERT_EQ(-4, cvRound(-3.5));
1619 }
1620
1621
1622 typedef testing::TestWithParam<Size> Mul1;
1623
1624 TEST_P(Mul1, One)
1625 {
1626     Size size = GetParam();
1627     cv::Mat src(size, CV_32FC1, cv::Scalar::all(2)), dst,
1628             ref_dst(size, CV_32FC1, cv::Scalar::all(6));
1629
1630     cv::multiply(3, src, dst);
1631
1632     ASSERT_EQ(0, cvtest::norm(dst, ref_dst, cv::NORM_INF));
1633 }
1634
1635 INSTANTIATE_TEST_CASE_P(Arithm, Mul1, testing::Values(Size(2, 2), Size(1, 1)));
1636
1637 class SubtractOutputMatNotEmpty : public testing::TestWithParam< tuple<cv::Size, perf::MatType, perf::MatDepth, bool> >
1638 {
1639 public:
1640     cv::Size size;
1641     int src_type;
1642     int dst_depth;
1643     bool fixed;
1644
1645     void SetUp()
1646     {
1647         size = get<0>(GetParam());
1648         src_type = get<1>(GetParam());
1649         dst_depth = get<2>(GetParam());
1650         fixed = get<3>(GetParam());
1651     }
1652 };
1653
1654 TEST_P(SubtractOutputMatNotEmpty, Mat_Mat)
1655 {
1656     cv::Mat src1(size, src_type, cv::Scalar::all(16));
1657     cv::Mat src2(size, src_type, cv::Scalar::all(16));
1658
1659     cv::Mat dst;
1660
1661     if (!fixed)
1662     {
1663         cv::subtract(src1, src2, dst, cv::noArray(), dst_depth);
1664     }
1665     else
1666     {
1667         const cv::Mat fixed_dst(size, CV_MAKE_TYPE((dst_depth > 0 ? dst_depth : CV_16S), src1.channels()));
1668         cv::subtract(src1, src2, fixed_dst, cv::noArray(), dst_depth);
1669         dst = fixed_dst;
1670         dst_depth = fixed_dst.depth();
1671     }
1672
1673     ASSERT_FALSE(dst.empty());
1674     ASSERT_EQ(src1.size(), dst.size());
1675     ASSERT_EQ(dst_depth > 0 ? dst_depth : src1.depth(), dst.depth());
1676     ASSERT_EQ(0, cv::countNonZero(dst.reshape(1)));
1677 }
1678
1679 TEST_P(SubtractOutputMatNotEmpty, Mat_Mat_WithMask)
1680 {
1681     cv::Mat src1(size, src_type, cv::Scalar::all(16));
1682     cv::Mat src2(size, src_type, cv::Scalar::all(16));
1683     cv::Mat mask(size, CV_8UC1, cv::Scalar::all(255));
1684
1685     cv::Mat dst;
1686
1687     if (!fixed)
1688     {
1689         cv::subtract(src1, src2, dst, mask, dst_depth);
1690     }
1691     else
1692     {
1693         const cv::Mat fixed_dst(size, CV_MAKE_TYPE((dst_depth > 0 ? dst_depth : CV_16S), src1.channels()));
1694         cv::subtract(src1, src2, fixed_dst, mask, dst_depth);
1695         dst = fixed_dst;
1696         dst_depth = fixed_dst.depth();
1697     }
1698
1699     ASSERT_FALSE(dst.empty());
1700     ASSERT_EQ(src1.size(), dst.size());
1701     ASSERT_EQ(dst_depth > 0 ? dst_depth : src1.depth(), dst.depth());
1702     ASSERT_EQ(0, cv::countNonZero(dst.reshape(1)));
1703 }
1704
1705 TEST_P(SubtractOutputMatNotEmpty, Mat_Mat_Expr)
1706 {
1707     cv::Mat src1(size, src_type, cv::Scalar::all(16));
1708     cv::Mat src2(size, src_type, cv::Scalar::all(16));
1709
1710     cv::Mat dst = src1 - src2;
1711
1712     ASSERT_FALSE(dst.empty());
1713     ASSERT_EQ(src1.size(), dst.size());
1714     ASSERT_EQ(src1.depth(), dst.depth());
1715     ASSERT_EQ(0, cv::countNonZero(dst.reshape(1)));
1716 }
1717
1718 TEST_P(SubtractOutputMatNotEmpty, Mat_Scalar)
1719 {
1720     cv::Mat src(size, src_type, cv::Scalar::all(16));
1721
1722     cv::Mat dst;
1723
1724     if (!fixed)
1725     {
1726         cv::subtract(src, cv::Scalar::all(16), dst, cv::noArray(), dst_depth);
1727     }
1728     else
1729     {
1730         const cv::Mat fixed_dst(size, CV_MAKE_TYPE((dst_depth > 0 ? dst_depth : CV_16S), src.channels()));
1731         cv::subtract(src, cv::Scalar::all(16), fixed_dst, cv::noArray(), dst_depth);
1732         dst = fixed_dst;
1733         dst_depth = fixed_dst.depth();
1734     }
1735
1736     ASSERT_FALSE(dst.empty());
1737     ASSERT_EQ(src.size(), dst.size());
1738     ASSERT_EQ(dst_depth > 0 ? dst_depth : src.depth(), dst.depth());
1739     ASSERT_EQ(0, cv::countNonZero(dst.reshape(1)));
1740 }
1741
1742 TEST_P(SubtractOutputMatNotEmpty, Mat_Scalar_WithMask)
1743 {
1744     cv::Mat src(size, src_type, cv::Scalar::all(16));
1745     cv::Mat mask(size, CV_8UC1, cv::Scalar::all(255));
1746
1747     cv::Mat dst;
1748
1749     if (!fixed)
1750     {
1751         cv::subtract(src, cv::Scalar::all(16), dst, mask, dst_depth);
1752     }
1753     else
1754     {
1755         const cv::Mat fixed_dst(size, CV_MAKE_TYPE((dst_depth > 0 ? dst_depth : CV_16S), src.channels()));
1756         cv::subtract(src, cv::Scalar::all(16), fixed_dst, mask, dst_depth);
1757         dst = fixed_dst;
1758         dst_depth = fixed_dst.depth();
1759     }
1760
1761     ASSERT_FALSE(dst.empty());
1762     ASSERT_EQ(src.size(), dst.size());
1763     ASSERT_EQ(dst_depth > 0 ? dst_depth : src.depth(), dst.depth());
1764     ASSERT_EQ(0, cv::countNonZero(dst.reshape(1)));
1765 }
1766
1767 TEST_P(SubtractOutputMatNotEmpty, Scalar_Mat)
1768 {
1769     cv::Mat src(size, src_type, cv::Scalar::all(16));
1770
1771     cv::Mat dst;
1772
1773     if (!fixed)
1774     {
1775         cv::subtract(cv::Scalar::all(16), src, dst, cv::noArray(), dst_depth);
1776     }
1777     else
1778     {
1779         const cv::Mat fixed_dst(size, CV_MAKE_TYPE((dst_depth > 0 ? dst_depth : CV_16S), src.channels()));
1780         cv::subtract(cv::Scalar::all(16), src, fixed_dst, cv::noArray(), dst_depth);
1781         dst = fixed_dst;
1782         dst_depth = fixed_dst.depth();
1783     }
1784
1785     ASSERT_FALSE(dst.empty());
1786     ASSERT_EQ(src.size(), dst.size());
1787     ASSERT_EQ(dst_depth > 0 ? dst_depth : src.depth(), dst.depth());
1788     ASSERT_EQ(0, cv::countNonZero(dst.reshape(1)));
1789 }
1790
1791 TEST_P(SubtractOutputMatNotEmpty, Scalar_Mat_WithMask)
1792 {
1793     cv::Mat src(size, src_type, cv::Scalar::all(16));
1794     cv::Mat mask(size, CV_8UC1, cv::Scalar::all(255));
1795
1796     cv::Mat dst;
1797
1798     if (!fixed)
1799     {
1800         cv::subtract(cv::Scalar::all(16), src, dst, mask, dst_depth);
1801     }
1802     else
1803     {
1804         const cv::Mat fixed_dst(size, CV_MAKE_TYPE((dst_depth > 0 ? dst_depth : CV_16S), src.channels()));
1805         cv::subtract(cv::Scalar::all(16), src, fixed_dst, mask, dst_depth);
1806         dst = fixed_dst;
1807         dst_depth = fixed_dst.depth();
1808     }
1809
1810     ASSERT_FALSE(dst.empty());
1811     ASSERT_EQ(src.size(), dst.size());
1812     ASSERT_EQ(dst_depth > 0 ? dst_depth : src.depth(), dst.depth());
1813     ASSERT_EQ(0, cv::countNonZero(dst.reshape(1)));
1814 }
1815
1816 TEST_P(SubtractOutputMatNotEmpty, Mat_Mat_3d)
1817 {
1818     int dims[] = {5, size.height, size.width};
1819
1820     cv::Mat src1(3, dims, src_type, cv::Scalar::all(16));
1821     cv::Mat src2(3, dims, src_type, cv::Scalar::all(16));
1822
1823     cv::Mat dst;
1824
1825     if (!fixed)
1826     {
1827         cv::subtract(src1, src2, dst, cv::noArray(), dst_depth);
1828     }
1829     else
1830     {
1831         const cv::Mat fixed_dst(3, dims, CV_MAKE_TYPE((dst_depth > 0 ? dst_depth : CV_16S), src1.channels()));
1832         cv::subtract(src1, src2, fixed_dst, cv::noArray(), dst_depth);
1833         dst = fixed_dst;
1834         dst_depth = fixed_dst.depth();
1835     }
1836
1837     ASSERT_FALSE(dst.empty());
1838     ASSERT_EQ(src1.dims, dst.dims);
1839     ASSERT_EQ(src1.size, dst.size);
1840     ASSERT_EQ(dst_depth > 0 ? dst_depth : src1.depth(), dst.depth());
1841     ASSERT_EQ(0, cv::countNonZero(dst.reshape(1)));
1842 }
1843
1844 INSTANTIATE_TEST_CASE_P(Arithm, SubtractOutputMatNotEmpty, testing::Combine(
1845     testing::Values(cv::Size(16, 16), cv::Size(13, 13), cv::Size(16, 13), cv::Size(13, 16)),
1846     testing::Values(perf::MatType(CV_8UC1), CV_8UC3, CV_8UC4, CV_16SC1, CV_16SC3),
1847     testing::Values(-1, CV_16S, CV_32S, CV_32F),
1848     testing::Bool()));
1849
1850 TEST(Core_FindNonZero, singular)
1851 {
1852     Mat img(10, 10, CV_8U, Scalar::all(0));
1853     vector<Point> pts, pts2(10);
1854     findNonZero(img, pts);
1855     findNonZero(img, pts2);
1856     ASSERT_TRUE(pts.empty() && pts2.empty());
1857 }
1858
1859 TEST(Core_BoolVector, support)
1860 {
1861     std::vector<bool> test;
1862     int i, n = 205;
1863     int nz = 0;
1864     test.resize(n);
1865     for( i = 0; i < n; i++ )
1866     {
1867         test[i] = theRNG().uniform(0, 2) != 0;
1868         nz += (int)test[i];
1869     }
1870     ASSERT_EQ( nz, countNonZero(test) );
1871     ASSERT_FLOAT_EQ((float)nz/n, (float)(cv::mean(test)[0]));
1872 }
1873
1874 TEST(MinMaxLoc, Mat_UcharMax_Without_Loc)
1875 {
1876     Mat_<uchar> mat(50, 50);
1877     uchar iMaxVal = std::numeric_limits<uchar>::max();
1878     mat.setTo(iMaxVal);
1879
1880     double min, max;
1881     Point minLoc, maxLoc;
1882
1883     minMaxLoc(mat, &min, &max, &minLoc, &maxLoc, Mat());
1884
1885     ASSERT_EQ(iMaxVal, min);
1886     ASSERT_EQ(iMaxVal, max);
1887
1888     ASSERT_EQ(Point(0, 0), minLoc);
1889     ASSERT_EQ(Point(0, 0), maxLoc);
1890 }
1891
1892 TEST(MinMaxLoc, Mat_IntMax_Without_Mask)
1893 {
1894     Mat_<int> mat(50, 50);
1895     int iMaxVal = std::numeric_limits<int>::max();
1896     mat.setTo(iMaxVal);
1897
1898     double min, max;
1899     Point minLoc, maxLoc;
1900
1901     minMaxLoc(mat, &min, &max, &minLoc, &maxLoc, Mat());
1902
1903     ASSERT_EQ(iMaxVal, min);
1904     ASSERT_EQ(iMaxVal, max);
1905
1906     ASSERT_EQ(Point(0, 0), minLoc);
1907     ASSERT_EQ(Point(0, 0), maxLoc);
1908 }
1909
1910 TEST(Normalize, regression_5876_inplace_change_type)
1911 {
1912     double initial_values[] = {1, 2, 5, 4, 3};
1913     float result_values[] = {0, 0.25, 1, 0.75, 0.5};
1914     Mat m(Size(5, 1), CV_64FC1, initial_values);
1915     Mat result(Size(5, 1), CV_32FC1, result_values);
1916
1917     normalize(m, m, 1, 0, NORM_MINMAX, CV_32F);
1918     EXPECT_EQ(0, cvtest::norm(m, result, NORM_INF));
1919 }
1920
1921 TEST(Normalize, regression_6125)
1922 {
1923     float initial_values[] = {
1924         1888, 1692, 369, 263, 199,
1925         280, 326, 129, 143, 126,
1926         233, 221, 130, 126, 150,
1927         249, 575, 574, 63, 12
1928     };
1929
1930     Mat src(Size(20, 1), CV_32F, initial_values);
1931     float min = 0., max = 400.;
1932     normalize(src, src, 0, 400, NORM_MINMAX, CV_32F);
1933     for(int i = 0; i < 20; i++)
1934     {
1935         EXPECT_GE(src.at<float>(i), min) << "Value should be >= 0";
1936         EXPECT_LE(src.at<float>(i), max) << "Value should be <= 400";
1937     }
1938 }
1939
1940 TEST(MinMaxLoc, regression_4955_nans)
1941 {
1942     cv::Mat one_mat(2, 2, CV_32F, cv::Scalar(1));
1943     cv::minMaxLoc(one_mat, NULL, NULL, NULL, NULL);
1944
1945     cv::Mat nan_mat(2, 2, CV_32F, cv::Scalar(std::numeric_limits<float>::quiet_NaN()));
1946     cv::minMaxLoc(nan_mat, NULL, NULL, NULL, NULL);
1947 }
1948
1949 TEST(Subtract, scalarc1_matc3)
1950 {
1951     int scalar = 255;
1952     cv::Mat srcImage(5, 5, CV_8UC3, cv::Scalar::all(5)), destImage;
1953     cv::subtract(scalar, srcImage, destImage);
1954
1955     ASSERT_EQ(0, cv::norm(cv::Mat(5, 5, CV_8UC3, cv::Scalar::all(250)), destImage, cv::NORM_INF));
1956 }
1957
1958 TEST(Subtract, scalarc4_matc4)
1959 {
1960     cv::Scalar sc(255, 255, 255, 255);
1961     cv::Mat srcImage(5, 5, CV_8UC4, cv::Scalar::all(5)), destImage;
1962     cv::subtract(sc, srcImage, destImage);
1963
1964     ASSERT_EQ(0, cv::norm(cv::Mat(5, 5, CV_8UC4, cv::Scalar::all(250)), destImage, cv::NORM_INF));
1965 }
1966
1967 TEST(Compare, empty)
1968 {
1969     cv::Mat temp, dst1, dst2;
1970     cv::compare(temp, temp, dst1, cv::CMP_EQ);
1971     dst2 = temp > 5;
1972
1973     EXPECT_TRUE(dst1.empty());
1974     EXPECT_TRUE(dst2.empty());
1975 }
1976
1977 TEST(Compare, regression_8999)
1978 {
1979     Mat_<double> A(4,1); A << 1, 3, 2, 4;
1980     Mat_<double> B(1,1); B << 2;
1981     Mat C;
1982     ASSERT_ANY_THROW({
1983         cv::compare(A, B, C, CMP_LT);
1984     });
1985 }
1986
1987
1988 TEST(Core_minMaxIdx, regression_9207_1)
1989 {
1990     const int rows = 4;
1991     const int cols = 3;
1992     uchar mask_[rows*cols] = {
1993  255, 255, 255,
1994  255,   0, 255,
1995    0, 255, 255,
1996    0,   0, 255
1997 };
1998     uchar src_[rows*cols] = {
1999    1,   1,   1,
2000    1,   1,   1,
2001    2,   1,   1,
2002    2,   2,   1
2003 };
2004     Mat mask(Size(cols, rows), CV_8UC1, mask_);
2005     Mat src(Size(cols, rows), CV_8UC1, src_);
2006     double minVal = -0.0, maxVal = -0.0;
2007     int minIdx[2] = { -2, -2 }, maxIdx[2] = { -2, -2 };
2008     cv::minMaxIdx(src, &minVal, &maxVal, minIdx, maxIdx, mask);
2009     EXPECT_EQ(0, minIdx[0]);
2010     EXPECT_EQ(0, minIdx[1]);
2011     EXPECT_EQ(0, maxIdx[0]);
2012     EXPECT_EQ(0, maxIdx[1]);
2013 }
2014
2015
2016 TEST(Core_minMaxIdx, regression_9207_2)
2017 {
2018     const int rows = 13;
2019     const int cols = 15;
2020     uchar mask_[rows*cols] = {
2021    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 255,
2022    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 255,
2023    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 255,
2024    0, 255, 255, 255, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0, 255,
2025  255,   0,   0,   0,   0, 255,   0,   0,   0,   0,   0,   0,   0,   0, 255,
2026  255,   0,   0,   0,   0,   0, 255,   0,   0,   0,   0,   0,   0, 255, 255,
2027  255,   0,   0,   0,   0,   0,   0, 255, 255,   0,   0, 255, 255, 255,   0,
2028  255,   0,   0,   0,   0,   0,   0,   0,   0, 255, 255, 255,   0, 255,   0,
2029  255,   0,   0,   0,   0,   0,   0, 255, 255,   0,   0,   0, 255, 255,   0,
2030  255,   0,   0,   0,   0,   0, 255,   0,   0,   0,   0,   0,   0, 255,   0,
2031  255,   0,   0,   0,   0, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0,
2032    0, 255,   0,   0,   0, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0,
2033    0, 255, 255, 255, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
2034 };
2035     uchar src_[15*13] = {
2036    5,   5,   5,   5,   5,   6,   5,   2,   0,   4,   6,   6,   4,   1,   0,
2037    6,   5,   4,   4,   5,   6,   6,   5,   2,   0,   4,   6,   5,   2,   0,
2038    3,   2,   1,   1,   2,   4,   6,   6,   4,   2,   3,   4,   4,   2,   0,
2039    1,   0,   0,   0,   0,   1,   4,   5,   4,   4,   4,   4,   3,   2,   0,
2040    0,   0,   0,   0,   0,   0,   2,   3,   4,   4,   4,   3,   2,   1,   0,
2041    0,   0,   0,   0,   0,   0,   0,   2,   3,   4,   3,   2,   1,   0,   0,
2042    0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   0,   0,   0,   1,
2043    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,
2044    0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   0,   0,   1,
2045    0,   0,   0,   0,   0,   0,   0,   1,   2,   4,   3,   3,   1,   0,   1,
2046    0,   0,   0,   0,   0,   0,   1,   4,   5,   6,   5,   4,   3,   2,   0,
2047    1,   0,   0,   0,   0,   0,   3,   5,   5,   4,   3,   4,   4,   3,   0,
2048    2,   0,   0,   0,   0,   2,   5,   6,   5,   2,   2,   5,   4,   3,   0
2049 };
2050     Mat mask(Size(cols, rows), CV_8UC1, mask_);
2051     Mat src(Size(cols, rows), CV_8UC1, src_);
2052     double minVal = -0.0, maxVal = -0.0;
2053     int minIdx[2] = { -2, -2 }, maxIdx[2] = { -2, -2 };
2054     cv::minMaxIdx(src, &minVal, &maxVal, minIdx, maxIdx, mask);
2055     EXPECT_EQ(0, minIdx[0]);
2056     EXPECT_EQ(14, minIdx[1]);
2057     EXPECT_EQ(0, maxIdx[0]);
2058     EXPECT_EQ(14, maxIdx[1]);
2059 }
2060
2061 TEST(Core_Set, regression_11044)
2062 {
2063     Mat testFloat(Size(3, 3), CV_32FC1);
2064     Mat testDouble(Size(3, 3), CV_64FC1);
2065
2066     testFloat.setTo(1);
2067     EXPECT_EQ(1, testFloat.at<float>(0,0));
2068     testFloat.setTo(std::numeric_limits<float>::infinity());
2069     EXPECT_EQ(std::numeric_limits<float>::infinity(), testFloat.at<float>(0, 0));
2070     testFloat.setTo(1);
2071     EXPECT_EQ(1, testFloat.at<float>(0, 0));
2072     testFloat.setTo(std::numeric_limits<double>::infinity());
2073     EXPECT_EQ(std::numeric_limits<float>::infinity(), testFloat.at<float>(0, 0));
2074
2075     testDouble.setTo(1);
2076     EXPECT_EQ(1, testDouble.at<double>(0, 0));
2077     testDouble.setTo(std::numeric_limits<float>::infinity());
2078     EXPECT_EQ(std::numeric_limits<double>::infinity(), testDouble.at<double>(0, 0));
2079     testDouble.setTo(1);
2080     EXPECT_EQ(1, testDouble.at<double>(0, 0));
2081     testDouble.setTo(std::numeric_limits<double>::infinity());
2082     EXPECT_EQ(std::numeric_limits<double>::infinity(), testDouble.at<double>(0, 0));
2083
2084     Mat testMask(Size(3, 3), CV_8UC1, Scalar(1));
2085
2086     testFloat.setTo(1);
2087     EXPECT_EQ(1, testFloat.at<float>(0, 0));
2088     testFloat.setTo(std::numeric_limits<float>::infinity(), testMask);
2089     EXPECT_EQ(std::numeric_limits<float>::infinity(), testFloat.at<float>(0, 0));
2090     testFloat.setTo(1);
2091     EXPECT_EQ(1, testFloat.at<float>(0, 0));
2092     testFloat.setTo(std::numeric_limits<double>::infinity(), testMask);
2093     EXPECT_EQ(std::numeric_limits<float>::infinity(), testFloat.at<float>(0, 0));
2094
2095
2096     testDouble.setTo(1);
2097     EXPECT_EQ(1, testDouble.at<double>(0, 0));
2098     testDouble.setTo(std::numeric_limits<float>::infinity(), testMask);
2099     EXPECT_EQ(std::numeric_limits<double>::infinity(), testDouble.at<double>(0, 0));
2100     testDouble.setTo(1);
2101     EXPECT_EQ(1, testDouble.at<double>(0, 0));
2102     testDouble.setTo(std::numeric_limits<double>::infinity(), testMask);
2103     EXPECT_EQ(std::numeric_limits<double>::infinity(), testDouble.at<double>(0, 0));
2104 }
2105
2106 TEST(Core_Norm, IPP_regression_NORM_L1_16UC3_small)
2107 {
2108     int cn = 3;
2109     Size sz(9, 4);  // width < 16
2110     Mat a(sz, CV_MAKE_TYPE(CV_16U, cn), Scalar::all(1));
2111     Mat b(sz, CV_MAKE_TYPE(CV_16U, cn), Scalar::all(2));
2112     uchar mask_[9*4] = {
2113  255, 255, 255,   0, 255, 255,   0, 255,   0,
2114    0, 255,   0,   0, 255, 255, 255, 255,   0,
2115    0,   0,   0, 255,   0, 255,   0, 255, 255,
2116    0,   0, 255,   0, 255, 255, 255,   0, 255
2117 };
2118     Mat mask(sz, CV_8UC1, mask_);
2119
2120     EXPECT_EQ((double)9*4*cn, cv::norm(a, b, NORM_L1)); // without mask, IPP works well
2121     EXPECT_EQ((double)20*cn, cv::norm(a, b, NORM_L1, mask));
2122 }
2123
2124 }} // namespace