Python: How to write a single channel png file from numpy array?

15,144

Solution 1

Here is a solution using opencv / cv2

import cv2
myImg = np.random.randint(255, size=(200, 400)) # create a random image
cv2.imwrite('myImage.png',myImg)

Solution 2

PIL's Image.fromarray() automatically determines the mode to use from the datatype of the passed numpy array, for example for an 8-bit greyscale image you can use:

from PIL import Image
import numpy as np

data = np.random.randint(256, size=(100, 100), dtype=np.uint8)
img = Image.fromarray(data)  # uses mode='L'

This however only works if your array uses a compatible datatype, if you simply use data = np.random.randint(256, size=(100, 100)) that can result in a int64 array (typestr <i8), which PIL can't handle.

You can also specify a different mode, e.g. to interpret a 32bit array as an RGB image:

data = np.random.randint(2**32, size=(100, 100), dtype=np.uint32)
img = Image.fromarray(data, mode='RGB')

Internally Image.fromarray() simply tries to guess the correct mode and size and then invokes Image.frombuffer().

The image can then be saved as any format PIL can handle e.g: img.save('filename.png')

Solution 3

You might want not to utilise OpenCV for simple image manipulation. As suggested, use PIL:

im = Image.fromarray(arr)
im.save("output.png", "PNG")

Have you tried this? What has failed here that led you to concluding that this is JPEG-only?

Share:
15,144

Related videos on Youtube

mcExchange
Author by

mcExchange

Updated on September 15, 2022

Comments

  • mcExchange
    mcExchange over 1 year

    I want to write a single channel png image from a numpy array in python? In Matlab that would be

    A = randi(100,100,255)
    imwrite(uint8(A),'myFilename.png','png');
    

    I saw exampels using from PIL import Image and Image.fromarray() but they are for jpeg and 3-channel pngs only it appears...

    I already found the solution using opencv, I will post it here. Hopefully it will shorten someone else's searching...

  • mcExchange
    mcExchange about 7 years
    this saves a 3 channel pnd, but I need a 1 channel png file
  • Pearley
    Pearley about 7 years
    Then you need your array to be of type uint8. im = Image.fromarray(arr.astype(numpy.uint8))