4

I've tried searching for the explanation in different sites but I'm not getting a fully explained answer.

import cv2
import numpy as np
img1 = cv2.imread('3D-Matplotlib.png')
img2 = cv2.imread('mainlogo.png')
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols ]
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 220, 255, cv2.THRESH_BINARY_INV)
mask_inv = cv2.bitwise_not(mask)

#why using similar argument two times? 
img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)

img2_fg = cv2.bitwise_and(img2,img2,mask = mask)
dst = cv2.add(img1_bg,img2_fg)
img1[0:rows, 0:cols ] = dst
cv2.imshow('res',img1)
cv2.waitKey(0)
cv2.destroyAllWindows()
  • 1
    Why did you write it that way? Or where did you get that code? Perhaps if you viewed images after each step you might figure it out. Does it work? – fmw42 Aug 10 '19 at 21:03
  • Possible duplicate of https://stackoverflow.com/questions/32774956/explain-arguments-meaning-in-res-cv2-bitwise-andimg-img-mask-mask – Anubhav Singh Aug 10 '19 at 22:35
  • Possible duplicate of [explain arguments meaning in res = cv2.bitwise\_and(img,img,mask = mask)](https://stackoverflow.com/questions/32774956/explain-arguments-meaning-in-res-cv2-bitwise-andimg-img-mask-mask) – Anubhav Singh Aug 10 '19 at 22:36

1 Answers1

4

I agree it would be more natural if something this worked:

img1_bg = cv2.bitwise_and(roi, mask_inv) # will not work
#raises cv2.error: /modules/core/src/arithm.cpp:225: error: (-209:Sizes of input arguments do not match) The operation is neither 'array op array' (where arrays have the same size and type), nor 'array op scalar', nor 'scalar op array' in function 'binary_op'

And the first question is why doesn't it. The thing is, the roi and mask_inv arrays have different shapes: (rows, cols, channels) vs (rows, cols, 1). I guess, the authors of the OpenCV library wanted to prevent silent shape casting, which may be unsafe and introduce hard to catch bugs, and decided to implement the check, that the first two arguments are of the same shape.

The second question is why this works:

img1_bg = cv2.bitwise_and(roi, roi, mask_inv)

In short, the answer is that for any array of integers (like roi) it is always true that

roi == cv2.bitwise_and(roi, roi)

This holds due to the fact that 0 & 0 == 0 and 1 & 1 == 1 for the bits. But the cv2.bitwise_and function is actually a combination of two:

  1. Apply bitwise and to the images from the first two arguments
  2. Apply mask to the result, i.e. make equal to zeroes (== black) any pixel, where mask is zero.

In this typical usage you present, the first part of this function is not used, the two arguments make this part work like identity, it doesn't change the array. So you kind of bypass the first part with a trick of putting the first two arguments equal. The second part is the only one, which is applied in this typical usage.

P.S. Please, see the answers, linked in the comments for more info.

Dima Mironov
  • 525
  • 4
  • 19