0

I tried the below code, it doesn't show any error and runs properly, but changing the value of the alpha channel, doesn't show any change in image

img3 = cv2.cvtColor(img2, cv2.COLOR_BGR2BGRA)
img3[:,:,3] = 100
cv2.imshow('img1',img2)    
cv2.imshow('img',img3)     
cv2.waitKey(0)

works ok, but the output of both images are same and there is no seen-able change after applying alpha channel

i have already tried the below code

papanito
  • 2,349
  • 2
  • 32
  • 60

1 Answers1

7

Your code is actually correct.

The simple answer is that OpenCV's imshow() ignores transparency, so if you want to see its effect, save your image as a PNG/TIFF (both of which support transparency) and view it with a different viewer - such as GIMP, Photoshop or feh.

As an alternative, I made a wrapper/decorator for OpenCV's imshow() that displays images with transparency overlaid on a chessboard like Photoshop does. So, starting with this RGBA Paddington image and this grey+alpha Paddington image:

enter image description here

enter image description here

#!/usr/bin/env python3

import cv2
import numpy as np

def imshow(title,im):
    """Decorator for OpenCV "imshow()" to handle images with transparency"""

    # Check we got np.uint8, 2-channel (grey + alpha) or 4-channel RGBA image
    if (im.dtype == np.uint8) and (len(im.shape)==3) and (im.shape[2] in set([2,4])):

       # Pick up the alpha channel and delete from original
       alpha = im[...,-1]/255.0
       im = np.delete(im, -1, -1)

       # Promote greyscale image to RGB to make coding simpler
       if len(im.shape) == 2:
          im = np.stack((im,im,im))

       h, w, _ = im.shape

       # Make a checkerboard background image same size, dark squares are grey(102), light squares are grey(152)
       f = lambda i, j: 102 + 50*((i+j)%2)
       bg = np.fromfunction(np.vectorize(f), (16,16)).astype(np.uint8)

       # Resize to square same length as longer side (so squares stay square), then trim
       if h>w:
          longer = h
       else:
          longer = w
       bg = cv2.resize(bg, (longer,longer), interpolation=cv2.INTER_NEAREST)
       # Trim to correct size
       bg = bg[:h,:w]

       # Blend, using result = alpha*overlay + (1-alpha)*background
       im = (alpha[...,None] * im + (1.0-alpha[...,None])*bg[...,None]).astype(np.uint8)

    cv2.imshow(title,im)


if __name__ == "__main__":

    # Open RGBA image
    im = cv2.imread('paddington.png',cv2.IMREAD_UNCHANGED)

    imshow("Paddington (RGBA)",im)
    key = cv2.waitKey(0)
    cv2.destroyAllWindows()

    # Open Grey + alpha  image
    im = cv2.imread('paddington-ga.png',cv2.IMREAD_UNCHANGED)

    imshow("Paddington (grey + alpha)",im)
    key = cv2.waitKey(0)
    cv2.destroyAllWindows()

And you will get this:

enter image description here

and this:

enter image description here

Keywords: Image, image processing, Python, alpha channel, transparency, overlay, checkerboard, chessboard, blend, blending. OpenCV, imshow, cv2.imshow.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • b_channel, g_channel, r_channel = cv2.split(img) alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 50 #creating a dummy alpha channel image. img_BGRA = cv2.merge((b_channel, g_channel, r_channel, alpha_channel)) can you please tell the differrnce between this code and the code which i have asked peviously , do they both do the same job. also what should i change if i want my alpha channel to have an intensity of 50% ..thanks – Harshit Gupta Nov 04 '19 at 09:18
  • i have also seen that using plt.show can make the changes in alpha channel seenable – Harshit Gupta Nov 04 '19 at 09:22
  • Sorry, I don't know what your comment means, and comments are not a good place for code as they come out unformatted and difficult to read. If you have some new code, please click `edit` under your original question and add it in there and then add a comment to my answer to alert me to whatever is new. Thank you. – Mark Setchell Nov 04 '19 at 09:22
  • If your pixels are `uint8` (i.e. in range 0..255) and you want 50% transparency, use `alpha = np.ones_like(b_channel) * 128` – Mark Setchell Nov 04 '19 at 09:25
  • 1
    Yes, it is perfectly possible that **matplotlib** and **PIL/Pillow** can display images with transparency, but your question was tagged with **OpenCV** so I presumed you wanted an OpenCV solution... plus plenty of others on StackOverflow seem to be having issues displaying transparency so I thought it might be useful to make a Photoshop-like viewer with chessboard underneath. Use whatever makes you happy though! – Mark Setchell Nov 04 '19 at 09:28
  • https://stackoverflow.com/a/32290192/12315516 can u please tell the difference between the above code and the code i have originally written , are they doing the same job . thanks – Harshit Gupta Nov 04 '19 at 09:51
  • also if i want 50% transperancy , can i do this to my original code , will it work img3[:,:,3] = 255*0.5 – Harshit Gupta Nov 04 '19 at 09:52