0

I would like to be able to display a PIL image object created from a numpy array of 8 bit integers (essentially just a grayscale image) using pygame, but have been running into several errors in the process. Referring to this post, I tried using this function:

def pilImageToSurface(pilImage):
    return pygame.image.fromstring(
        pilImage.tobytes(), pilImage.size,pilImage.mode)

to take my PIL image object (created from a numpy array with datatype np.uint8) and convert it to a pygame surface, but it would return the error

ValueError: Unrecognized type of format

I tried troubleshooting this by printing out pilImage.mode which returned 'L'. simply replacing pilImage.mode with 'L' in the function returned the same error. When I tried the format 'P', it simply displayed a solid gray image. What can I do to rectify this? here is an example of what I tried:

import numpy as np
from PIL import Image
import pygame
#initiating pygame and displaying a blank image to the screen
pygame.init()
white = (255, 255, 255)
X = 1920
Y = 1080
display_surface = pygame.display.set_mode((X, Y ))
pygame.display.set_caption('Image')
display_surface.fill(white)
#make PIL image object from a numpy array
imagelist = ((0,1,2,3),(255,254,253,252),(100,101,102,103)) #example array
imagearray = np.array(imagelist,dtype = np.uint8)
imagedata = Image.fromarray(imagearray)
def pilImageToSurface(pilImage):
    return pygame.image.fromstring(
        pilImage.tobytes(), pilImage.size,pilImage.mode)
pygameimage = pilImageToSurface(imagedata)
display_surface.blit(pygame_image, (0, 0)) #sends image to the display
pygame.display.update()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
JBowers
  • 35
  • 3
  • Why are you trying to convert the numpy array to a PIL image and the PLI image to a pygame.Surface? The array can be directly loaded into a Surface. Anyway, what is the size of the image? 1x3? – Rabbid76 Jun 14 '22 at 19:55
  • I wasn't aware that the array could be loaded as a surface. How would one do that? the actual size of the image that I need is 1920x1080, I was just using that array as an example. – JBowers Jun 14 '22 at 20:01
  • You have to specify the size somewhere. PLI and pygame cannot guess the size of the image. – Rabbid76 Jun 14 '22 at 20:03

1 Answers1

2

You don't need to load the numpy array into a PLI image and that image into a pygame.Surface. A numpy array can be loaded directly into a pygame.Surface using pygame.image.frombuffer:

imagelist = ((0,1,2,3), (255,254,253,252), (100,101,102,103))
imagearray = np.array(imagelist,dtype = np.uint8)
pygame_surface = pygame.image.frombuffer(imagearray.flatten(), (3, 1), 'RGBA')
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • Thank you for your response. I tried this with an array size (1080,1920) and used the function `pygame_surface = pygame.image.frombuffer(imagearray.flatten(),(1080,1920),'RGBA')` and recieved an error, "ValueError: Buffer length does not equal format and resolution size". why might this be occurring? – JBowers Jun 14 '22 at 20:32
  • @JBowers Yes of course, You have to create an array with 1080*1920*4 bytes. Your array has just 12 bytes. You can create an array with zeros: `imagearray = np.zeros(shape = (1080, 1920, 4), dtype = np.uint8)`. – Rabbid76 Jun 14 '22 at 20:35