Masks in python opencv cv2 not working?
Question: While in general the new python bindings for opencv (cv2) are a beauty,
"masks" don't seem to be working properly - unless I really get something
wrong:

For example "cv2.add" still works properly without a mask:

    
    
    import cv2
    a = ones((2,2,3), dtype=uint8)
    cv2.add(a,a)
    

correctly gives

    
    
    array([[[2, 2, 2],
            [2, 2, 2]],
    
           [[2, 2, 2],
            [2, 2, 2]]], dtype=uint8)
    

But when you add a mask (and an out array "b" - which is required by for some
reason is not assigned either) you get a RANDOM result, i.e. the result
changes when you run the command multiple times

    
    
    myMask = zeros(a.shape[0:2], dtype = uint8)
    mask[1,1] = 255
    b = zeros(a.shape)
    cv2.add(a,a,b,myMask)
    cv2.add(a,a,b,myMask)
    

gives on my machine (Win7, 32bit,Python 2.7, opencv 2.3.1)

    
    
    In [34]: cv2.add(a,a,b,myMask)
    Out[34]: 
    array([[[ 26,   0, 143],
            [  5, 216, 245]],
    
           [[156,   5, 104],
            [  2,   2,   2]]], dtype=uint8)
    
    In [35]: cv2.add(a,a,b,myMask)
    Out[35]: 
    array([[[35,  0,  0],
            [ 0,  3,  0]],
    
           [[ 0,  0,  3],
            [ 2,  2,  2]]], dtype=uint8)
    

... and something new on the next trial. Now either I get something seriously
wrong, or there is a serious problem with the cv2 bindings.

Any suggestions?


Answer: Its an interesting question. I am seeing the same problem. I posted a bug and
got a reply. <http://code.opencv.org/issues/1748>

The solution is simple. The dst array is undefined on creation and the
operation changes only those destination array pixels p, for which mask(p)!=0.

So the only mechanism that works is to premake dst before addition. I.e.

    
    
    dst = np.zeros(...)
    dst = cv2.add(a, a, dst=dst, mask=mask)
    

The next release will clear newly created images in operations such as
cv2.add, cv2.subtract, cv2.bitwise_and/or/xor - so it will work without
problem.

my code looks like:

    
    
    import cv2
    import numpy as np
    import time
    
    a = np.ones((2,2,3), dtype=np.uint8)
    
    print "simple add"
    t = time.time()
    for i in range(10000):
        b = cv2.add(a,a)
    print "%5.4f seconds" % (time.time()-t)
    print b
    
    print "\nnumpy add"
    t = time.time()
    for i in range(10000):
        b = a+a
    print "%5.4f seconds" % (time.time()-t)
    print b
    
    # make mask same dimensions but 1 byte deep(not three)
    mask = np.zeros(a.shape[:-1], dtype=np.uint8)
    mask[1,1] = 255
    
    print "\nmask", mask.shape
    print mask
    
    print "\nmasked add - uninitialised"
    t = time.time()
    for i in range(10000):
        b = cv2.add(a,a,mask=mask)
    print "%5.4f seconds" % (time.time()-t)
    print b
    print "uninitialised entries are unmodified - so random.\n Inconsistent when run more than once."
    print "same calc a second time..."
    b = cv2.add(a,a,mask=mask)
    print b
    
    print "\nmasked add - using preinitialised dst"
    t = time.time()
    b = a.copy()
    for i in range(10000):
        b = cv2.add(a,a,b,mask=mask)
    print "%5.4f seconds" % (time.time()-t)
    print b
    print "Consistent when run more than once."
    print "same calc a second time..."
    b = a.copy()
    b = cv2.add(a,a,b,mask=mask)
    print b
    

FYI: timings (10k repeats):

    
    
    cv2.add - no mask            0.0120 seconds
    cv2.add - with mask          0.0160 seconds
    np.add                       0.0190 seconds
    cv2.add - uninitialised mask 0.0220 seconds
    

FYI: Submit bugs following instructions here:
<http://code.opencv.org/projects/OpenCV/wiki/WikiStart>

