I just want to cover an png image with another png image, cv2.imshow got the right result, cv2.imwrite got the strange result.
coverImg = cv2.imread('./images/cover.png', cv2.IMREAD_UNCHANGED)
back = cv2.imread('./images/back.png', cv2.IMREAD_UNCHANGED)
x_offset = y_offset = 0
y1, y2 = y_offset, y_offset coverImg.shape[0]
x1, x2 = x_offset, x_offset coverImg.shape[1]
alpha_s = coverImg[:, :, 3] / 255.0
alpha_l = 1.0 - alpha_s
result = back.copy()
for c in range(0, 3):
result[y1:y2, x1:x2, c] = (alpha_s * coverImg[y1:y2, x1:x2, c]
alpha_l * result[y1:y2, x1:x2, c])
cv2.imshow("result", result)
res2 = cv2.imwrite("./result.png", result)
result.dtype is uint8
CodePudding user response:
The problem occurs because you're modifying a copy of the original background image, which you loaded as BGRA, but do not modify the alpha channel on the result. Since the background image is mostly transparent (other than the shadows), so is the result when viewed by something that supports alpha.
To fix this and keep the result partially transparent (where appropriate), you need to merge the alpha channels as well. Since alpha=0 means fully transparent, alpha=255 means fully opaque, and our goal is to retain the opaque parts of both images, let's take max(foreground_alpha, background_alpha) for each pixel. This can be accomplished using 
CodePudding user response:
Your arrays are of floating point type because you use division.
imshow and imread treat float arrays differently.
imshow assumes the brightness to be ranging from 0.0 to 1.0, if the data is float (0 to 255 for uint8).
imwrite just converts to uint8, so the range still needs to be 0 to 255 for floats.
You should convert your float data to uint8 using .astype(np.uint8)
You also need to mind the transparency channel. imshow ignores that, doesn't "show" its effects. It will show you the color of pixels that are marked as transparent.




