Problem about Background transparent .png format OpenCV with Python

16,770

Solution 1

First, let me mention that if you display an image with alpha transparency using cv2.imshow then the transparent areas are going to be black.


Since your input image already contains an alpha channel, the solution is simple -- just reuse the alpha channel.

There's a slight problem -- even though PNG format allows to have grayscale with alpha channel, AFAIK there is no way to write such an image with OpenCV.

Therefore the solution is straightforward: Take the processed grayscale image, convert it back to BGR, add the original alpha channel, and save the result.

Since we're in Python, and therefore the image is represented as a numpy array, we can use array indexing to extract the channels we need. numpy.dstack allows us to add the alpha channel easily.


Sample code:

import cv2
import numpy as np

src = cv2.imread('51IgH.png', cv2.IMREAD_UNCHANGED)

bgr = src[:,:,:3] # Channels 0..2
gray = cv2.cvtColor(bgr, cv2.COLOR_BGR2GRAY)

# Some sort of processing...

bgr = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
alpha = src[:,:,3] # Channel 3
result = np.dstack([bgr, alpha]) # Add the alpha channel

cv2.imwrite('51IgH_result.png', result)

Result:

Once more on different background, so you can see it's really transparent:

Solution 2

You have to add a fourth channel in your array so that the transparency information can be encoded in the alpha channel.

Here is a python code example:

import cv2
file_name = "source.png"

src = cv2.imread(file_name, cv2.IMREAD_UNCHANGED)

# Save the transparency channel alpha
*_, alpha = cv2.split(src)

gray_layer = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)

# ... Your image processing

# Duplicate the grayscale image to mimic the BGR image and finally add the transparency
dst = cv2.merge((gray_layer, gray_layer, gray_layer, alpha))
cv2.imwrite("result.png", dst)

Result for grey image:

Grey image with transparency

Result for BGR image:

Share:
16,770
zzob
Author by

zzob

Updated on June 19, 2022

Comments

  • zzob
    zzob almost 2 years

    I'm studying on OpenCV with Python. I tried to change a color of picture in PNG format, but I have got some problem with PNG background (The image has transparent background).

    When I change it to grayscale, the background has changed to black -- my picture is not transparent anymore. What I desire is to keep the transparent background of picture.


    Original image:

    My code:

    img = cv2.imread('line.png',cv2.IMREAD_UNCHANGED)
    cv2.imshow('line',img)
    cv2.waitKey()
    

    Output image:

    Desired output:

    The white color around the border image should be transparent. How I can do this?

  • zzob
    zzob over 5 years
    you have example ?
  • Dan Mašek
    Dan Mašek over 5 years
    Please, don't use magic numbers in code samples. That 1 in cv2.imread should really be a cv2.IMREAD_COLOR. | However, looking at this again, it seems much of this is unnecessary. OP's input image already contains a transparency channel, so there's no need to determine it again using threshold.
  • zzob
    zzob over 5 years
    what is meaning of src[: , : , :3] . why the last index is must be :3 only ?
  • Dan Mašek
    Dan Mašek over 5 years
    @lyca That's the array indexing I mention in the answer -- IMHO it's quite worth taking some time to read that documentation page. In this case it means "give me all the columns, all the rows and all the channels up to (and not including) 3". NB: Remember indexing starts at 0. | A transparent image is a 4 channel image, in this case the channels being Blue (0), Green (1), Red (2), Alpha transparency (3). So that command basically gets rid of the transparency channel, and lets us work only on the colour info.
  • vozman
    vozman over 3 years
    opencv ignores transparent channel at all when doing cv2.imshow