I recently worked on a project that required blending multiple images together. I successfully completed all the necessary steps and successfully blended the images. However, I noticed that when I blended the images, black lines appeared on the borders of each piece of the final image, indicating where each image was placed. You can see an example of the final image with these artifacts in the following link:
These artifacts are noticeable even with a quick glance at the image.
This is my code for blending the images:
def normalize_piece(img):
return cv2.normalize(img.astype('float'), None, 0.0, 1.0, cv2.NORM_MINMAX)
def blend_pieces(piece1, piece2, transformation_matrix, width, height):
piece1_norm = normalize_piece(piece1)
piece2_norm = normalize_piece(piece2)
piece1_warped = cv2.warpPerspective(src=piece1_norm, M=transformation_matrix, dsize=(width, height))
black_rgb_pixel = np.zeros(3)
mask_left = np.all(piece1_warped != black_rgb_pixel, axis=-1)
mask_right = np.all(piece2_norm != black_rgb_pixel, axis=-1)
mask_overlap = mask_left & mask_right
mask_left_only = mask_left & ~mask_right
mask_right_only = mask_right & ~mask_left
piece1_warped[mask_left_only] = piece1_warped[mask_left_only]
piece1_warped[mask_right_only] = piece2_norm[mask_right_only]
piece1_warped[mask_overlap] = (piece1_warped[mask_overlap] + piece2_norm[mask_overlap]) / 2
return piece1_warped
I have these 3 parts of the final image for example and I want to merge them together:
I need to blend part 1 with part 2. And then, I need to blend the blended part with part 3.
I was able to achieve an answer to my question.
Here is a simple code to merge the parts that were provided in the question:
import numpy as np
import cv2
width = 808
height = 457
def blend_images(image1, image2):
# Create the canvas with the desired shape
# Note that when debugging it shows that the canvas is ndarray of shape (457, 808, 3)
# The 457 here represents the height, the 808 represents the width and the 3 represents the channels (RGB)
canvas = np.zeros((height, width, 3), dtype=np.uint8)
# Iterate over the canvas and the two images while taking the maximum RGB value of the two images for each pixel
for y in range(height):
for x in range(width):
canvas[y, x] = np.maximum(image1[y, x], image2[y, x])
return canvas
def main():
# Change the images paths to your images paths
image1 = cv2.imread('part1.jpg')
image2 = cv2.imread('part2.jpg')
image3 = cv2.imread('part3.jpg')
# Blend the first two images
canvas1 = blend_images(image1, image2)
# Blend the blended images with the third image to get the final result
canvas2 = blend_images(canvas1, image3)
# Show the final result
cv2.imshow('Canvas', canvas2)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
The blend_images
function creates a canvas of the specified shape (height, width) and merges the two input images using an element-wise maximum operation. Specifically, the function iterates over each pixel of the canvas and selects the maximum RGB value from the corresponding pixels in the two input images. The resulting pixel values are then assigned to the corresponding pixel in the new image.
Thanks to a helpful comment from 'Christoph Rackwitz', it was pointed out that the merging operation in the blend_images
function can be performed more efficiently using a Numpy routine.
Here's an updated version of the code:
import numpy as np
import cv2
def blend_images(image1, image2):
# Ensure that the input images have the same shape
assert image1.shape == image2.shape
return np.maximum(image1, image2)
def main():
# Change the images paths to your images paths
image1 = cv2.imread('part1.jpg')
image2 = cv2.imread('part2.jpg')
image3 = cv2.imread('part3.jpg')
# Blend the first two images
canvas = blend_images(image1, image2)
# Blend the blended images with the third image to get the final result
canvas = blend_images(canvas, image3)
# Show the final result
cv2.imshow('Canvas', canvas)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
In this updated code, the blend_images
function is modified to use the Numpy maximum
function instead of nested loops to perform the merging operation. The function also includes an assertion to ensure that the input images have the same shape.