Salvando PNG transparente como JPEG em fundo branco

Nov 26 2020

Digamos que eu tenha uma imagem BGRA como numpyarray que se parece muito com isto:

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

Isso parece bastante simples - três canais de cores + um alfa que controla a transparência dos pixels. Salvar essa matriz numpy em um formato PNG resulta em uma imagem que é semitransparente como deveria ser.

No entanto, ao salvá-lo como JPEG, o canal alfa é totalmente descartado e todos os pixels ficam totalmente opacos.

Como JPEG não oferece suporte para transparência alfa, gostaria que minha imagem semitransparente (a matriz numpy acima) fosse salva em um fundo branco. Dessa forma, pareceria que os pixels ainda seriam semitransparentes.

Como posso sobrepor a matriz numpy semitransparente em um fundo totalmente branco? Estou usando principalmente numpy e OpenCV.

Respostas

2 MarkSetchell Nov 27 2020 at 10:44

Acho que você está procurando mais pela mistura alfa graduada do que pelo limiar alfa mais simples que a resposta de Fred demonstra muito bem.

Fiz uma imagem de amostra com um gradiente alfa no meio para fins de teste. Aqui está como uma imagem normal e composta sobre um tabuleiro de xadrez para mostrar a transparência como o Photoshop faz:

Para fazer a mistura alfa, você usa a fórmula:

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

onde os valores são todos flutuantes em escala no intervalo 0..1


O código para mesclar sobre fundo preto e depois branco segue:

#!/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)

Isso dá isso sobre o preto:

E isso sobre o branco:

Palavras - chave : Processamento de imagens, Python, OpenCV, alfa, mistura alfa, composição alfa, sobreposição.

1 fmw42 Nov 27 2020 at 06:16

No Python OpenCV Numpy, você pode separar o canal alfa da imagem. Portanto, se imgA é a imagem com canal alfa. Em seguida, separe a imagem rgb (img) e o canal alfa (alfa)

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

Em seguida, defina a cor de img para branco, onde o alfa é preto

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