Zapisywanie przezroczystego PNG jako JPEG na białym tle

Nov 26 2020

Powiedzmy, że mam obraz BGRA jako numpytablicę, która wygląda mniej więcej tak:

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

Wygląda to całkiem prosto - trzy kanały kolorów + jedna alfa kontrolująca przezroczystość pikseli. Zapisanie tej tablicy numpy w formacie PNG powoduje, że obraz jest półprzezroczysty, tak jak powinien.

Jednak podczas zapisywania pliku jako JPEG kanał alfa jest całkowicie pomijany, a wszystkie piksele są całkowicie nieprzezroczyste.

Ponieważ format JPEG nie obsługuje przezroczystości alfa, chciałbym, aby zamiast tego mój półprzezroczysty obraz (powyższa tablica numpy) został zapisany na białym tle. W ten sposób wyglądałoby to tak, jakby piksele nadal były półprzezroczyste.

Jak mogę nałożyć półprzezroczystą tablicę numpy na w pełni białe tło? Używam głównie numpy i OpenCV.

Odpowiedzi

2 MarkSetchell Nov 27 2020 at 10:44

Myślę, że bardziej szukasz stopniowego mieszania alfa niż prostszego progowania alfa, co ładnie pokazuje odpowiedź Freda.

Zrobiłem przykładowy obraz z gradientem alfa pośrodku do celów testowych. Tutaj jest to normalny obraz i złożony na szachownicy, aby pokazać przezroczystość, tak jak robi to Photoshop:

Aby wykonać mieszanie alfa, użyj wzoru:

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

gdzie wszystkie wartości są zmiennoprzecinkowe przeskalowane w zakresie 0..1


Kod łączenia na czarnym i białym tle jest następujący:

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

To daje to na czarno:

A to na białym:

Słowa kluczowe : przetwarzanie obrazu, Python, OpenCV, alpha, alpha blending, alpha compositing, overlay.

1 fmw42 Nov 27 2020 at 06:16

W Python OpenCV Numpy możesz oddzielić kanał alfa od obrazu. Więc jeśli imgA jest obrazem z kanałem alfa. Następnie oddziel obraz rgb (img) i kanał alfa (alfa)

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

Następnie ustaw kolor img na biały, gdzie alfa jest czarny

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