3 votes

Comment fusionner deux images RGBA

J'essaie de fusionner deux images RGBA (avec une forme de (h,w,4)), en tenant compte de leurs canaux alpha.
Exemple : example


Ce que j'ai essayé

J'ai essayé de le faire en utilisant opencv pour cela, mais j'obtiens des pixels étranges sur l'image de sortie.

Images utilisées :

image1.png

y

image2.png

import cv2
import numpy as np
import matplotlib.pyplot as plt

image1 = cv2.imread("image1.png", cv2.IMREAD_UNCHANGED)
image2 = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)

mask1 = image1[:,:,3]
mask2 = image2[:,:,3]
mask2_inv = cv2.bitwise_not(mask2)

mask2_bgra = cv2.cvtColor(mask2, cv2.COLOR_GRAY2BGRA)
mask2_inv_bgra = cv2.cvtColor(mask2_inv, cv2.COLOR_GRAY2BGRA)

# output = image2*mask2_bgra + image1
output = cv2.bitwise_or(cv2.bitwise_and(image2, mask2_bgra), cv2.bitwise_and(image1, mask2_inv_bgra))
output[:,:,3] = cv2.bitwise_or(mask1, mask2)
plt.figure(figsize=(12,12))
plt.imshow(cv2.cvtColor(output, cv2.COLOR_BGRA2RGBA))
plt.axis('off')

Sortie :
output

Ce que j'ai compris, c'est que j'ai ces pixels bizarres parce que j'ai utilisé cv2.bitwise_and (qui fonctionne parfaitement avec les canaux alpha binaires). J'ai essayé d'utiliser différentes approches


Question

Existe-t-il une approche pour faire cela (tout en gardant l'image de sortie comme une image 8bit).

2voto

Jeru Luke Points 7725

J'ai pu obtenir le résultat escompté en 2 étapes.

# Read both images preserving the alpha channel
hh1 = cv2.imread(r'C:\Users\524316\Desktop\Stack\house.png', cv2.IMREAD_UNCHANGED)  
hh2 = cv2.imread(r'C:\Users\524316\Desktop\Stack\memo.png', cv2.IMREAD_UNCHANGED)   

# store the alpha channels only
m1 = hh1[:,:,3]
m2 = hh2[:,:,3]

# invert the alpha channel and obtain 3-channel mask of float data type
m1i = cv2.bitwise_not(m1)
alpha1i = cv2.cvtColor(m1i, cv2.COLOR_GRAY2BGRA)/255.0

m2i = cv2.bitwise_not(m2)
alpha2i = cv2.cvtColor(m2i, cv2.COLOR_GRAY2BGRA)/255.0

# Perform blending and limit pixel values to 0-255 (convert to 8-bit)
b1i = cv2.convertScaleAbs(hh2*(1-alpha2i) + hh1*alpha2i)

Note : Dans l'image b=supérieure, nous utilisons seulement le canal alpha inverse de l'image mémo.

enter image description here

Mais je suppose que ce n'est pas le résultat attendu. Alors on continue ....

# Finding common ground between both the inverted alpha channels
mul = cv2.multiply(alpha1i,alpha2i)

# converting to 8-bit
mulint = cv2.normalize(mul, dst=None, alpha=0, beta=255,norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)

# again create 3-channel mask of float data type
alpha = cv2.cvtColor(mulint[:,:,2], cv2.COLOR_GRAY2BGRA)/255.0

# perform blending using previous output and multiplied result
final = cv2.convertScaleAbs(b1i*(1-alpha) + mulint*alpha)

enter image description here

Désolé pour les noms de variables bizarres. Je vous demanderais d'analyser le résultat de chaque ligne. J'espère que c'est le résultat attendu.

0voto

W0rk L0ne Points 21

Vous pouvez utiliser la bibliothèque PIL pour y parvenir

from PIL import Image

def merge_images(im1, im2):
    bg = Image.open(im1).convert("RGBA")
    fg = Image.open(im2).convert("RGBA")
    x, y = ((bg.width - fg.width) // 2 , (bg.height - fg.height) // 2)
    bg.paste(fg, (x, y), fg)
    # convert to 8 bits (pallete mode)
    return bg.convert("P") 

nous pouvons le tester en utilisant les images fournies :

result_image = merge_images("image1.png", "image2.png")
result_image.save("image3.png")

Voici le résultat :

image3.png

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X