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 
5 
6 /* ////////////////////////////////////////////////////////////////////
7 //
8 //  Mat basic operations: Copy, Set
9 //
10 // */
11 
12 #include "precomp.hpp"
13 #include <opencv2/core/utils/logger.hpp>
14 
15 namespace cv
16 {
17 
18 //This and its overload below are used in various MatExpr operator overloads
19 //implemented to check that Matrix operands exist.
checkOperandsExist(const Mat & a)20 static void checkOperandsExist(const Mat& a)
21 {
22     if (a.empty())
23     {
24         CV_Error(CV_StsBadArg, "Matrix operand is an empty matrix.");
25     }
26 }
27 
checkOperandsExist(const Mat & a,const Mat & b)28 static void checkOperandsExist(const Mat& a, const Mat& b)
29 {
30     if (a.empty() || b.empty())
31     {
32         CV_Error(CV_StsBadArg, "One or more matrix operands are empty.");
33     }
34 }
35 
36 
37 class MatOp_Identity CV_FINAL : public MatOp
38 {
39 public:
MatOp_Identity()40     MatOp_Identity() {}
~MatOp_Identity()41     virtual ~MatOp_Identity() {}
42 
elementWise(const MatExpr &) const43     bool elementWise(const MatExpr& /*expr*/) const CV_OVERRIDE { return true; }
44     void assign(const MatExpr& expr, Mat& m, int type=-1) const CV_OVERRIDE;
45 
46     static void makeExpr(MatExpr& res, const Mat& m);
47 };
48 
49 static MatOp_Identity g_MatOp_Identity;
50 
51 class MatOp_AddEx CV_FINAL : public MatOp
52 {
53 public:
MatOp_AddEx()54     MatOp_AddEx() {}
~MatOp_AddEx()55     virtual ~MatOp_AddEx() {}
56 
elementWise(const MatExpr &) const57     bool elementWise(const MatExpr& /*expr*/) const CV_OVERRIDE { return true; }
58     void assign(const MatExpr& expr, Mat& m, int type=-1) const CV_OVERRIDE;
59 
60     void add(const MatExpr& e1, const Scalar& s, MatExpr& res) const CV_OVERRIDE;
61     void subtract(const Scalar& s, const MatExpr& expr, MatExpr& res) const CV_OVERRIDE;
62     void multiply(const MatExpr& e1, double s, MatExpr& res) const CV_OVERRIDE;
63     void divide(double s, const MatExpr& e, MatExpr& res) const CV_OVERRIDE;
64 
65     void transpose(const MatExpr& e1, MatExpr& res) const CV_OVERRIDE;
66     void abs(const MatExpr& expr, MatExpr& res) const CV_OVERRIDE;
67 
68     static void makeExpr(MatExpr& res, const Mat& a, const Mat& b, double alpha, double beta, const Scalar& s=Scalar());
69 };
70 
71 static MatOp_AddEx g_MatOp_AddEx;
72 
73 class MatOp_Bin CV_FINAL : public MatOp
74 {
75 public:
MatOp_Bin()76     MatOp_Bin() {}
~MatOp_Bin()77     virtual ~MatOp_Bin() {}
78 
elementWise(const MatExpr &) const79     bool elementWise(const MatExpr& /*expr*/) const CV_OVERRIDE { return true; }
80     void assign(const MatExpr& expr, Mat& m, int type=-1) const CV_OVERRIDE;
81 
82     void multiply(const MatExpr& e1, double s, MatExpr& res) const CV_OVERRIDE;
83     void divide(double s, const MatExpr& e, MatExpr& res) const CV_OVERRIDE;
84 
85     static void makeExpr(MatExpr& res, char op, const Mat& a, const Mat& b, double scale=1);
86     static void makeExpr(MatExpr& res, char op, const Mat& a, const Scalar& s);
87 };
88 
89 static MatOp_Bin g_MatOp_Bin;
90 
91 class MatOp_Cmp CV_FINAL : public MatOp
92 {
93 public:
MatOp_Cmp()94     MatOp_Cmp() {}
~MatOp_Cmp()95     virtual ~MatOp_Cmp() {}
96 
elementWise(const MatExpr &) const97     bool elementWise(const MatExpr& /*expr*/) const CV_OVERRIDE { return true; }
98     void assign(const MatExpr& expr, Mat& m, int type=-1) const CV_OVERRIDE;
99 
100     static void makeExpr(MatExpr& res, int cmpop, const Mat& a, const Mat& b);
101     static void makeExpr(MatExpr& res, int cmpop, const Mat& a, double alpha);
102 };
103 
104 static MatOp_Cmp g_MatOp_Cmp;
105 
106 class MatOp_GEMM CV_FINAL : public MatOp
107 {
108 public:
MatOp_GEMM()109     MatOp_GEMM() {}
~MatOp_GEMM()110     virtual ~MatOp_GEMM() {}
111 
elementWise(const MatExpr &) const112     bool elementWise(const MatExpr& /*expr*/) const CV_OVERRIDE { return false; }
113     void assign(const MatExpr& expr, Mat& m, int type=-1) const CV_OVERRIDE;
114 
115     void add(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const CV_OVERRIDE;
116     void subtract(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const CV_OVERRIDE;
117     void multiply(const MatExpr& e, double s, MatExpr& res) const CV_OVERRIDE;
118 
119     void transpose(const MatExpr& expr, MatExpr& res) const CV_OVERRIDE;
120 
size(const MatExpr & expr) const121     Size size(const MatExpr& expr) const CV_OVERRIDE
122     {
123         return Size(
124             (expr.flags & GEMM_2_T) ? expr.b.rows : expr.b.cols,
125             (expr.flags & GEMM_1_T) ? expr.a.cols : expr.a.rows
126         );
127     }
128 
129     static void makeExpr(MatExpr& res, int flags, const Mat& a, const Mat& b,
130                          double alpha=1, const Mat& c=Mat(), double beta=1);
131 
132 };
133 
134 static MatOp_GEMM g_MatOp_GEMM;
135 
136 class MatOp_Invert CV_FINAL : public MatOp
137 {
138 public:
MatOp_Invert()139     MatOp_Invert() {}
~MatOp_Invert()140     virtual ~MatOp_Invert() {}
141 
elementWise(const MatExpr &) const142     bool elementWise(const MatExpr& /*expr*/) const CV_OVERRIDE { return false; }
143     void assign(const MatExpr& expr, Mat& m, int type=-1) const CV_OVERRIDE;
144 
145     void matmul(const MatExpr& expr1, const MatExpr& expr2, MatExpr& res) const CV_OVERRIDE;
146 
147     static void makeExpr(MatExpr& res, int method, const Mat& m);
148 };
149 
150 static MatOp_Invert g_MatOp_Invert;
151 
152 class MatOp_T CV_FINAL : public MatOp
153 {
154 public:
MatOp_T()155     MatOp_T() {}
~MatOp_T()156     virtual ~MatOp_T() {}
157 
elementWise(const MatExpr &) const158     bool elementWise(const MatExpr& /*expr*/) const CV_OVERRIDE { return false; }
159     void assign(const MatExpr& expr, Mat& m, int type=-1) const CV_OVERRIDE;
160 
161     void multiply(const MatExpr& e1, double s, MatExpr& res) const CV_OVERRIDE;
162     void transpose(const MatExpr& expr, MatExpr& res) const CV_OVERRIDE;
163 
164     static void makeExpr(MatExpr& res, const Mat& a, double alpha=1);
165 };
166 
167 static MatOp_T g_MatOp_T;
168 
169 class MatOp_Solve CV_FINAL : public MatOp
170 {
171 public:
MatOp_Solve()172     MatOp_Solve() {}
~MatOp_Solve()173     virtual ~MatOp_Solve() {}
174 
elementWise(const MatExpr &) const175     bool elementWise(const MatExpr& /*expr*/) const CV_OVERRIDE { return false; }
176     void assign(const MatExpr& expr, Mat& m, int type=-1) const CV_OVERRIDE;
177 
178     static void makeExpr(MatExpr& res, int method, const Mat& a, const Mat& b);
179 };
180 
181 static MatOp_Solve g_MatOp_Solve;
182 
183 class MatOp_Initializer CV_FINAL : public MatOp
184 {
185 public:
MatOp_Initializer()186     MatOp_Initializer() {}
~MatOp_Initializer()187     virtual ~MatOp_Initializer() {}
188 
elementWise(const MatExpr &) const189     bool elementWise(const MatExpr& /*expr*/) const CV_OVERRIDE { return false; }
190     void assign(const MatExpr& expr, Mat& m, int type=-1) const CV_OVERRIDE;
191 
192     void multiply(const MatExpr& e, double s, MatExpr& res) const CV_OVERRIDE;
193 
194     static void makeExpr(MatExpr& res, int method, Size sz, int type, double alpha=1);
195     static void makeExpr(MatExpr& res, int method, int ndims, const int* sizes, int type, double alpha=1);
196 };
197 
getGlobalMatOpInitializer()198 static MatOp_Initializer* getGlobalMatOpInitializer()
199 {
200     CV_SINGLETON_LAZY_INIT(MatOp_Initializer, new MatOp_Initializer())
201 }
202 
isIdentity(const MatExpr & e)203 static inline bool isIdentity(const MatExpr& e) { return e.op == &g_MatOp_Identity; }
isAddEx(const MatExpr & e)204 static inline bool isAddEx(const MatExpr& e) { return e.op == &g_MatOp_AddEx; }
isScaled(const MatExpr & e)205 static inline bool isScaled(const MatExpr& e) { return isAddEx(e) && (!e.b.data || e.beta == 0) && e.s == Scalar(); }
isBin(const MatExpr & e,char c)206 static inline bool isBin(const MatExpr& e, char c) { return e.op == &g_MatOp_Bin && e.flags == c; }
isCmp(const MatExpr & e)207 static inline bool isCmp(const MatExpr& e) { return e.op == &g_MatOp_Cmp; }
isReciprocal(const MatExpr & e)208 static inline bool isReciprocal(const MatExpr& e) { return isBin(e,'/') && (!e.b.data || e.beta == 0); }
isT(const MatExpr & e)209 static inline bool isT(const MatExpr& e) { return e.op == &g_MatOp_T; }
isInv(const MatExpr & e)210 static inline bool isInv(const MatExpr& e) { return e.op == &g_MatOp_Invert; }
isSolve(const MatExpr & e)211 static inline bool isSolve(const MatExpr& e) { return e.op == &g_MatOp_Solve; }
212 //static inline bool isGEMM(const MatExpr& e) { return e.op == &g_MatOp_GEMM; }
isMatProd(const MatExpr & e)213 static inline bool isMatProd(const MatExpr& e) { return e.op == &g_MatOp_GEMM && (!e.c.data || e.beta == 0); }
isInitializer(const MatExpr & e)214 static inline bool isInitializer(const MatExpr& e) { return e.op == getGlobalMatOpInitializer(); }
215 
216 /////////////////////////////////////////////////////////////////////////////////////////////////////
217 
MatOp()218 MatOp::MatOp() {}
~MatOp()219 MatOp::~MatOp() {}
220 
221 
elementWise(const MatExpr &) const222 bool MatOp::elementWise(const MatExpr& /*expr*/) const
223 {
224     return false;
225 }
226 
roi(const MatExpr & expr,const Range & rowRange,const Range & colRange,MatExpr & e) const227 void MatOp::roi(const MatExpr& expr, const Range& rowRange, const Range& colRange, MatExpr& e) const
228 {
229     if( elementWise(expr) )
230     {
231         e = MatExpr(expr.op, expr.flags, Mat(), Mat(), Mat(),
232                     expr.alpha, expr.beta, expr.s);
233         if(expr.a.data)
234             e.a = expr.a(rowRange, colRange);
235         if(expr.b.data)
236             e.b = expr.b(rowRange, colRange);
237         if(expr.c.data)
238             e.c = expr.c(rowRange, colRange);
239     }
240     else
241     {
242         Mat m;
243         expr.op->assign(expr, m);
244         e = MatExpr(&g_MatOp_Identity, 0, m(rowRange, colRange), Mat(), Mat());
245     }
246 }
247 
diag(const MatExpr & expr,int d,MatExpr & e) const248 void MatOp::diag(const MatExpr& expr, int d, MatExpr& e) const
249 {
250     if( elementWise(expr) )
251     {
252         e = MatExpr(expr.op, expr.flags, Mat(), Mat(), Mat(),
253                     expr.alpha, expr.beta, expr.s);
254         if(expr.a.data)
255             e.a = expr.a.diag(d);
256         if(expr.b.data)
257             e.b = expr.b.diag(d);
258         if(expr.c.data)
259             e.c = expr.c.diag(d);
260     }
261     else
262     {
263         Mat m;
264         expr.op->assign(expr, m);
265         e = MatExpr(&g_MatOp_Identity, 0, m.diag(d), Mat(), Mat());
266     }
267 }
268 
269 
augAssignAdd(const MatExpr & expr,Mat & m) const270 void MatOp::augAssignAdd(const MatExpr& expr, Mat& m) const
271 {
272     Mat temp;
273     expr.op->assign(expr, temp);
274     m += temp;
275 }
276 
277 
augAssignSubtract(const MatExpr & expr,Mat & m) const278 void MatOp::augAssignSubtract(const MatExpr& expr, Mat& m) const
279 {
280     Mat temp;
281     expr.op->assign(expr, temp);
282     m -= temp;
283 }
284 
285 
augAssignMultiply(const MatExpr & expr,Mat & m) const286 void MatOp::augAssignMultiply(const MatExpr& expr, Mat& m) const
287 {
288     Mat temp;
289     expr.op->assign(expr, temp);
290     m *= temp;
291 }
292 
293 
augAssignDivide(const MatExpr & expr,Mat & m) const294 void MatOp::augAssignDivide(const MatExpr& expr, Mat& m) const
295 {
296     Mat temp;
297     expr.op->assign(expr, temp);
298     m /= temp;
299 }
300 
301 
augAssignAnd(const MatExpr & expr,Mat & m) const302 void MatOp::augAssignAnd(const MatExpr& expr, Mat& m) const
303 {
304     Mat temp;
305     expr.op->assign(expr, temp);
306     m &= temp;
307 }
308 
309 
augAssignOr(const MatExpr & expr,Mat & m) const310 void MatOp::augAssignOr(const MatExpr& expr, Mat& m) const
311 {
312     Mat temp;
313     expr.op->assign(expr, temp);
314     m |= temp;
315 }
316 
317 
augAssignXor(const MatExpr & expr,Mat & m) const318 void MatOp::augAssignXor(const MatExpr& expr, Mat& m) const
319 {
320     Mat temp;
321     expr.op->assign(expr, temp);
322     m ^= temp;
323 }
324 
325 
add(const MatExpr & e1,const MatExpr & e2,MatExpr & res) const326 void MatOp::add(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const
327 {
328     CV_INSTRUMENT_REGION();
329 
330     if( this == e2.op )
331     {
332         double alpha = 1, beta = 1;
333         Scalar s;
334         Mat m1, m2;
335         if( isAddEx(e1) && (!e1.b.data || e1.beta == 0) )
336         {
337             m1 = e1.a;
338             alpha = e1.alpha;
339             s = e1.s;
340         }
341         else
342             e1.op->assign(e1, m1);
343 
344         if( isAddEx(e2) && (!e2.b.data || e2.beta == 0) )
345         {
346             m2 = e2.a;
347             beta = e2.alpha;
348             s += e2.s;
349         }
350         else
351             e2.op->assign(e2, m2);
352         MatOp_AddEx::makeExpr(res, m1, m2, alpha, beta, s);
353     }
354     else
355         e2.op->add(e1, e2, res);
356 }
357 
358 
add(const MatExpr & expr1,const Scalar & s,MatExpr & res) const359 void MatOp::add(const MatExpr& expr1, const Scalar& s, MatExpr& res) const
360 {
361     CV_INSTRUMENT_REGION();
362 
363     Mat m1;
364     expr1.op->assign(expr1, m1);
365     MatOp_AddEx::makeExpr(res, m1, Mat(), 1, 0, s);
366 }
367 
368 
subtract(const MatExpr & e1,const MatExpr & e2,MatExpr & res) const369 void MatOp::subtract(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const
370 {
371     CV_INSTRUMENT_REGION();
372 
373     if( this == e2.op )
374     {
375         double alpha = 1, beta = -1;
376         Scalar s;
377         Mat m1, m2;
378         if( isAddEx(e1) && (!e1.b.data || e1.beta == 0) )
379         {
380             m1 = e1.a;
381             alpha = e1.alpha;
382             s = e1.s;
383         }
384         else
385             e1.op->assign(e1, m1);
386 
387         if( isAddEx(e2) && (!e2.b.data || e2.beta == 0) )
388         {
389             m2 = e2.a;
390             beta = -e2.alpha;
391             s -= e2.s;
392         }
393         else
394             e2.op->assign(e2, m2);
395         MatOp_AddEx::makeExpr(res, m1, m2, alpha, beta, s);
396     }
397     else
398         e2.op->subtract(e1, e2, res);
399 }
400 
401 
subtract(const Scalar & s,const MatExpr & expr,MatExpr & res) const402 void MatOp::subtract(const Scalar& s, const MatExpr& expr, MatExpr& res) const
403 {
404     CV_INSTRUMENT_REGION();
405 
406     Mat m;
407     expr.op->assign(expr, m);
408     MatOp_AddEx::makeExpr(res, m, Mat(), -1, 0, s);
409 }
410 
411 
multiply(const MatExpr & e1,const MatExpr & e2,MatExpr & res,double scale) const412 void MatOp::multiply(const MatExpr& e1, const MatExpr& e2, MatExpr& res, double scale) const
413 {
414     CV_INSTRUMENT_REGION();
415 
416     if( this == e2.op )
417     {
418         Mat m1, m2;
419 
420         if( isReciprocal(e1) )
421         {
422             if( isScaled(e2) )
423             {
424                 scale *= e2.alpha;
425                 m2 = e2.a;
426             }
427             else
428                 e2.op->assign(e2, m2);
429 
430             MatOp_Bin::makeExpr(res, '/', m2, e1.a, scale/e1.alpha);
431         }
432         else
433         {
434             char op = '*';
435             if( isScaled(e1) )
436             {
437                 m1 = e1.a;
438                 scale *= e1.alpha;
439             }
440             else
441                 e1.op->assign(e1, m1);
442 
443             if( isScaled(e2) )
444             {
445                 m2 = e2.a;
446                 scale *= e2.alpha;
447             }
448             else if( isReciprocal(e2) )
449             {
450                 op = '/';
451                 m2 = e2.a;
452                 scale *= e2.alpha;
453             }
454             else
455                 e2.op->assign(e2, m2);
456 
457             MatOp_Bin::makeExpr(res, op, m1, m2, scale);
458         }
459     }
460     else
461         e2.op->multiply(e1, e2, res, scale);
462 }
463 
464 
multiply(const MatExpr & expr,double s,MatExpr & res) const465 void MatOp::multiply(const MatExpr& expr, double s, MatExpr& res) const
466 {
467     CV_INSTRUMENT_REGION();
468 
469     Mat m;
470     expr.op->assign(expr, m);
471     MatOp_AddEx::makeExpr(res, m, Mat(), s, 0);
472 }
473 
474 
divide(const MatExpr & e1,const MatExpr & e2,MatExpr & res,double scale) const475 void MatOp::divide(const MatExpr& e1, const MatExpr& e2, MatExpr& res, double scale) const
476 {
477     CV_INSTRUMENT_REGION();
478 
479     if( this == e2.op )
480     {
481         if( isReciprocal(e1) && isReciprocal(e2) )
482             MatOp_Bin::makeExpr(res, '/', e2.a, e1.a, e1.alpha/e2.alpha);
483         else
484         {
485             Mat m1, m2;
486             char op = '/';
487 
488             if( isScaled(e1) )
489             {
490                 m1 = e1.a;
491                 scale *= e1.alpha;
492             }
493             else
494                 e1.op->assign(e1, m1);
495 
496             if( isScaled(e2) )
497             {
498                 m2 = e2.a;
499                 scale /= e2.alpha;
500             }
501             else if( isReciprocal(e2) )
502             {
503                 m2 = e2.a;
504                 scale /= e2.alpha;
505                 op = '*';
506             }
507             else
508                 e2.op->assign(e2, m2);
509             MatOp_Bin::makeExpr(res, op, m1, m2, scale);
510         }
511     }
512     else
513         e2.op->divide(e1, e2, res, scale);
514 }
515 
516 
divide(double s,const MatExpr & expr,MatExpr & res) const517 void MatOp::divide(double s, const MatExpr& expr, MatExpr& res) const
518 {
519     CV_INSTRUMENT_REGION();
520 
521     Mat m;
522     expr.op->assign(expr, m);
523     MatOp_Bin::makeExpr(res, '/', m, Mat(), s);
524 }
525 
526 
abs(const MatExpr & expr,MatExpr & res) const527 void MatOp::abs(const MatExpr& expr, MatExpr& res) const
528 {
529     CV_INSTRUMENT_REGION();
530 
531     Mat m;
532     expr.op->assign(expr, m);
533     MatOp_Bin::makeExpr(res, 'a', m, Mat());
534 }
535 
536 
transpose(const MatExpr & expr,MatExpr & res) const537 void MatOp::transpose(const MatExpr& expr, MatExpr& res) const
538 {
539     CV_INSTRUMENT_REGION();
540 
541     Mat m;
542     expr.op->assign(expr, m);
543     MatOp_T::makeExpr(res, m, 1);
544 }
545 
546 
matmul(const MatExpr & e1,const MatExpr & e2,MatExpr & res) const547 void MatOp::matmul(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const
548 {
549     if( this == e2.op )
550     {
551         double scale = 1;
552         int flags = 0;
553         Mat m1, m2;
554 
555         if( isT(e1) )
556         {
557             flags = CV_GEMM_A_T;
558             scale = e1.alpha;
559             m1 = e1.a;
560         }
561         else if( isScaled(e1) )
562         {
563             scale = e1.alpha;
564             m1 = e1.a;
565         }
566         else
567             e1.op->assign(e1, m1);
568 
569         if( isT(e2) )
570         {
571             flags |= CV_GEMM_B_T;
572             scale *= e2.alpha;
573             m2 = e2.a;
574         }
575         else if( isScaled(e2) )
576         {
577             scale *= e2.alpha;
578             m2 = e2.a;
579         }
580         else
581             e2.op->assign(e2, m2);
582 
583         MatOp_GEMM::makeExpr(res, flags, m1, m2, scale);
584     }
585     else
586         e2.op->matmul(e1, e2, res);
587 }
588 
589 
invert(const MatExpr & expr,int method,MatExpr & res) const590 void MatOp::invert(const MatExpr& expr, int method, MatExpr& res) const
591 {
592     Mat m;
593     expr.op->assign(expr, m);
594     MatOp_Invert::makeExpr(res, method, m);
595 }
596 
597 
size(const MatExpr & expr) const598 Size MatOp::size(const MatExpr& expr) const
599 {
600     return !expr.a.empty() ? expr.a.size() : expr.b.empty() ? expr.b.size() : expr.c.size();
601 }
602 
type(const MatExpr & expr) const603 int MatOp::type(const MatExpr& expr) const
604 {
605     CV_INSTRUMENT_REGION();
606 
607     return !expr.a.empty() ? expr.a.type() : expr.b.empty() ? expr.b.type() : expr.c.type();
608 }
609 
610 //////////////////////////////////////////////////////////////////////////////////////////////////
611 
MatExpr(const Mat & m)612 MatExpr::MatExpr(const Mat& m) : op(&g_MatOp_Identity), flags(0), a(m), b(Mat()), c(Mat()), alpha(1), beta(0), s(Scalar())
613 {
614 }
615 
row(int y) const616 MatExpr MatExpr::row(int y) const
617 {
618     MatExpr e;
619     op->roi(*this, Range(y, y+1), Range::all(), e);
620     return e;
621 }
622 
col(int x) const623 MatExpr MatExpr::col(int x) const
624 {
625     MatExpr e;
626     op->roi(*this, Range::all(), Range(x, x+1), e);
627     return e;
628 }
629 
diag(int d) const630 MatExpr MatExpr::diag(int d) const
631 {
632     MatExpr e;
633     op->diag(*this, d, e);
634     return e;
635 }
636 
operator ()(const Range & rowRange,const Range & colRange) const637 MatExpr MatExpr::operator()( const Range& rowRange, const Range& colRange ) const
638 {
639     MatExpr e;
640     op->roi(*this, rowRange, colRange, e);
641     return e;
642 }
643 
operator ()(const Rect & roi) const644 MatExpr MatExpr::operator()( const Rect& roi ) const
645 {
646     MatExpr e;
647     op->roi(*this, Range(roi.y, roi.y + roi.height), Range(roi.x, roi.x + roi.width), e);
648     return e;
649 }
650 
cross(const Mat & m) const651 Mat MatExpr::cross(const Mat& m) const
652 {
653     return ((Mat)*this).cross(m);
654 }
655 
dot(const Mat & m) const656 double MatExpr::dot(const Mat& m) const
657 {
658     return ((Mat)*this).dot(m);
659 }
660 
t() const661 MatExpr MatExpr::t() const
662 {
663     MatExpr e;
664     op->transpose(*this, e);
665     return e;
666 }
667 
inv(int method) const668 MatExpr MatExpr::inv(int method) const
669 {
670     MatExpr e;
671     op->invert(*this, method, e);
672     return e;
673 }
674 
mul(const MatExpr & e,double scale) const675 MatExpr MatExpr::mul(const MatExpr& e, double scale) const
676 {
677     MatExpr en;
678     op->multiply(*this, e, en, scale);
679     return en;
680 }
681 
mul(const Mat & m,double scale) const682 MatExpr MatExpr::mul(const Mat& m, double scale) const
683 {
684     MatExpr e;
685     op->multiply(*this, MatExpr(m), e, scale);
686     return e;
687 }
688 
operator +(const Mat & a,const Mat & b)689 MatExpr operator + (const Mat& a, const Mat& b)
690 {
691     checkOperandsExist(a, b);
692     MatExpr e;
693     MatOp_AddEx::makeExpr(e, a, b, 1, 1);
694     return e;
695 }
696 
operator +(const Mat & a,const Scalar & s)697 MatExpr operator + (const Mat& a, const Scalar& s)
698 {
699     checkOperandsExist(a);
700     MatExpr e;
701     MatOp_AddEx::makeExpr(e, a, Mat(), 1, 0, s);
702     return e;
703 }
704 
operator +(const Scalar & s,const Mat & a)705 MatExpr operator + (const Scalar& s, const Mat& a)
706 {
707     checkOperandsExist(a);
708     MatExpr e;
709     MatOp_AddEx::makeExpr(e, a, Mat(), 1, 0, s);
710     return e;
711 }
712 
operator +(const MatExpr & e,const Mat & m)713 MatExpr operator + (const MatExpr& e, const Mat& m)
714 {
715     MatExpr en;
716     e.op->add(e, MatExpr(m), en);
717     return en;
718 }
719 
operator +(const Mat & m,const MatExpr & e)720 MatExpr operator + (const Mat& m, const MatExpr& e)
721 {
722     checkOperandsExist(m);
723     MatExpr en;
724     e.op->add(e, MatExpr(m), en);
725     return en;
726 }
727 
operator +(const MatExpr & e,const Scalar & s)728 MatExpr operator + (const MatExpr& e, const Scalar& s)
729 {
730     MatExpr en;
731     e.op->add(e, s, en);
732     return en;
733 }
734 
operator +(const Scalar & s,const MatExpr & e)735 MatExpr operator + (const Scalar& s, const MatExpr& e)
736 {
737     MatExpr en;
738     e.op->add(e, s, en);
739     return en;
740 }
741 
operator +(const MatExpr & e1,const MatExpr & e2)742 MatExpr operator + (const MatExpr& e1, const MatExpr& e2)
743 {
744     MatExpr en;
745     e1.op->add(e1, e2, en);
746     return en;
747 }
748 
operator -(const Mat & a,const Mat & b)749 MatExpr operator - (const Mat& a, const Mat& b)
750 {
751     checkOperandsExist(a, b);
752     MatExpr e;
753     MatOp_AddEx::makeExpr(e, a, b, 1, -1);
754     return e;
755 }
756 
operator -(const Mat & a,const Scalar & s)757 MatExpr operator - (const Mat& a, const Scalar& s)
758 {
759     checkOperandsExist(a);
760     MatExpr e;
761     MatOp_AddEx::makeExpr(e, a, Mat(), 1, 0, -s);
762     return e;
763 }
764 
operator -(const Scalar & s,const Mat & a)765 MatExpr operator - (const Scalar& s, const Mat& a)
766 {
767     checkOperandsExist(a);
768     MatExpr e;
769     MatOp_AddEx::makeExpr(e, a, Mat(), -1, 0, s);
770     return e;
771 }
772 
operator -(const MatExpr & e,const Mat & m)773 MatExpr operator - (const MatExpr& e, const Mat& m)
774 {
775     checkOperandsExist(m);
776     MatExpr en;
777     e.op->subtract(e, MatExpr(m), en);
778     return en;
779 }
780 
operator -(const Mat & m,const MatExpr & e)781 MatExpr operator - (const Mat& m, const MatExpr& e)
782 {
783     checkOperandsExist(m);
784     MatExpr en;
785     e.op->subtract(MatExpr(m), e, en);
786     return en;
787 }
788 
operator -(const MatExpr & e,const Scalar & s)789 MatExpr operator - (const MatExpr& e, const Scalar& s)
790 {
791     MatExpr en;
792     e.op->add(e, -s, en);
793     return en;
794 }
795 
operator -(const Scalar & s,const MatExpr & e)796 MatExpr operator - (const Scalar& s, const MatExpr& e)
797 {
798     MatExpr en;
799     e.op->subtract(s, e, en);
800     return en;
801 }
802 
operator -(const MatExpr & e1,const MatExpr & e2)803 MatExpr operator - (const MatExpr& e1, const MatExpr& e2)
804 {
805     MatExpr en;
806     e1.op->subtract(e1, e2, en);
807     return en;
808 }
809 
operator -(const Mat & m)810 MatExpr operator - (const Mat& m)
811 {
812     checkOperandsExist(m);
813     MatExpr e;
814     MatOp_AddEx::makeExpr(e, m, Mat(), -1, 0);
815     return e;
816 }
817 
operator -(const MatExpr & e)818 MatExpr operator - (const MatExpr& e)
819 {
820     MatExpr en;
821     e.op->subtract(Scalar(0), e, en);
822     return en;
823 }
824 
operator *(const Mat & a,const Mat & b)825 MatExpr operator * (const Mat& a, const Mat& b)
826 {
827     checkOperandsExist(a, b);
828     MatExpr e;
829     MatOp_GEMM::makeExpr(e, 0, a, b);
830     return e;
831 }
832 
operator *(const Mat & a,double s)833 MatExpr operator * (const Mat& a, double s)
834 {
835     checkOperandsExist(a);
836     MatExpr e;
837     MatOp_AddEx::makeExpr(e, a, Mat(), s, 0);
838     return e;
839 }
840 
operator *(double s,const Mat & a)841 MatExpr operator * (double s, const Mat& a)
842 {
843     checkOperandsExist(a);
844     MatExpr e;
845     MatOp_AddEx::makeExpr(e, a, Mat(), s, 0);
846     return e;
847 }
848 
operator *(const MatExpr & e,const Mat & m)849 MatExpr operator * (const MatExpr& e, const Mat& m)
850 {
851     MatExpr en;
852     e.op->matmul(e, MatExpr(m), en);
853     return en;
854 }
855 
operator *(const Mat & m,const MatExpr & e)856 MatExpr operator * (const Mat& m, const MatExpr& e)
857 {
858     checkOperandsExist(m);
859     MatExpr en;
860     e.op->matmul(MatExpr(m), e, en);
861     return en;
862 }
863 
operator *(const MatExpr & e,double s)864 MatExpr operator * (const MatExpr& e, double s)
865 {
866     MatExpr en;
867     e.op->multiply(e, s, en);
868     return en;
869 }
870 
operator *(double s,const MatExpr & e)871 MatExpr operator * (double s, const MatExpr& e)
872 {
873     MatExpr en;
874     e.op->multiply(e, s, en);
875     return en;
876 }
877 
operator *(const MatExpr & e1,const MatExpr & e2)878 MatExpr operator * (const MatExpr& e1, const MatExpr& e2)
879 {
880     MatExpr en;
881     e1.op->matmul(e1, e2, en);
882     return en;
883 }
884 
operator /(const Mat & a,const Mat & b)885 MatExpr operator / (const Mat& a, const Mat& b)
886 {
887     checkOperandsExist(a, b);
888     MatExpr e;
889     MatOp_Bin::makeExpr(e, '/', a, b);
890     return e;
891 }
892 
operator /(const Mat & a,double s)893 MatExpr operator / (const Mat& a, double s)
894 {
895     checkOperandsExist(a);
896     MatExpr e;
897     MatOp_AddEx::makeExpr(e, a, Mat(), 1./s, 0);
898     return e;
899 }
900 
operator /(double s,const Mat & a)901 MatExpr operator / (double s, const Mat& a)
902 {
903     checkOperandsExist(a);
904     MatExpr e;
905     MatOp_Bin::makeExpr(e, '/', a, Mat(), s);
906     return e;
907 }
908 
operator /(const MatExpr & e,const Mat & m)909 MatExpr operator / (const MatExpr& e, const Mat& m)
910 {
911     MatExpr en;
912     e.op->divide(e, MatExpr(m), en);
913     return en;
914 }
915 
operator /(const Mat & m,const MatExpr & e)916 MatExpr operator / (const Mat& m, const MatExpr& e)
917 {
918     checkOperandsExist(m);
919     MatExpr en;
920     e.op->divide(MatExpr(m), e, en);
921     return en;
922 }
923 
operator /(const MatExpr & e,double s)924 MatExpr operator / (const MatExpr& e, double s)
925 {
926     MatExpr en;
927     e.op->multiply(e, 1./s, en);
928     return en;
929 }
930 
operator /(double s,const MatExpr & e)931 MatExpr operator / (double s, const MatExpr& e)
932 {
933     MatExpr en;
934     e.op->divide(s, e, en);
935     return en;
936 }
937 
operator /(const MatExpr & e1,const MatExpr & e2)938 MatExpr operator / (const MatExpr& e1, const MatExpr& e2)
939 {
940     MatExpr en;
941     e1.op->divide(e1, e2, en);
942     return en;
943 }
944 
operator <(const Mat & a,const Mat & b)945 MatExpr operator < (const Mat& a, const Mat& b)
946 {
947     checkOperandsExist(a, b);
948     MatExpr e;
949     MatOp_Cmp::makeExpr(e, CV_CMP_LT, a, b);
950     return e;
951 }
952 
operator <(const Mat & a,double s)953 MatExpr operator < (const Mat& a, double s)
954 {
955     checkOperandsExist(a);
956     MatExpr e;
957     MatOp_Cmp::makeExpr(e, CV_CMP_LT, a, s);
958     return e;
959 }
960 
operator <(double s,const Mat & a)961 MatExpr operator < (double s, const Mat& a)
962 {
963     checkOperandsExist(a);
964     MatExpr e;
965     MatOp_Cmp::makeExpr(e, CV_CMP_GT, a, s);
966     return e;
967 }
968 
operator <=(const Mat & a,const Mat & b)969 MatExpr operator <= (const Mat& a, const Mat& b)
970 {
971     checkOperandsExist(a, b);
972     MatExpr e;
973     MatOp_Cmp::makeExpr(e, CV_CMP_LE, a, b);
974     return e;
975 }
976 
operator <=(const Mat & a,double s)977 MatExpr operator <= (const Mat& a, double s)
978 {
979     checkOperandsExist(a);
980     MatExpr e;
981     MatOp_Cmp::makeExpr(e, CV_CMP_LE, a, s);
982     return e;
983 }
984 
operator <=(double s,const Mat & a)985 MatExpr operator <= (double s, const Mat& a)
986 {
987     checkOperandsExist(a);
988     MatExpr e;
989     MatOp_Cmp::makeExpr(e, CV_CMP_GE, a, s);
990     return e;
991 }
992 
operator ==(const Mat & a,const Mat & b)993 MatExpr operator == (const Mat& a, const Mat& b)
994 {
995     checkOperandsExist(a, b);
996     MatExpr e;
997     MatOp_Cmp::makeExpr(e, CV_CMP_EQ, a, b);
998     return e;
999 }
1000 
operator ==(const Mat & a,double s)1001 MatExpr operator == (const Mat& a, double s)
1002 {
1003     checkOperandsExist(a);
1004     MatExpr e;
1005     MatOp_Cmp::makeExpr(e, CV_CMP_EQ, a, s);
1006     return e;
1007 }
1008 
operator ==(double s,const Mat & a)1009 MatExpr operator == (double s, const Mat& a)
1010 {
1011     checkOperandsExist(a);
1012     MatExpr e;
1013     MatOp_Cmp::makeExpr(e, CV_CMP_EQ, a, s);
1014     return e;
1015 }
1016 
operator !=(const Mat & a,const Mat & b)1017 MatExpr operator != (const Mat& a, const Mat& b)
1018 {
1019     checkOperandsExist(a, b);
1020     MatExpr e;
1021     MatOp_Cmp::makeExpr(e, CV_CMP_NE, a, b);
1022     return e;
1023 }
1024 
operator !=(const Mat & a,double s)1025 MatExpr operator != (const Mat& a, double s)
1026 {
1027     checkOperandsExist(a);
1028     MatExpr e;
1029     MatOp_Cmp::makeExpr(e, CV_CMP_NE, a, s);
1030     return e;
1031 }
1032 
operator !=(double s,const Mat & a)1033 MatExpr operator != (double s, const Mat& a)
1034 {
1035     checkOperandsExist(a);
1036     MatExpr e;
1037     MatOp_Cmp::makeExpr(e, CV_CMP_NE, a, s);
1038     return e;
1039 }
1040 
operator >=(const Mat & a,const Mat & b)1041 MatExpr operator >= (const Mat& a, const Mat& b)
1042 {
1043     checkOperandsExist(a, b);
1044     MatExpr e;
1045     MatOp_Cmp::makeExpr(e, CV_CMP_GE, a, b);
1046     return e;
1047 }
1048 
operator >=(const Mat & a,double s)1049 MatExpr operator >= (const Mat& a, double s)
1050 {
1051     checkOperandsExist(a);
1052     MatExpr e;
1053     MatOp_Cmp::makeExpr(e, CV_CMP_GE, a, s);
1054     return e;
1055 }
1056 
operator >=(double s,const Mat & a)1057 MatExpr operator >= (double s, const Mat& a)
1058 {
1059     checkOperandsExist(a);
1060     MatExpr e;
1061     MatOp_Cmp::makeExpr(e, CV_CMP_LE, a, s);
1062     return e;
1063 }
1064 
operator >(const Mat & a,const Mat & b)1065 MatExpr operator > (const Mat& a, const Mat& b)
1066 {
1067     checkOperandsExist(a, b);
1068     MatExpr e;
1069     MatOp_Cmp::makeExpr(e, CV_CMP_GT, a, b);
1070     return e;
1071 }
1072 
operator >(const Mat & a,double s)1073 MatExpr operator > (const Mat& a, double s)
1074 {
1075     checkOperandsExist(a);
1076     MatExpr e;
1077     MatOp_Cmp::makeExpr(e, CV_CMP_GT, a, s);
1078     return e;
1079 }
1080 
operator >(double s,const Mat & a)1081 MatExpr operator > (double s, const Mat& a)
1082 {
1083     checkOperandsExist(a);
1084     MatExpr e;
1085     MatOp_Cmp::makeExpr(e, CV_CMP_LT, a, s);
1086     return e;
1087 }
1088 
min(const Mat & a,const Mat & b)1089 MatExpr min(const Mat& a, const Mat& b)
1090 {
1091     CV_INSTRUMENT_REGION();
1092 
1093     checkOperandsExist(a, b);
1094     MatExpr e;
1095     MatOp_Bin::makeExpr(e, 'm', a, b);
1096     return e;
1097 }
1098 
min(const Mat & a,double s)1099 MatExpr min(const Mat& a, double s)
1100 {
1101     CV_INSTRUMENT_REGION();
1102 
1103     checkOperandsExist(a);
1104     MatExpr e;
1105     MatOp_Bin::makeExpr(e, 'n', a, s);
1106     return e;
1107 }
1108 
min(double s,const Mat & a)1109 MatExpr min(double s, const Mat& a)
1110 {
1111     CV_INSTRUMENT_REGION();
1112 
1113     checkOperandsExist(a);
1114     MatExpr e;
1115     MatOp_Bin::makeExpr(e, 'n', a, s);
1116     return e;
1117 }
1118 
max(const Mat & a,const Mat & b)1119 MatExpr max(const Mat& a, const Mat& b)
1120 {
1121     CV_INSTRUMENT_REGION();
1122 
1123     checkOperandsExist(a, b);
1124     MatExpr e;
1125     MatOp_Bin::makeExpr(e, 'M', a, b);
1126     return e;
1127 }
1128 
max(const Mat & a,double s)1129 MatExpr max(const Mat& a, double s)
1130 {
1131     CV_INSTRUMENT_REGION();
1132 
1133     checkOperandsExist(a);
1134     MatExpr e;
1135     MatOp_Bin::makeExpr(e, 'N', a, s);
1136     return e;
1137 }
1138 
max(double s,const Mat & a)1139 MatExpr max(double s, const Mat& a)
1140 {
1141     CV_INSTRUMENT_REGION();
1142 
1143     checkOperandsExist(a);
1144     MatExpr e;
1145     MatOp_Bin::makeExpr(e, 'N', a, s);
1146     return e;
1147 }
1148 
operator &(const Mat & a,const Mat & b)1149 MatExpr operator & (const Mat& a, const Mat& b)
1150 {
1151     checkOperandsExist(a, b);
1152     MatExpr e;
1153     MatOp_Bin::makeExpr(e, '&', a, b);
1154     return e;
1155 }
1156 
operator &(const Mat & a,const Scalar & s)1157 MatExpr operator & (const Mat& a, const Scalar& s)
1158 {
1159     checkOperandsExist(a);
1160     MatExpr e;
1161     MatOp_Bin::makeExpr(e, '&', a, s);
1162     return e;
1163 }
1164 
operator &(const Scalar & s,const Mat & a)1165 MatExpr operator & (const Scalar& s, const Mat& a)
1166 {
1167     checkOperandsExist(a);
1168     MatExpr e;
1169     MatOp_Bin::makeExpr(e, '&', a, s);
1170     return e;
1171 }
1172 
operator |(const Mat & a,const Mat & b)1173 MatExpr operator | (const Mat& a, const Mat& b)
1174 {
1175     checkOperandsExist(a, b);
1176     MatExpr e;
1177     MatOp_Bin::makeExpr(e, '|', a, b);
1178     return e;
1179 }
1180 
operator |(const Mat & a,const Scalar & s)1181 MatExpr operator | (const Mat& a, const Scalar& s)
1182 {
1183     checkOperandsExist(a);
1184     MatExpr e;
1185     MatOp_Bin::makeExpr(e, '|', a, s);
1186     return e;
1187 }
1188 
operator |(const Scalar & s,const Mat & a)1189 MatExpr operator | (const Scalar& s, const Mat& a)
1190 {
1191     checkOperandsExist(a);
1192     MatExpr e;
1193     MatOp_Bin::makeExpr(e, '|', a, s);
1194     return e;
1195 }
1196 
operator ^(const Mat & a,const Mat & b)1197 MatExpr operator ^ (const Mat& a, const Mat& b)
1198 {
1199     checkOperandsExist(a, b);
1200     MatExpr e;
1201     MatOp_Bin::makeExpr(e, '^', a, b);
1202     return e;
1203 }
1204 
operator ^(const Mat & a,const Scalar & s)1205 MatExpr operator ^ (const Mat& a, const Scalar& s)
1206 {
1207     checkOperandsExist(a);
1208     MatExpr e;
1209     MatOp_Bin::makeExpr(e, '^', a, s);
1210     return e;
1211 }
1212 
operator ^(const Scalar & s,const Mat & a)1213 MatExpr operator ^ (const Scalar& s, const Mat& a)
1214 {
1215     checkOperandsExist(a);
1216     MatExpr e;
1217     MatOp_Bin::makeExpr(e, '^', a, s);
1218     return e;
1219 }
1220 
operator ~(const Mat & a)1221 MatExpr operator ~(const Mat& a)
1222 {
1223     checkOperandsExist(a);
1224     MatExpr e;
1225     MatOp_Bin::makeExpr(e, '~', a, Scalar());
1226     return e;
1227 }
1228 
abs(const Mat & a)1229 MatExpr abs(const Mat& a)
1230 {
1231     CV_INSTRUMENT_REGION();
1232 
1233     checkOperandsExist(a);
1234     MatExpr e;
1235     MatOp_Bin::makeExpr(e, 'a', a, Scalar());
1236     return e;
1237 }
1238 
abs(const MatExpr & e)1239 MatExpr abs(const MatExpr& e)
1240 {
1241     CV_INSTRUMENT_REGION();
1242 
1243     MatExpr en;
1244     e.op->abs(e, en);
1245     return en;
1246 }
1247 
1248 
size() const1249 Size MatExpr::size() const
1250 {
1251     if( isT(*this) || isInv(*this) )
1252         return Size(a.rows, a.cols);
1253     if( isSolve(*this) )
1254         return Size(b.cols, a.cols);
1255     if( isInitializer(*this) )
1256         return a.size();
1257     return op ? op->size(*this) : Size();
1258 }
1259 
1260 
type() const1261 int MatExpr::type() const
1262 {
1263     CV_INSTRUMENT_REGION();
1264 
1265     if( isInitializer(*this) )
1266         return a.type();
1267     if( isCmp(*this) )
1268         return CV_MAKETYPE(CV_8U, a.channels());
1269     return op ? op->type(*this) : -1;
1270 }
1271 
1272 
1273 /////////////////////////////////////////////////////////////////////////////////////////////////////
1274 
assign(const MatExpr & e,Mat & m,int _type) const1275 void MatOp_Identity::assign(const MatExpr& e, Mat& m, int _type) const
1276 {
1277     if( _type == -1 || _type == e.a.type() )
1278         m = e.a;
1279     else
1280     {
1281         CV_Assert( CV_MAT_CN(_type) == e.a.channels() );
1282         e.a.convertTo(m, _type);
1283     }
1284 }
1285 
makeExpr(MatExpr & res,const Mat & m)1286 inline void MatOp_Identity::makeExpr(MatExpr& res, const Mat& m)
1287 {
1288     res = MatExpr(&g_MatOp_Identity, 0, m, Mat(), Mat(), 1, 0);
1289 }
1290 
1291 /////////////////////////////////////////////////////////////////////////////////////////////////////
1292 
assign(const MatExpr & e,Mat & m,int _type) const1293 void MatOp_AddEx::assign(const MatExpr& e, Mat& m, int _type) const
1294 {
1295     Mat temp, &dst = _type == -1 || e.a.type() == _type ? m : temp;
1296     if( e.b.data )
1297     {
1298         if( e.s == Scalar() || !e.s.isReal() )
1299         {
1300             if( e.alpha == 1 )
1301             {
1302                 if( e.beta == 1 )
1303                     cv::add(e.a, e.b, dst);
1304                 else if( e.beta == -1 )
1305                     cv::subtract(e.a, e.b, dst);
1306                 else
1307                     cv::scaleAdd(e.b, e.beta, e.a, dst);
1308             }
1309             else if( e.beta == 1 )
1310             {
1311                 if( e.alpha == -1 )
1312                     cv::subtract(e.b, e.a, dst);
1313                 else
1314                     cv::scaleAdd(e.a, e.alpha, e.b, dst);
1315             }
1316             else
1317                 cv::addWeighted(e.a, e.alpha, e.b, e.beta, 0, dst);
1318 
1319             if( !e.s.isReal() )
1320                 cv::add(dst, e.s, dst);
1321         }
1322         else
1323         {
1324             if (e.a.channels() > 1)
1325                 CV_LOG_ONCE_WARNING(NULL, "OpenCV/MatExpr: processing of multi-channel arrays might be changed in the future: "
1326                                           "https://github.com/opencv/opencv/issues/16739");
1327             cv::addWeighted(e.a, e.alpha, e.b, e.beta, e.s[0], dst);
1328         }
1329     }
1330     else if( e.s.isReal() && (dst.data != m.data || fabs(e.alpha) != 1))
1331     {
1332         if (e.a.channels() > 1 && e.s[0] != 0.0)
1333             CV_LOG_ONCE_WARNING(NULL, "OpenCV/MatExpr: processing of multi-channel arrays might be changed in the future: "
1334                                       "https://github.com/opencv/opencv/issues/16739");
1335         e.a.convertTo(m, _type, e.alpha, e.s[0]);
1336         return;
1337     }
1338     else if( e.alpha == 1 )
1339         cv::add(e.a, e.s, dst);
1340     else if( e.alpha == -1 )
1341         cv::subtract(e.s, e.a, dst);
1342     else
1343     {
1344         e.a.convertTo(dst, e.a.type(), e.alpha);
1345         cv::add(dst, e.s, dst);
1346     }
1347 
1348     if( dst.data != m.data )
1349         dst.convertTo(m, m.type());
1350 }
1351 
1352 
add(const MatExpr & e,const Scalar & s,MatExpr & res) const1353 void MatOp_AddEx::add(const MatExpr& e, const Scalar& s, MatExpr& res) const
1354 {
1355     CV_INSTRUMENT_REGION();
1356 
1357     res = e;
1358     res.s += s;
1359 }
1360 
1361 
subtract(const Scalar & s,const MatExpr & e,MatExpr & res) const1362 void MatOp_AddEx::subtract(const Scalar& s, const MatExpr& e, MatExpr& res) const
1363 {
1364     CV_INSTRUMENT_REGION();
1365 
1366     res = e;
1367     res.alpha = -res.alpha;
1368     res.beta = -res.beta;
1369     res.s = s - res.s;
1370 }
1371 
multiply(const MatExpr & e,double s,MatExpr & res) const1372 void MatOp_AddEx::multiply(const MatExpr& e, double s, MatExpr& res) const
1373 {
1374     CV_INSTRUMENT_REGION();
1375 
1376     res = e;
1377     res.alpha *= s;
1378     res.beta *= s;
1379     res.s *= s;
1380 }
1381 
divide(double s,const MatExpr & e,MatExpr & res) const1382 void MatOp_AddEx::divide(double s, const MatExpr& e, MatExpr& res) const
1383 {
1384     CV_INSTRUMENT_REGION();
1385 
1386     if( isScaled(e) )
1387         MatOp_Bin::makeExpr(res, '/', e.a, Mat(), s/e.alpha);
1388     else
1389         MatOp::divide(s, e, res);
1390 }
1391 
1392 
transpose(const MatExpr & e,MatExpr & res) const1393 void MatOp_AddEx::transpose(const MatExpr& e, MatExpr& res) const
1394 {
1395     CV_INSTRUMENT_REGION();
1396 
1397     if( isScaled(e) )
1398         MatOp_T::makeExpr(res, e.a, e.alpha);
1399     else
1400         MatOp::transpose(e, res);
1401 }
1402 
abs(const MatExpr & e,MatExpr & res) const1403 void MatOp_AddEx::abs(const MatExpr& e, MatExpr& res) const
1404 {
1405     CV_INSTRUMENT_REGION();
1406 
1407     if( (!e.b.data || e.beta == 0) && fabs(e.alpha) == 1 )
1408         MatOp_Bin::makeExpr(res, 'a', e.a, -e.s*e.alpha);
1409     else if( e.b.data && e.alpha + e.beta == 0 && e.alpha*e.beta == -1 )
1410         MatOp_Bin::makeExpr(res, 'a', e.a, e.b);
1411     else
1412         MatOp::abs(e, res);
1413 }
1414 
makeExpr(MatExpr & res,const Mat & a,const Mat & b,double alpha,double beta,const Scalar & s)1415 inline void MatOp_AddEx::makeExpr(MatExpr& res, const Mat& a, const Mat& b, double alpha, double beta, const Scalar& s)
1416 {
1417     res = MatExpr(&g_MatOp_AddEx, 0, a, b, Mat(), alpha, beta, s);
1418 }
1419 
1420 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1421 
assign(const MatExpr & e,Mat & m,int _type) const1422 void MatOp_Bin::assign(const MatExpr& e, Mat& m, int _type) const
1423 {
1424     Mat temp, &dst = _type == -1 || e.a.type() == _type ? m : temp;
1425 
1426     if( e.flags == '*' )
1427         cv::multiply(e.a, e.b, dst, e.alpha);
1428     else if( e.flags == '/' && e.b.data )
1429         cv::divide(e.a, e.b, dst, e.alpha);
1430     else if( e.flags == '/' && !e.b.data )
1431         cv::divide(e.alpha, e.a, dst );
1432     else if( e.flags == '&' && e.b.data )
1433         bitwise_and(e.a, e.b, dst);
1434     else if( e.flags == '&' && !e.b.data )
1435         bitwise_and(e.a, e.s, dst);
1436     else if( e.flags == '|' && e.b.data )
1437         bitwise_or(e.a, e.b, dst);
1438     else if( e.flags == '|' && !e.b.data )
1439         bitwise_or(e.a, e.s, dst);
1440     else if( e.flags == '^' && e.b.data )
1441         bitwise_xor(e.a, e.b, dst);
1442     else if( e.flags == '^' && !e.b.data )
1443         bitwise_xor(e.a, e.s, dst);
1444     else if( e.flags == '~' && !e.b.data )
1445         bitwise_not(e.a, dst);
1446     else if( e.flags == 'm' )
1447         cv::min(e.a, e.b, dst);
1448     else if( e.flags == 'n' )
1449         cv::min(e.a, e.s[0], dst);
1450     else if( e.flags == 'M' )
1451         cv::max(e.a, e.b, dst);
1452     else if( e.flags == 'N' )
1453         cv::max(e.a, e.s[0], dst);
1454     else if( e.flags == 'a' && e.b.data )
1455         cv::absdiff(e.a, e.b, dst);
1456     else if( e.flags == 'a' && !e.b.data )
1457         cv::absdiff(e.a, e.s, dst);
1458     else
1459         CV_Error(CV_StsError, "Unknown operation");
1460 
1461     if( dst.data != m.data )
1462         dst.convertTo(m, _type);
1463 }
1464 
multiply(const MatExpr & e,double s,MatExpr & res) const1465 void MatOp_Bin::multiply(const MatExpr& e, double s, MatExpr& res) const
1466 {
1467     CV_INSTRUMENT_REGION();
1468 
1469     if( e.flags == '*' || e.flags == '/' )
1470     {
1471         res = e;
1472         res.alpha *= s;
1473     }
1474     else
1475         MatOp::multiply(e, s, res);
1476 }
1477 
divide(double s,const MatExpr & e,MatExpr & res) const1478 void MatOp_Bin::divide(double s, const MatExpr& e, MatExpr& res) const
1479 {
1480     CV_INSTRUMENT_REGION();
1481 
1482     if( e.flags == '/' && (!e.b.data || e.beta == 0) )
1483         MatOp_AddEx::makeExpr(res, e.a, Mat(), s/e.alpha, 0);
1484     else
1485         MatOp::divide(s, e, res);
1486 }
1487 
makeExpr(MatExpr & res,char op,const Mat & a,const Mat & b,double scale)1488 inline void MatOp_Bin::makeExpr(MatExpr& res, char op, const Mat& a, const Mat& b, double scale)
1489 {
1490     res = MatExpr(&g_MatOp_Bin, op, a, b, Mat(), scale, b.data ? 1 : 0);
1491 }
1492 
makeExpr(MatExpr & res,char op,const Mat & a,const Scalar & s)1493 inline void MatOp_Bin::makeExpr(MatExpr& res, char op, const Mat& a, const Scalar& s)
1494 {
1495     res = MatExpr(&g_MatOp_Bin, op, a, Mat(), Mat(), 1, 0, s);
1496 }
1497 
1498 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1499 
assign(const MatExpr & e,Mat & m,int _type) const1500 void MatOp_Cmp::assign(const MatExpr& e, Mat& m, int _type) const
1501 {
1502     Mat temp, &dst = _type == -1 || _type == CV_8U ? m : temp;
1503 
1504     if( e.b.data )
1505         cv::compare(e.a, e.b, dst, e.flags);
1506     else
1507         cv::compare(e.a, e.alpha, dst, e.flags);
1508 
1509     if( dst.data != m.data )
1510         dst.convertTo(m, _type);
1511 }
1512 
makeExpr(MatExpr & res,int cmpop,const Mat & a,const Mat & b)1513 inline void MatOp_Cmp::makeExpr(MatExpr& res, int cmpop, const Mat& a, const Mat& b)
1514 {
1515     res = MatExpr(&g_MatOp_Cmp, cmpop, a, b, Mat(), 1, 1);
1516 }
1517 
makeExpr(MatExpr & res,int cmpop,const Mat & a,double alpha)1518 inline void MatOp_Cmp::makeExpr(MatExpr& res, int cmpop, const Mat& a, double alpha)
1519 {
1520     res = MatExpr(&g_MatOp_Cmp, cmpop, a, Mat(), Mat(), alpha, 1);
1521 }
1522 
1523 /////////////////////////////////////////////////////////////////////////////////////////////////////////
1524 
assign(const MatExpr & e,Mat & m,int _type) const1525 void MatOp_T::assign(const MatExpr& e, Mat& m, int _type) const
1526 {
1527     Mat temp, &dst = _type == -1 || _type == e.a.type() ? m : temp;
1528 
1529     cv::transpose(e.a, dst);
1530 
1531     if( dst.data != m.data || e.alpha != 1 )
1532         dst.convertTo(m, _type, e.alpha);
1533 }
1534 
multiply(const MatExpr & e,double s,MatExpr & res) const1535 void MatOp_T::multiply(const MatExpr& e, double s, MatExpr& res) const
1536 {
1537     CV_INSTRUMENT_REGION();
1538 
1539     res = e;
1540     res.alpha *= s;
1541 }
1542 
transpose(const MatExpr & e,MatExpr & res) const1543 void MatOp_T::transpose(const MatExpr& e, MatExpr& res) const
1544 {
1545     CV_INSTRUMENT_REGION();
1546 
1547     if( e.alpha == 1 )
1548         MatOp_Identity::makeExpr(res, e.a);
1549     else
1550         MatOp_AddEx::makeExpr(res, e.a, Mat(), e.alpha, 0);
1551 }
1552 
makeExpr(MatExpr & res,const Mat & a,double alpha)1553 inline void MatOp_T::makeExpr(MatExpr& res, const Mat& a, double alpha)
1554 {
1555     res = MatExpr(&g_MatOp_T, 0, a, Mat(), Mat(), alpha, 0);
1556 }
1557 
1558 /////////////////////////////////////////////////////////////////////////////////////////////////////////
1559 
assign(const MatExpr & e,Mat & m,int _type) const1560 void MatOp_GEMM::assign(const MatExpr& e, Mat& m, int _type) const
1561 {
1562     Mat temp, &dst = _type == -1 || _type == e.a.type() ? m : temp;
1563 
1564     cv::gemm(e.a, e.b, e.alpha, e.c, e.beta, dst, e.flags);
1565     if( dst.data != m.data )
1566         dst.convertTo(m, _type);
1567 }
1568 
add(const MatExpr & e1,const MatExpr & e2,MatExpr & res) const1569 void MatOp_GEMM::add(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const
1570 {
1571     CV_INSTRUMENT_REGION();
1572 
1573     bool i1 = isIdentity(e1), i2 = isIdentity(e2);
1574     double alpha1 = i1 ? 1 : e1.alpha, alpha2 = i2 ? 1 : e2.alpha;
1575 
1576     if( isMatProd(e1) && (i2 || isScaled(e2) || isT(e2)) )
1577         MatOp_GEMM::makeExpr(res, (e1.flags & ~CV_GEMM_C_T)|(isT(e2) ? CV_GEMM_C_T : 0),
1578                              e1.a, e1.b, alpha1, e2.a, alpha2);
1579     else if( isMatProd(e2) && (i1 || isScaled(e1) || isT(e1)) )
1580         MatOp_GEMM::makeExpr(res, (e2.flags & ~CV_GEMM_C_T)|(isT(e1) ? CV_GEMM_C_T : 0),
1581                              e2.a, e2.b, alpha2, e1.a, alpha1);
1582     else if( this == e2.op )
1583         MatOp::add(e1, e2, res);
1584     else
1585         e2.op->add(e1, e2, res);
1586 }
1587 
subtract(const MatExpr & e1,const MatExpr & e2,MatExpr & res) const1588 void MatOp_GEMM::subtract(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const
1589 {
1590     CV_INSTRUMENT_REGION();
1591 
1592     bool i1 = isIdentity(e1), i2 = isIdentity(e2);
1593     double alpha1 = i1 ? 1 : e1.alpha, alpha2 = i2 ? 1 : e2.alpha;
1594 
1595     if( isMatProd(e1) && (i2 || isScaled(e2) || isT(e2)) )
1596         MatOp_GEMM::makeExpr(res, (e1.flags & ~CV_GEMM_C_T)|(isT(e2) ? CV_GEMM_C_T : 0),
1597                              e1.a, e1.b, alpha1, e2.a, -alpha2);
1598     else if( isMatProd(e2) && (i1 || isScaled(e1) || isT(e1)) )
1599         MatOp_GEMM::makeExpr(res, (e2.flags & ~CV_GEMM_C_T)|(isT(e1) ? CV_GEMM_C_T : 0),
1600                             e2.a, e2.b, -alpha2, e1.a, alpha1);
1601     else if( this == e2.op )
1602         MatOp::subtract(e1, e2, res);
1603     else
1604         e2.op->subtract(e1, e2, res);
1605 }
1606 
multiply(const MatExpr & e,double s,MatExpr & res) const1607 void MatOp_GEMM::multiply(const MatExpr& e, double s, MatExpr& res) const
1608 {
1609     CV_INSTRUMENT_REGION();
1610 
1611     res = e;
1612     res.alpha *= s;
1613     res.beta *= s;
1614 }
1615 
transpose(const MatExpr & e,MatExpr & res) const1616 void MatOp_GEMM::transpose(const MatExpr& e, MatExpr& res) const
1617 {
1618     CV_INSTRUMENT_REGION();
1619 
1620     res = e;
1621     res.flags = (!(e.flags & CV_GEMM_A_T) ? CV_GEMM_B_T : 0) |
1622                 (!(e.flags & CV_GEMM_B_T) ? CV_GEMM_A_T : 0) |
1623                 (!(e.flags & CV_GEMM_C_T) ? CV_GEMM_C_T : 0);
1624     swap(res.a, res.b);
1625 }
1626 
makeExpr(MatExpr & res,int flags,const Mat & a,const Mat & b,double alpha,const Mat & c,double beta)1627 inline void MatOp_GEMM::makeExpr(MatExpr& res, int flags, const Mat& a, const Mat& b,
1628                                  double alpha, const Mat& c, double beta)
1629 {
1630     res = MatExpr(&g_MatOp_GEMM, flags, a, b, c, alpha, beta);
1631 }
1632 
1633 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1634 
assign(const MatExpr & e,Mat & m,int _type) const1635 void MatOp_Invert::assign(const MatExpr& e, Mat& m, int _type) const
1636 {
1637     Mat temp, &dst = _type == -1 || _type == e.a.type() ? m : temp;
1638 
1639     cv::invert(e.a, dst, e.flags);
1640     if( dst.data != m.data )
1641         dst.convertTo(m, _type);
1642 }
1643 
matmul(const MatExpr & e1,const MatExpr & e2,MatExpr & res) const1644 void MatOp_Invert::matmul(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const
1645 {
1646     if( isInv(e1) && isIdentity(e2) )
1647         MatOp_Solve::makeExpr(res, e1.flags, e1.a, e2.a);
1648     else if( this == e2.op )
1649         MatOp::matmul(e1, e2, res);
1650     else
1651         e2.op->matmul(e1, e2, res);
1652 }
1653 
makeExpr(MatExpr & res,int method,const Mat & m)1654 inline void MatOp_Invert::makeExpr(MatExpr& res, int method, const Mat& m)
1655 {
1656     res = MatExpr(&g_MatOp_Invert, method, m, Mat(), Mat(), 1, 0);
1657 }
1658 
1659 /////////////////////////////////////////////////////////////////////////////////////////////////////////
1660 
assign(const MatExpr & e,Mat & m,int _type) const1661 void MatOp_Solve::assign(const MatExpr& e, Mat& m, int _type) const
1662 {
1663     Mat temp, &dst = _type == -1 || _type == e.a.type() ? m : temp;
1664 
1665     cv::solve(e.a, e.b, dst, e.flags);
1666     if( dst.data != m.data )
1667         dst.convertTo(m, _type);
1668 }
1669 
makeExpr(MatExpr & res,int method,const Mat & a,const Mat & b)1670 inline void MatOp_Solve::makeExpr(MatExpr& res, int method, const Mat& a, const Mat& b)
1671 {
1672     res = MatExpr(&g_MatOp_Solve, method, a, b, Mat(), 1, 1);
1673 }
1674 
1675 //////////////////////////////////////////////////////////////////////////////////////////////////////////
1676 
assign(const MatExpr & e,Mat & m,int _type) const1677 void MatOp_Initializer::assign(const MatExpr& e, Mat& m, int _type) const
1678 {
1679     if( _type == -1 )
1680         _type = e.a.type();
1681 
1682     if( e.a.dims <= 2 )
1683         m.create(e.a.size(), _type);
1684     else
1685         m.create(e.a.dims, e.a.size, _type);
1686 
1687     if( e.flags == 'I' && e.a.dims <= 2 )
1688         setIdentity(m, Scalar(e.alpha));
1689     else if( e.flags == '0' )
1690         m = Scalar();
1691     else if( e.flags == '1' )
1692         m = Scalar(e.alpha);
1693     else
1694         CV_Error(CV_StsError, "Invalid matrix initializer type");
1695 }
1696 
multiply(const MatExpr & e,double s,MatExpr & res) const1697 void MatOp_Initializer::multiply(const MatExpr& e, double s, MatExpr& res) const
1698 {
1699     CV_INSTRUMENT_REGION();
1700 
1701     res = e;
1702     res.alpha *= s;
1703 }
1704 
makeExpr(MatExpr & res,int method,Size sz,int type,double alpha)1705 inline void MatOp_Initializer::makeExpr(MatExpr& res, int method, Size sz, int type, double alpha)
1706 {
1707     res = MatExpr(getGlobalMatOpInitializer(), method, Mat(sz, type, (void*)(size_t)0xEEEEEEEE), Mat(), Mat(), alpha, 0);
1708 }
1709 
makeExpr(MatExpr & res,int method,int ndims,const int * sizes,int type,double alpha)1710 inline void MatOp_Initializer::makeExpr(MatExpr& res, int method, int ndims, const int* sizes, int type, double alpha)
1711 {
1712     res = MatExpr(getGlobalMatOpInitializer(), method, Mat(ndims, sizes, type, (void*)(size_t)0xEEEEEEEE), Mat(), Mat(), alpha, 0);
1713 }
1714 
1715 ///////////////////////////////////////////////////////////////////////////////////////////////////////////
1716 
t() const1717 MatExpr Mat::t() const
1718 {
1719     CV_INSTRUMENT_REGION();
1720 
1721     checkOperandsExist(*this);
1722     MatExpr e;
1723     MatOp_T::makeExpr(e, *this);
1724     return e;
1725 }
1726 
inv(int method) const1727 MatExpr Mat::inv(int method) const
1728 {
1729     CV_INSTRUMENT_REGION();
1730 
1731     MatExpr e;
1732     MatOp_Invert::makeExpr(e, method, *this);
1733     return e;
1734 }
1735 
1736 
mul(InputArray m,double scale) const1737 MatExpr Mat::mul(InputArray m, double scale) const
1738 {
1739     CV_INSTRUMENT_REGION();
1740 
1741     MatExpr e;
1742     MatOp_Bin::makeExpr(e, '*', *this, m.getMat(), scale);
1743     return e;
1744 }
1745 
zeros(int rows,int cols,int type)1746 MatExpr Mat::zeros(int rows, int cols, int type)
1747 {
1748     CV_INSTRUMENT_REGION();
1749 
1750     MatExpr e;
1751     MatOp_Initializer::makeExpr(e, '0', Size(cols, rows), type);
1752     return e;
1753 }
1754 
zeros(Size size,int type)1755 MatExpr Mat::zeros(Size size, int type)
1756 {
1757     CV_INSTRUMENT_REGION();
1758 
1759     MatExpr e;
1760     MatOp_Initializer::makeExpr(e, '0', size, type);
1761     return e;
1762 }
1763 
zeros(int ndims,const int * sizes,int type)1764 MatExpr Mat::zeros(int ndims, const int* sizes, int type)
1765 {
1766     CV_INSTRUMENT_REGION();
1767 
1768     MatExpr e;
1769     MatOp_Initializer::makeExpr(e, '0', ndims, sizes, type);
1770     return e;
1771 }
1772 
ones(int rows,int cols,int type)1773 MatExpr Mat::ones(int rows, int cols, int type)
1774 {
1775     CV_INSTRUMENT_REGION();
1776 
1777     MatExpr e;
1778     MatOp_Initializer::makeExpr(e, '1', Size(cols, rows), type);
1779     return e;
1780 }
1781 
ones(Size size,int type)1782 MatExpr Mat::ones(Size size, int type)
1783 {
1784     CV_INSTRUMENT_REGION();
1785 
1786     MatExpr e;
1787     MatOp_Initializer::makeExpr(e, '1', size, type);
1788     return e;
1789 }
1790 
ones(int ndims,const int * sizes,int type)1791 MatExpr Mat::ones(int ndims, const int* sizes, int type)
1792 {
1793     CV_INSTRUMENT_REGION();
1794 
1795     MatExpr e;
1796     MatOp_Initializer::makeExpr(e, '1', ndims, sizes, type);
1797     return e;
1798 }
1799 
eye(int rows,int cols,int type)1800 MatExpr Mat::eye(int rows, int cols, int type)
1801 {
1802     CV_INSTRUMENT_REGION();
1803 
1804     MatExpr e;
1805     MatOp_Initializer::makeExpr(e, 'I', Size(cols, rows), type);
1806     return e;
1807 }
1808 
eye(Size size,int type)1809 MatExpr Mat::eye(Size size, int type)
1810 {
1811     CV_INSTRUMENT_REGION();
1812 
1813     MatExpr e;
1814     MatOp_Initializer::makeExpr(e, 'I', size, type);
1815     return e;
1816 }
1817 
swap(MatExpr & other)1818 void MatExpr::swap(MatExpr& other)
1819 {
1820     using std::swap;
1821 
1822     swap(op, other.op);
1823     swap(flags, other.flags);
1824 
1825     swap(a, other.a);
1826     swap(b, other.b);
1827     swap(c, other.c);
1828 
1829     swap(alpha, other.alpha);
1830     swap(beta, other.beta);
1831 
1832     swap(s, other.s);
1833 }
1834 
_InputArray(const MatExpr & expr)1835 _InputArray::_InputArray(const MatExpr& expr)
1836 {
1837     if (!isIdentity(expr))
1838     {
1839         Mat result = expr;  // TODO improve through refcount == 1 of expr.a (inplace operation is possible - except gemm?)
1840         MatExpr result_expr(result);
1841         swap(const_cast<MatExpr&>(expr), result_expr);
1842     }
1843     CV_Assert(isIdentity(expr));
1844     init(FIXED_TYPE + FIXED_SIZE + MAT + ACCESS_READ, &expr.a);
1845 }
1846 
1847 } // cv::
1848