Skip to content Skip to sidebar Skip to footer

Paste An Image To Another Image At Two Given Co-ordinates With Altered Opacity Using PIL Or OpenCV In Python

I have two images with given points, one point each image, that need to be aligned so that the result image is a summation of both images, while image 2 is pasted on image 1 with 4

Solution 1:

I made two input images with ImageMagick like this:

magick -size 300x400 xc:"rgb(1,204,255)" -fill red -draw "point 280,250" 1.png
magick -size 250x80  xc:"rgb(150,203,0)" -fill red -draw "point 12,25"   2.png

enter image description here enter image description here

Then ran the following code:

#!/usr/bin/env python3
"""
Paste one image on top of another such that given points in each are coincident.
"""

from PIL import Image

# Open images and ensure RGB
im1 = Image.open('1.png').convert('RGB')
im2 = Image.open('2.png').convert('RGB')

# x,y coordinates of point in each image
p1x, p1y = 280, 250
p2x, p2y = 12, 25

# Work out how many pixels of space we need left, right, above, below common point in new image
pL = max(p1x, p2x)
pR = max(im1.width-p1x,  im2.width-p2x)
pT = max(p1y, p2y)
pB = max(im1.height-p1y, im2.height-p2y)

# Create background in solid white
bg = Image.new('RGB', (pL+pR, pT+pB),'white')
bg.save('DEBUG-bg.png')

# Paste im1 onto background
bg.paste(im1, (pL-p1x, pT-p1y))
bg.save('DEBUG-bg+im1.png')

# Make 40% opacity mask for im2
alpha = Image.new('L', (im2.width,im2.height), int(40*255/100))
alpha.save('DEBUG-alpha.png')

# Paste im2 over background with alpha
bg.paste(im2, (pL-p2x, pT-p2y), alpha)
bg.save('result.png')

The result is this:

enter image description here

The lines that save images with names starting "DEBUG-xxx.png" are just for easy debugging and can be removed. I can easily view them all to see what is going on with the code and I can easily delete them all by removing "DEBUG*png".


Solution 2:

Without any more details, I will try to answer the question as best as I can and will name all the extra assumptions that I made (and how to handle them if you can't make them).

Since there were no provided images, I created a blue and green image with a black dot as merging coordinate, using the following code:

import numpy as np

from PIL import Image, ImageDraw


def create_image_with_point(name, color, x, y, width=3):
    image = np.full((400, 400, 3), color, dtype=np.uint8)
    image[y - width:y + width, x - width:x + width] = (0, 0, 0)
    image = Image.fromarray(image, mode='RGB')
    ImageDraw.Draw(image).text((x - 15, y - 20), 'Point', (0, 0, 0))
    image.save(name)
    return image


blue = create_image_with_point('blue.png', color=(50, 50, 255), x=300, y=100)
green = create_image_with_point('green.png', color=(50, 255, 50), x=50, y=50)

This results in the following images:

Blue and green image, with combination dot marker.

Now I will make the assumption that the images do not contain an alpha layer yet (as I created them without). Therefore I will load the image and add an alpha layer to them:

import numpy as np

from PIL import Image

blue = Image.open('blue.png')
blue.putalpha(255)

green = Image.open('green.png')
green.putalpha(255)

My following assumption is that you know the merge coordinates beforehand:

# Assuming x, y coordinates.
point_blue = (300, 100)
point_green = (50, 50)

Then you can create an empty image, that can hold both of the images easily:

new_image = np.zeros((1000, 1000, 4), dtype=np.uint8)

This is a far stretch assumption if you do not know the image size beforehand, and in case you do not know this you will have to calculate the combining size of the two images.

Then you can place the images dot in the center of the newly created images (in my case (500, 500). For this you use the merging points as offsets. And you can perform alpha blending (in any case: np.uint8(img_1*alpha + img_2*(1-alpha))) to merge the images using different opacity.

Which is in code:

def place_image(image: Image, point_xy: tuple[int, int], dest: np.ndarray, alpha: float = 1.) -> np.ndarray:

    # Place the merging dot on (500, 500).
    offset_x, offset_y = 500 - point_xy[0], 500 - point_xy[1]

    # Calculate the location of the image and perform alpha blending.
    destination = dest[offset_y:offset_y + image.height, offset_x:offset_x + image.width]
    destination = np.uint8(destination * (1 - alpha) + np.array(image) * alpha)

    # Copy the 'merged' imaged to the destination location.
    dest[offset_y:offset_y + image.height, offset_x:offset_x + image.width] = destination
    return dest

# Add the background image blue with alpha 1
new_image = place_image(blue, point_blue, dest=new_image, alpha=1)

# Add the second image with 40% opacity
new_image = place_image(green, point_green, dest=new_image, alpha=0.4)

# Store the resulting image.
image = Image.fromarray(new_image)
image.save('result.png')

The final result will be a bigger image, of the combined images, again you can calculate the correct bounding box, so you don't have these huge areas of 'nothing' sticking out. The final result will look like this:

enter image description here


Post a Comment for "Paste An Image To Another Image At Two Given Co-ordinates With Altered Opacity Using PIL Or OpenCV In Python"