Search code examples
pythonnumpypython-imaging-library

How do you create a semi-transaparent image in numpy and saving it in pillows as PNG


Hello I would like to create a semi-transparent image. What i thought would be straight forward turns out not to be. I created a 1000x1000 pixel array with a depth of 4 (B,G,R,A channels). I initialized them to all 0 thinking that they would produce full black but also fully transparent base image. I then draw a green shape at 50% transaparency, in this case a square to make the code very minimal,

enter image description here

from PIL import Image
import cv2

blankImage = np.zeros((1000,1000,4))
BGRAcolor = (38,255,0,125) # 50% transaparent light green

blankImage[250:250, 750:750] = BGRAcolor

#Image.fromarray(blankImage).save('result.png') #throws an error

cv2.imshow("blankImage", blankImage)
cv2.waitKey()

Problem is i cannot save the image as a .png because PIL throws an error, hence i cannot confirm if i have correctly made the image or not. Error is:

Traceback (most recent call last):
  File "C:\Users\.....\Image.py", line 3098, in fromarray
    mode, rawmode = _fromarray_typemap[typekey]
                    ~~~~~~~~~~~~~~~~~~^^^^^^^^^
KeyError: ((1, 1, 4), '<f8')

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "c:\Users\.....\transparentImage.py", line 25, in <module>
    Image.fromarray(testImage).save('result.png')
    ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\.....\Image.py", line 3102, in fromarray
    raise TypeError(msg) from e
TypeError: Cannot handle this data type: (1, 1, 4), <f8

Alternativly i tried using opencv imshow() to preview the images, but I really cant tell if open cv shows transparent pixels as black or if i have messed up making/assigning values to my alpha layer. Also the color is white for some reason and not green.

Can anyone point out what i am doing wrong?

Pardon that the square became a rectangle strip.

enter image description here


Solution

  • There are two mistakes in your code.

    First, you need to create a numpy array of dtype np.uint8.

    blankImage = np.zeros((1000, 1000, 4), dtype=np.uint8)
    

    Second, you are using slice incorrectly.

    blankImage[top:bottom, left:right] = BGRAcolor
    

    Here is the corrected code.

    import numpy as np
    from PIL import Image
    
    testImage = np.zeros((1000, 1000, 4), dtype=np.uint8)
    BGRAcolor = (38, 255, 0, 125)  # 50% transaparent light green
    
    testImage[250:750, 250:750] = BGRAcolor
    
    Image.fromarray(testImage).save('result.png')