TaihouKai
TaihouKai

Reputation: 371

Overlay smaller image to larger image in Python

I know this question has been asked for several times, e.g., this one, but my problem is I need to overlay a smaller PNG image with a larger PNG image, where both images need to maintain their transparency in the output.

For example, smaller image is like: enter image description here ... larger image is like: enter image description here (The image above has only 1 pixel filled with white color and 90% transparency)

Using the code examples given in the previous question (overlay a smaller image on a larger image python OpenCv), the larger background image will be in black.

def overlay_image_alpha(img, img_overlay, x, y, alpha_mask):
    """Overlay `img_overlay` onto `img` at (x, y) and blend using `alpha_mask`.

    `alpha_mask` must have same HxW as `img_overlay` and values in range [0, 1].
    """
    # Image ranges
    y1, y2 = max(0, y), min(img.shape[0], y + img_overlay.shape[0])
    x1, x2 = max(0, x), min(img.shape[1], x + img_overlay.shape[1])

    # Overlay ranges
    y1o, y2o = max(0, -y), min(img_overlay.shape[0], img.shape[0] - y)
    x1o, x2o = max(0, -x), min(img_overlay.shape[1], img.shape[1] - x)

    # Exit if nothing to do
    if y1 >= y2 or x1 >= x2 or y1o >= y2o or x1o >= x2o:
        return

    # Blend overlay within the determined ranges
    img_crop = img[y1:y2, x1:x2]
    img_overlay_crop = img_overlay[y1o:y2o, x1o:x2o]
    alpha = alpha_mask[y1o:y2o, x1o:x2o, np.newaxis]
    alpha_inv = 1.0 - alpha

    img_crop[:] = alpha * img_overlay_crop + alpha_inv * img_crop


# Prepare inputs
x, y = 50, 0
img = np.array(Image.open("template.png"))
img_overlay_rgba = np.array(Image.open("../foo.png"))

# Perform blending
alpha_mask = img_overlay_rgba[:, :, 3] / 255.0
img_result = img[:, :, :3].copy()
img_overlay = img_overlay_rgba[:, :, :3]
overlay_image_alpha(img_result, img_overlay, x, y, alpha_mask)

# Save result
Image.fromarray(img_result).save("img_result.png")

Result: enter image description here

My desired result is to maintain the larger image's transparency.

May I know how to do so?

Upvotes: 0

Views: 570

Answers (1)

Ege Yıldırım
Ege Yıldırım

Reputation: 435

This is actually the correct output. Fully transparent images (like your template image) have the pixel value of 0 on empty areas which represents black. If you were to use semi-transparent templates (which have pixels value greater than 0 even if they are slightly transparent). You should see this:

enter image description here

Answer 2:

Your output images are 24bit. (Which means you get rid of thhe alpha channel before saving it). I looked into your code and saw the lines 34 and 35;

img_result = img[:, :, :3].copy()   
img_overlay = img_overlay_rgba[:, :, :3]

You're sending RGB images to overlay_image_alpha function. Change this to;

img_result = img.copy()
img_overlay = img_overlay_rgba

To preserve Alpha channel information.

New Output:

enter image description here

On Photoshop:

enter image description here

Upvotes: 1

Related Questions