Search code examples
pythonopencvimage-processingpython-imaging-libraryalpha

Png transparency with opencv in python


I've been using opencv to paste a png image over a background. My target is to simulate a sort of plastic bag underwater. In that way, I would like to apply Alpha in order to have the png image semi-transparent over the background, but when I do, the black mask of the png becomes transparent too.

y1, y2 = yoff, yoff + png.shape[0]
x1, x2 = xoff, xoff + png.shape[1]

alpha_png = png[:, :, 3] / 255.0
alpha_bg = 0.5 - alpha_png

bg_copy = bg.copy()

for c in range(0, 3):
    bg_copy[y1:y2, x1:x2, c] = (alpha_png * png[:, :, c] + alpha_bg * bg_copy[y1:y2, x1:x2, c])
cv2.imwrite("result.png", bg_copy)

I found this code online, and I changed the alpha_bg in order to make the image more or less transparent.

And the result is png image on background

I need to remove the black semi-transparent background, but the rest of the png should remain semi-transparent, plus the bag should get the background green color or underwater color (But I'll work later on this).

Any suggestion is really appreciated, also considering to use PIL instead of opencv.

Edit:

The used images are: Foreground foreground

And Background: background


Solution

  • Filling out the the details from the answer according Christoph Rackwitz, we crop the water image at the desired location to the size of the bag and blend with the bag image (bgr) using the mask from the alpha channel. Then we insert the resulting composite into a copy of the water image at the desired location.

    import cv2
    import numpy as np
    
    # read the background image
    water = cv2.imread('background.jpg')
    h, w = water.shape[:2]
    cx = w//2
    cy = h//2
    
    # read the foreground image
    bag = cv2.imread('bag.png', cv2.IMREAD_UNCHANGED)
    hh, ww = bag.shape[:2]
    
    # separate bgr and alpha in bag image
    bag_bgr = bag[:,:,0:3]
    bag_alpha = bag[:,:,3]
    
    # crop the water image at center to size of bag
    water2 = water.copy()
    water_crop = water2[cy:cy+hh, cx:cx+ww]
    
    blend = 0.5
    mask = blend*bag_alpha.astype(np.float32)/255
    mask = mask[..., None]
    composite = bag_bgr.astype(np.float32) * mask + water_crop.astype(np.float32) * (1-mask)
    composite = composite.astype(np.uint8)
    
    # insert composite into water
    result = water.copy()
    result[cy:cy+hh, cx:cx+ww] = composite
    
    # save results
    cv2.imwrite('water_bag2.jpg', result)
    
    # show results
    cv2.imshow('result', result)
    cv2.waitKey(0)
    

    Result:

    enter image description here