Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does bitwise_and operator exactly do in openCV?

Tags:

I did not exactly understand what the "bitwise_and" operator does when used in openCV. I would also like to know about it's parameters.

like image 367
Harit Ahuja Avatar asked Jun 02 '17 16:06

Harit Ahuja


People also ask

What does bitwise_and do in Python?

bitwise_and() function is used to Compute the bit-wise AND of two array element-wise. This function computes the bit-wise AND of the underlying binary representation of the integers in the input arrays. Parameters : arr1 : [array_like] Input array.

How do I put 2 photos on cv2?

You can add two images with the OpenCV function, cv. add(), or simply by the numpy operation res = img1 + img2. Both images should be of same depth and type, or the second image can just be a scalar value.

What is mask in Bitwise and OpenCV?

Performing masking on color images: You can mask out a certain region of a given color image using the same function as well. Consider the following image: and consider Screen 1 (given above) to be the mask fin = cv2. bitwise_and(image, image, mask = screen1) cv2. imwrite("Masked image.jpg", fin)

What does Bitwise not do OpenCV?

bitwise_not function. Essentially, the bitwise NOT function flips pixel values. All pixels that are greater than zero are set to zero, and all pixels that are equal to zero are set to 255 : Figure 6: Applying a bitwise NOT with OpenCV.


2 Answers

The general usage is that you want to get a subset of an image defined by another image, typically referred to as a "mask".

So suppose you want to "grab" the top left quadrant of an 8x8 image. You could form a mask that looks like:

1 1 1 1 0 0 0 0
1 1 1 1 0 0 0 0
1 1 1 1 0 0 0 0
1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

You could produce the above image with Python with:

import numpy as np

mask = np.zeros(shape=(8,8), dtype=bool)
mask[0:4,0:4] = True

Then suppose you had an image like:

1 0 1 0 1 1 1 1
0 1 0 1 0 0 0 0
1 0 1 0 1 1 1 1
0 1 0 1 0 0 0 0
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0

For concreteness, imagine that the above image is a simplified representation of the U.S.A. flag: stars in the top left, bars everywhere else. Suppose you wanted to form the above image. You could use the mask, and bitwise_and and bitwise_or to help you.

imageStars = np.ones(shape=(8,8), dtype=bool)
for r, row in enumerate(imageStars):
    for c, col in enumerate(row):
        if r % 2 != c % 2: # even row, odd column, or odd row, even column
            imageStars[r,c] = False

imageBars = np.zeros(shape=(8,8), dtype=bool)
for r, row in enumerate(imageStars):
    if r % 2 == 0:
        imageBars[r,:] = True

Now you have an image of stars:

1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1    
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1    
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1    
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1

And an image of bars:

1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0

And you want to combine them in a particular way, to form the flag, with the stars in the upper left quadrant and the bars everywhere else.

imageStarsCropped = cv2.bitwise_and(imageStars, mask)

imageStarsCropped will look like:

1 0 1 0 0 0 0 0
0 1 0 1 0 0 0 0    
1 0 1 0 0 0 0 0
0 1 0 1 0 0 0 0  
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

Do you see how it was formed? The bitwise_and returns 1 at every pixel where imageStars is 1 AND mask is 1; else, it returns 0.

Now let's get imageBarsCropped. First, let's reverse the mask:

maskReversed = cv2.bitwise_not(mask)

bitwise_not turns 1's into 0's and 0's into 1's. It "flips the bits". maskReversed will look like:

0 0 0 0 1 1 1 1
0 0 0 0 1 1 1 1
0 0 0 0 1 1 1 1
0 0 0 0 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1

Now, we will use maskReversed to "grab" the portion of imageBars that we want.

imageBarsCropped = cv2.bitwise_and(imageBars, maskReversed)

imageBarsCropped will look like:

0 0 0 0 1 1 1 1
0 0 0 0 0 0 0 0
0 0 0 0 1 1 1 1
0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0

