I would like to add a semi-transparent rectangle filled with a solid colour to an already loaded semi-transparent PNG. Here's an example input image I am using:
That image is loaded with a standard cv2.IMREAD_UNCHANGED
flag so that alpha channel is perfectly preserved. That input image is stored in the image
variable.
Here's my code that I have so far:
# get image dimensions
imgHeight, imgWidth = image.shape[:2]
# create empty overlay layer with 4 channels
overlay = np.zeros((imgHeight, imgWidth, 4), dtype = "uint8")
# draw semi-transparent red rectangle
overlay[200:300, 0:imgWidth] = (0, 0, 255, 200)
# extract alpha channel from overlay
alpha = cv2.split(overlay)[3]
# compute mask
mask = (np.multiply(alpha, 1.0 / 255))[:, :, np.newaxis]
# blend input image and overlay
output = cv2.convertScaleAbs(overlay * mask + image * (1 - mask))
And here's the result that I am getting:
At first glance it looks acceptable. We have our input image with a semi-transparent rectangle in the middle. However, upon closer inspection, we can observe strange behaviour when mixing alpha channels (marked with arrows):
It seems that alpha is not blended at all which results in original image pixels being only fully opaque or fully transparent.
Perhaps my method of blending transparent PNG with semi-transparent shapes is far from ideal. As a side note, I did try the cv2.addWeighted
method but that yielded even worse results.
I would like the solution to be limited to OpenCV and/or Numpy. Any help would be greatly appreciated.