Instantly share code, notes, and snippets.

Embed
What would you like to do?
import numpy as np
import cv2
def overlay_alpha_image_lazy(background_rgb, overlay_rgba, alpha):
# cf https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
# If the destination background is opaque, then
# out_rgb = overlay_rgb * overlay_alpha + background_rgb * (1 - overlay_alpha)
overlay_alpha = overlay_rgba[: , : , 3].astype(np.float) / 255. * alpha
overlay_alpha_3 = np.dstack((overlay_alpha, overlay_alpha, overlay_alpha))
overlay_rgb = overlay_rgba[: , : , : 3].astype(np.float)
background_rgb_f = background_rgb.astype(np.float)
out_rgb = overlay_rgb * overlay_alpha_3 + background_rgb_f * (1. - overlay_alpha_3)
out_rgb = out_rgb.astype(np.uint8)
return out_rgb
def overlay_alpha_image_precise(background_rgb, overlay_rgba, alpha, gamma_factor=2.2):
"""
cf minute physics brilliant clip "Computer color is broken" : https://www.youtube.com/watch?v=LKnqECcg6Gw
the RGB values are gamma-corrected by the sensor (in order to keep accuracy for lower luminancy),
we need to undo this before averaging.
"""
overlay_alpha = overlay_rgba[: , : , 3].astype(np.float) / 255. * alpha
overlay_alpha_3 = np.dstack((overlay_alpha, overlay_alpha, overlay_alpha))
overlay_rgb_squared = np.float_power(overlay_rgba[: , : , : 3].astype(np.float), gamma_factor)
background_rgb_squared = np.float_power( background_rgb.astype(np.float), gamma_factor)
out_rgb_squared = overlay_rgb_squared * overlay_alpha_3 + background_rgb_squared * (1. - overlay_alpha_3)
out_rgb = np.float_power(out_rgb_squared, 1. / gamma_factor)
out_rgb = out_rgb.astype(np.uint8)
return out_rgb
def test_overlay():
img = np.zeros((100, 800, 3), np.uint8)
img[ : , : , : ] = (0, 0, 255)
overlay = np.zeros((100, 800, 4), np.uint8)
def make_gradient(x0, color):
x1 = x0 + 40
for x in range(x0, x1):
for y in range(0, 100):
k = (x - x0) / (x1 - x0)
alpha = int(round(k * 255.))
color_grad = (color[0], color[1], color[2], alpha)
overlay[y, x, :] = color_grad
make_gradient(100, (255, 0, 0))
make_gradient(200, (0, 255, 0))
make_gradient(300, (255, 255, 0))
make_gradient(400, (0, 255, 255))
make_gradient(500, (250, 50, 200))
mix_precise = overlay_alpha_image_precise(img, overlay, alpha=1.)
mix_lazy = overlay_alpha_image_lazy(img, overlay, alpha=1.)
cv2.imshow("mix_precise", mix_precise)
cv2.imshow("mix_lazy", mix_lazy)
#cv2.imshow("img", img)
#cv2.imshow("overlay", overlay)
cv2.waitKey()
test_overlay()
@pthom

This comment has been minimized.

Owner

pthom commented Apr 5, 2018

overlay_alpha_image_precise() gives the following result:
mix_precise

Compared to overlay_alpha_image_lazy()
mix_lazy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment