Home > Enterprise >  Opencv imshow is right whereas imwrite is wrong?
Opencv imshow is right whereas imwrite is wrong?

Time:11-12

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

imshow: imshow result

imwrite: enter image description here

my back.png back.png

my cover.png cover.png

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 Output image

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.

  • Related