1
votes

Say I have an BGRA image as numpy array that looks pretty much like this:

[[[233 228 230   128]
  [233 228 230   128]
  [233 228 230   0]
  ...
  [164 160 159   65]
  [199 197 196   65]
  [255 255 254   120]]

That looks pretty straightforward - three colour channels + one alpha that controls transparency of pixels. Saving that numpy array in a PNG format results in an image that is semi-transparent as it should be.

However, when saving it as JPEG, the alpha channel is dropped completely and the all of the pixels are fully opaque.

As JPEG does not support alpha-transparency, I would like my semi-transparent image (the numpy array above) to be saved on a white background instead. That way, it would appear as if the pixels would still be semi-transparent.

How can I overlay the semi-transparent numpy array on a fully white background? I am using mainly numpy and OpenCV.

2

2 Answers

2
votes

I think you are looking more for gradated alpha-blending than the simpler alpha-thresholding that Fred's answer nicely demonstrates.

I made a sample image with an alpha gradient in the middle for test purposes. Here it is as a normal image and composited over a checkerboard to show the transparency like Photoshop does:

enter image description here

enter image description here

To do alpha blending you use the formula:

result = alpha * Foreground + (1-alpha)*Background

where the values are all floats scaled on the range 0..1


The code for blending over black and then white background follows:

#!/usr/bin/env python3

import cv2
import numpy as np

# Load image, including gradient alpha layer
im = cv2.imread('GradientAlpha.png', cv2.IMREAD_UNCHANGED)

# Separate BGR channels from A, make everything float in range 0..1
BGR = im[...,0:3].astype(np.float)/255
A   = im[...,3].astype(np.float)/255

# First, composite image over black background using:
# result = alpha * Foreground + (1-alpha)*Background
bg  = np.zeros_like(BGR).astype(np.float)     # black background
fg  = A[...,np.newaxis]*BGR                   # new alpha-scaled foreground
bg = (1-A[...,np.newaxis])*bg                 # new alpha-scaled background
res = cv2.add(fg, bg)                         # sum of the parts
res = (res*255).astype(np.uint8)              # scaled back up
cv2.imwrite('OverBlack.png', res)

# Now, composite image over white background
bg  = np.zeros_like(BGR).astype(np.float)+1   # white background
fg  = A[...,np.newaxis]*BGR                   # new alpha-scaled foreground
bg = (1-A[...,np.newaxis])*bg                 # new alpha-scaled background
res = cv2.add(fg, bg)                         # sum of the parts
res = (res*255).astype(np.uint8)              # scaled back up
cv2.imwrite('OverWhite.png', res)

That gives this over black:

enter image description here

And this over white:

enter image description here

Keywords: Image processing, Python, OpenCV, alpha, alpha blending, alpha compositing, overlay.

1
votes

In Python OpenCV Numpy, you can separate the alpha channel from the image. So if imgA is the image with alpha channel. Then separate the rgb image (img) and the alpha channel (alpha)

img = imgA[:,:,0:3]
alpha = imgA[:,:,3]

Then set the color of img to white where the alpha is black

img[alpha == 0] = (255,255,255)