Now, let's combined the two "cropped" images to form the flag!

imageFlag = cv2.bitwise_or(imageStarsCropped, imageBarsCropped)

imageFlag will look like:

1 0 1 0 1 1 1 1
0 1 0 1 0 0 0 0
1 0 1 0 1 1 1 1
0 1 0 1 0 0 0 0
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0

Do you see why? bitwise_or returns 1 whenever imageStarsCropped[r,c]==1 OR imageBarsCropped[r,c]==1.

Well, I hope this helps you to understand bitwise operations in OpenCV. These properties have a one-to-one correspondence with bitwise operations with binary numbers that the computer does to do arithmetic.

like image 56
mannyglover Avatar answered Oct 05 '22 00:10

mannyglover


What does the operator do?

bitwise_and, bitwise_or and bitwise_xor perform a bitwise operation on elements taken from two arrays, src1 nd src2. bitwise_not is similar. Bitwise means the boolean operation is done between each bit of the values, bit per bit.

What is the mask parameter?

It's actually not a Boolean mask (and a Boolean array will be rejected). It's a uint8 array type where values are checked as being 0 or not. The "mask" has the same x,y shape than the images, but its elements are scalar, that is for an image 100 x 50 x 3 of uint8, the mask must be an array 100 x 50 of uint8.

How is the mask used?

This mask determines whether the operation will be performed on the pair of pixels at location x,y. If the element at position x,y in the mask is 0, no operation is performed, and the pixel in the resulting array is 0,0,0 (black). If the mask element at position x,y is not null then the bitwise operation determines the value in the resulting array.

Let's say we want to extract pixels within a circle and make other pixels white. This can be done using to bitwise operation with complementary masks:

openCV bitwise_and and bitwise_or

import numpy as np
import cv2
import matplotlib.pyplot as plt

images = 'images/'

# Read image 330 x 379 x 3 uint8
img = cv2.imread(images + 'sample.jpg')

# Reorder channels as display is done with pyplot
img[:,:,[0,1,2]] = img[:,:,[2,1,0]]

# Create white image, 3 channels 330 x 379 x 3 uint8
w_3c = np.full_like(img, fill_value=(255,255,255))

# Define disk elements
center = (img.shape[1]//2, img.shape[0]//2)
radius = int(min(center) * .9)

# Create white disk, 3 channels 330 x 379 x 3 uint8
# and single channel 330 x 379 uint8
d_3c = np.zeros_like (img[:,:], dtype='uint8')
cv2.circle(d_3c, center, radius, [255]*3, thickness=cv2.FILLED)
d_1c = d_3c[:,:,0]

# Extract pixels disk using white disk single channel
masked = cv2.bitwise_and(img, w_3c, mask=d_1c)

# Add white background
d_3c_i = ~d_3c
final = cv2.bitwise_or(img, d_3c_i)

# Prepare to plot
to_plot = [[(img,'img'),
            (w_3c,'w_3c')],
           [(d_3c,'d_3c'),
            (d_1c,'d_1c'),
            (d_3c_i,'d_3c_i')],
           [(masked,'img & w_3c mask d_1c'),
            (final,'img | d_3c_i)')]]
r = len(to_plot)
c = max([len(l) for l in to_plot])

# Show everthing
fig,ax = plt.subplots(r,c, tight_layout=True)
for i in range(r):
    for j in range(c):
        axij = ax[i,j]
        if j < len(to_plot[i]):
            dims = to_plot[i][j][0].ndim
            if dims <= 3:
                axij.imshow(to_plot[i][j][0], cmap='gray')
            else:
                axij.imshow(to_plot[i][j][0])
            axij.set_title(to_plot[i][j][1])
            axij.set_xticks([])
            axij.set_yticks([])
        else:
            axij.set_axis_off()

plt.ioff()
plt.show()

The code can probably be improved.

like image 37
mins Avatar answered Oct 05 '22 00:10

mins