fixed mask operations with uninitialized output array, added the corresponding test...
authorVadim Pisarevsky <no@email>
Wed, 28 Mar 2012 09:07:00 +0000 (09:07 +0000)
committerVadim Pisarevsky <no@email>
Wed, 28 Mar 2012 09:07:00 +0000 (09:07 +0000)
modules/core/src/arithm.cpp
modules/core/test/test_arithm.cpp

index 01e1f4f..97c8659 100644 (file)
@@ -1027,6 +1027,7 @@ void binary_op(InputArray _src1, InputArray _src2, OutputArray _dst,
     int cn = src1.channels();
     BinaryFunc copymask = 0;
     Mat mask;
+    bool reallocate = false;
 
     if( haveMask )
     {
@@ -1034,6 +1035,8 @@ void binary_op(InputArray _src1, InputArray _src2, OutputArray _dst,
         CV_Assert( (mask.type() == CV_8UC1 || mask.type() == CV_8SC1) );
         CV_Assert( mask.size == src1.size );
         copymask = getCopyMaskFunc(esz);
+        Mat tdst = _dst.getMat();
+        reallocate = tdst.size != src1.size || tdst.type() != src1.type();
     }
 
     AutoBuffer<uchar> _buf;
@@ -1041,6 +1044,11 @@ void binary_op(InputArray _src1, InputArray _src2, OutputArray _dst,
 
     _dst.create(src1.dims, src1.size, src1.type());
     Mat dst = _dst.getMat();
+    
+    // if this is mask operation and dst has been reallocated,
+    // we have to 
+    if( haveMask && reallocate )
+        dst = Scalar::all(0);
 
     if( bitwise )
     {
@@ -1214,6 +1222,7 @@ void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst,
     int kind1 = _src1.kind(), kind2 = _src2.kind();
     Mat src1 = _src1.getMat(), src2 = _src2.getMat();
     bool haveMask = !_mask.empty();
+    bool reallocate = false;
 
     if( kind1 == kind2 && src1.dims <= 2 && src2.dims <= 2 &&
         src1.size() == src2.size() && src1.type() == src2.type() &&
@@ -1302,6 +1311,8 @@ void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst,
         CV_Assert( (mask.type() == CV_8UC1 || mask.type() == CV_8SC1) );
         CV_Assert( mask.size == src1.size );
         copymask = getCopyMaskFunc(dsz);
+        Mat tdst = _dst.getMat();
+        reallocate = tdst.size != src1.size || tdst.type() != dtype;
     }
 
     AutoBuffer<uchar> _buf;
@@ -1310,6 +1321,10 @@ void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst,
 
     _dst.create(src1.dims, src1.size, dtype);
     Mat dst = _dst.getMat();
+    
+    if( haveMask && reallocate )
+        dst = Scalar::all(0);
+    
     BinaryFunc func = tab[CV_MAT_DEPTH(wtype)];
 
     if( !haveScalar )
index d59dc7b..1c6b76c 100644 (file)
@@ -1402,4 +1402,90 @@ INSTANTIATE_TEST_CASE_P(Core_MinMaxLoc, ElemWiseTest, ::testing::Values(ElemWise
 INSTANTIATE_TEST_CASE_P(Core_CartToPolarToCart, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CartToPolarToCartOp)));
 
 
+class CV_ArithmMaskTest : public cvtest::BaseTest
+{
+public:
+    CV_ArithmMaskTest() {}
+    ~CV_ArithmMaskTest() {}   
+protected:
+    void run(int)
+    {
+        try
+        {
+            RNG& rng = theRNG();
+            const int MAX_DIM=3;
+            int sizes[MAX_DIM];
+            for( int iter = 0; iter < 100; iter++ )
+            {
+                //ts->printf(cvtest::TS::LOG, ".");
+                
+                ts->update_context(this, iter, true);
+                int k, dims = rng.uniform(1, MAX_DIM+1), p = 1;
+                int depth = rng.uniform(CV_8U, CV_64F+1);
+                int cn = rng.uniform(1, 6);
+                int type = CV_MAKETYPE(depth, cn);
+                int op = rng.uniform(0, 5);
+                int depth1 = op <= 1 ? CV_64F : depth;
+                for( k = 0; k < dims; k++ )
+                {
+                    sizes[k] = rng.uniform(1, 30);
+                    p *= sizes[k];
+                }
+                Mat a(dims, sizes, type), a1;
+                Mat b(dims, sizes, type), b1;
+                Mat mask(dims, sizes, CV_8U);
+                Mat mask1;
+                Mat c, d;
+                
+                // [-2,2) range means that the each generated random number
+                // will be one of -2, -1, 0, 1. Saturated to [0,255], it will become
+                // 0, 0, 0, 1 => the mask will be filled by ~25%.
+                rng.fill(mask, RNG::UNIFORM, -2, 2);
+                
+                a.convertTo(a1, depth1);
+                b.convertTo(b1, depth1);
+                // invert the mask
+                compare(mask, 0, mask1, CMP_EQ);
+                a1.setTo(0, mask1);
+                b1.setTo(0, mask1);
+                
+                if( op == 0 )
+                {
+                    add(a, b, c, mask);
+                    add(a1, b1, d);
+                }
+                else if( op == 1 )
+                {
+                    subtract(a, b, c, mask);
+                    subtract(a1, b1, d);
+                }
+                else if( op == 2 )
+                {
+                    bitwise_and(a, b, c, mask);
+                    bitwise_and(a1, b1, d);
+                }
+                else if( op == 3 )
+                {
+                    bitwise_or(a, b, c, mask);
+                    bitwise_or(a1, b1, d);
+                }
+                else if( op == 4 )
+                {
+                    bitwise_xor(a, b, c, mask);
+                    bitwise_xor(a1, b1, d);
+                }
+                Mat d1;
+                d.convertTo(d1, depth);
+                CV_Assert( norm(c, d1, CV_C) == 0 );
+            }
+        }
+        catch(...)
+        {
+            ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+        }
+    }
+};
+
+TEST(Core_ArithmMask, uninitialized) { CV_ArithmMaskTest test; test.safe_run(); }
+