Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to merge two RGBA images

I'm trying to merge two RGBA images (with a shape of (h,w,4)), taking into account their alpha channels.
Example : example


What I've tried

I tried to do this using opencv for that, but I getting some strange pixels on the output image.

Images Used:

image1.png

and

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')

Output :
output

So what I figured out is that I'm getting those weird pixels because I used cv2.bitwise_and function (Which btw works perfectly with binary alpha channels). I tried using different approaches


Question

Is there an approach to do this (While keeping the output image as an 8bit image).

like image 730
SaulGoodMan Avatar asked Oct 26 '25 08:10

SaulGoodMan


1 Answers

I was able to obtain the expected result in 2 stages.

# 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: In the b=above the we are using only the inverse alpha channel of the memo image

enter image description here

But I guess this is not the expected result. So moving on ....

# 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

Sorry for the weird variable names. I would request you to analyze the result in each line. I hope this is the expected output.

like image 89
Jeru Luke Avatar answered Oct 28 '25 22:10

Jeru Luke



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!