Cole uma imagem em outra imagem em duas coordenadas fornecidas com opacidade alterada usando PIL ou OpenCV em Python
Tenho duas imagens com determinados pontos, um ponto para cada imagem, que precisam ser alinhadas para que a imagem resultante seja um somatório de ambas as imagens, enquanto a imagem 2 é colada na imagem 1 com 40% de opacidade. Levei essa questão em consideração, mas nosso caso não corresponde exatamente, pois a coordenada da imagem é fornecida pelo usuário e as imagens podem ter uma ampla variedade de tamanhos.
Imagem 1:

Image2:

Resultado final (saída desejada):

Para isso, experimentei a img.paste()
função PIL e substituí os valores em uma série de imagens em cv2, ambos dando resultados que estão longe do desejado.
Respostas
Fiz duas imagens de entrada com ImageMagick assim:
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


Em seguida, executei o seguinte código:
#!/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')
O resultado é este:

As linhas que salvam imagens com nomes começando "DEBUG-xxx.png"
são apenas para depuração fácil e podem ser removidas. Posso facilmente ver todos eles para ver o que está acontecendo com o código e posso facilmente excluí-los removendo "DEBUG*png"
.
Sem mais detalhes, tentarei responder à pergunta da melhor maneira possível e nomearei todas as suposições extras que fiz (e como lidar com elas se você não puder fazê-las).
Como não foram fornecidas imagens, criei uma imagem azul e verde com um ponto preto como coordenada de mesclagem, usando o seguinte código:
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)
Isso resulta nas seguintes imagens:

Agora, presumirei que as imagens ainda não contêm uma camada alfa (como eu as criei sem). Portanto, vou carregar a imagem e adicionar uma camada alfa a eles:
import numpy as np
from PIL import Image
blue = Image.open('blue.png')
blue.putalpha(255)
green = Image.open('green.png')
green.putalpha(255)
Minha suposição a seguir é que você conhece as coordenadas de mesclagem de antemão:
# Assuming x, y coordinates.
point_blue = (300, 100)
point_green = (50, 50)
Então você pode criar uma imagem vazia, que pode conter ambas as imagens facilmente:
new_image = np.zeros((1000, 1000, 4), dtype=np.uint8)
Esta é uma suposição muito exagerada se você não souber o tamanho da imagem de antemão e, caso não saiba, terá que calcular o tamanho de combinação das duas imagens.
Em seguida, você pode colocar o ponto das imagens no centro das imagens recém-criadas (no meu caso (500, 500). Para isso, você usa os pontos de mesclagem como deslocamentos. E você pode realizar a mesclagem alfa (em qualquer caso np.uint8(img_1*alpha + img_2*(1-alpha))
:) para mesclar o imagens usando opacidade diferente.
Que está no código:
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')
O resultado final será uma imagem maior, das imagens combinadas, novamente você pode calcular a caixa delimitadora correta, então você não tem essas áreas enormes de 'nada' saindo. O resultado final ficará assim:
