OpenCV - Apply mask to a color image

image-processing, mask, opencv, python

Solution

import cv2 as cv

im_color = cv.imread("lena.png", cv.IMREAD_COLOR)
im_gray = cv.cvtColor(im_color, cv.COLOR_BGR2GRAY)

At this point you have a color and a gray image. We are dealing with `8-bit`, `uint8` images here. That means the images can have pixel values in the range of `[0, 255]` and the values have to be integers.

Let's do a binary thresholding operation. It creates a black and white masked image. The black regions have value `0` and the white regions `255`

_, mask = cv.threshold(im_gray, thresh=180, maxval=255, type=cv.THRESH_BINARY)
im_thresh_gray = cv.bitwise_and(im_gray, mask)

The mask can be seen below on the left. The image on its right is the result of applying `bitwise_and` operation between the gray image and the mask. What happened is, the spatial locations where the mask had a pixel value zero (black), became pixel value zero in the result image. The locations where the mask had pixel value 255 (white), the resulting image retained its original gray value.

To apply this mask to our original color image, we need to convert the mask into a 3 channel image as the original color image is a 3 channel image.

mask3 = cv.cvtColor(mask, cv.COLOR_GRAY2BGR)  # 3 channel mask

Then, we can apply this 3 channel mask to our color image using the same `bitwise_and` function.

im_thresh_color = cv.bitwise_and(im_color, mask3)

`mask3` from the code is the image below on the left, and `im_thresh_color` is on its right.

You can plot the results and see for yourself.

cv.imshow("original image", im_color)
cv.imshow("binary mask", mask)
cv.imshow("3 channel mask", mask3)
cv.imshow("im_thresh_gray", im_thresh_gray)
cv.imshow("im_thresh_color", im_thresh_color)
cv.waitKey(0)

The original image is `lenacolor.png` that I found here.

Problem

How can I apply mask to a color image in latest python binding (cv2)? In previous python binding the simplest way was to use `cv.Copy` e.g. `cv.Copy(dst, src, mask)` But this function is not available in cv2 binding. Is there any workaround without using boilerplate code?

Original source