I have an image of a living room and a mask that represents the floor area (Please see attached images). I want to replace the floor area with the texture image while preserving the perspective to make it look realistic.
This is the current result.
The hardest part is the mask is a complex polygon so I couldn’t find a way to find four corners to do perspective transformation.
I attempted the Perspective Transform and Warp Perspective methods, but they did not provide expected result.
Here’s my code, please guide me to solve this
import cv2
import numpy as np
from matplotlib import pyplot as plt
target_img_path = 'livingroom1.png'
mask_img_path = 'floor_mask1.png'
texture_img_path = 'flooring-texture.png'
target_img = cv2.imread(target_img_path)
mask_img = cv2.imread(mask_img_path, cv2.IMREAD_GRAYSCALE)
texture_img = cv2.imread(texture_img_path)
contours, _ = cv2.findContours(mask_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
mask_contour = max(contours, key=cv2.contourArea)
hull = cv2.convexHull(mask_contour)
rect = cv2.minAreaRect(hull)
box = cv2.boxPoints(rect)
box = np.array(box, dtype="float32")
# Tile the texture image to cover the entire target image
tile_height, tile_width = texture_img.shape[:2]
target_height, target_width = target_img.shape[:2]
num_tiles_x = int(np.ceil(target_width / tile_width))
num_tiles_y = int(np.ceil(target_height / tile_height))
# Create a large canvas to hold the tiled texture
tiled_texture = np.zeros((num_tiles_y * tile_height, num_tiles_x * tile_width, 3), dtype=texture_img.dtype)
# Tile the texture
for i in range(num_tiles_y):
for j in range(num_tiles_x):
tiled_texture[i * tile_height:(i + 1) * tile_height, j * tile_width:(j + 1) * tile_width] = texture_img
tiled_texture = tiled_texture[:target_height, :target_width]
texture_points = np.array([[0, 0],
[tiled_texture.shape[1], 0],
[tiled_texture.shape[1], tiled_texture.shape[0]],
[0, tiled_texture.shape[0]]], dtype=np.float32)
matrix = cv2.getPerspectiveTransform(texture_points, box)
warped_texture = cv2.warpPerspective(tiled_texture, matrix, (target_width, target_height))
mask = np.zeros_like(target_img, dtype=np.uint8)
cv2.fillPoly(mask, [mask_contour], (255, 255, 255))
warped_texture_masked = cv2.bitwise_and(warped_texture, mask)
inverse_mask = cv2.bitwise_not(mask)
target_img_masked = cv2.bitwise_and(target_img, inverse_mask)
result = cv2.add(target_img_masked, warped_texture_masked)
plt.figure(figsize=(10, 10))
plt.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.show()