Here is the background image;
Here is the foreground image;
Here is the Mask image;
The code below;
background = cv2.imread('back.jpg')
image = cv2.imread('img.jpg')
mask = cv2.imread('mask.jpg')
crop_background = cv2.resize(background, (image.shape[1], image.shape[0]), interpolation = cv2.INTER_NEAREST)
mask = np.where(mask == 0, mask, image)
crop_background1 = np.where(mask == 0, crop_background, mask)
cv2.imshow(f'{i}', crop_background1)
cv2.waitKey(0)
output image After running the code;
CodePudding user response:
Carefully look at the data types you are handling. All three images are BGR
, they have three intensity values per pixel. In the where
function you are only checking and setting one intensity value, so you only change the blue channel, instead of all three channels.
Now, you also have to be careful while composing these images. Be aware of pixel values possible “wrapping around” (unsigned integer overflow) and masking the correct pixels. One possible solution is to compose the image using a linear relationship between pixels values. Nothing fancy, just assigning the pixel values according to the mask matrix:
newPixel = (originalPixel * maskPixel backgroundPixel * (1-maskPixel))
Note what happens when maskPixel
is 0
or 1
(You'll need to use float
types). You can see that the "ramp" correctly sets the newPixel
value. The operation is also vectorizable. Let's check out the new code:
import cv2
import numpy as np
# Image path
path = "D://opencvImages//"
# Reading the images in default mode:
background = cv2.imread(path "jkU1C.jpg")
image = cv2.imread(path "QNuXL.jpg")
mask = cv2.imread(path "6yyNG.png")
# Resize background:
crop_background = cv2.resize(background, (image.shape[1], image.shape[0]), interpolation = cv2.INTER_NEAREST)
# BGR to Gray mask:
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
# Threshold mask:
_, mask = cv2.threshold(mask, 0, 255, cv2.THRESH_BINARY)
# Back to BGR:
mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
# Convert mask to float in range 0 to 1
mask = mask.astype(np.float64) / 255
# Get new pixel according to the mask matrix:
result = (image * mask crop_background * (1 - mask))
# Clip values and convert back to uint8:
result = result.clip(0, 255).astype(np.uint8)
# Show result:
cv2.imshow("result", result)
cv2.waitKey(0)
The result: