The numpy array is not displayed correctly with the piglet

I am having problems displaying a numpy array with pyglet. I found a very similar topic ( how to display a numpy array with pyglet? ) That I used. I want to display the array in shades of gray, but pyglet displays it with colors to see the image: http://i.stack.imgur.com/pL6Yr.jpg

def create(self, X,Y): IMG = random((X,Y)) * 255 self.IMG = dstack((IMG,IMG,IMG)) return self.IMG def image(self): self.img_data = self.create(X,Y).data.__str__() self.image = pyglet.image.ImageData(X,Y, 'RGB', self.img_data, pitch = -X*3) return self.image 

If I save and load the array, then it works (but it is terribly slower):

 def image(self): self.im_save=scipy.misc.toimage(self.create(X,Y),cmin=0, cmax=255) self.im_save.save('outfile.png') self.image = pyglet.image.load('outfile.png') return self.image 

And I get what I want:

i.stack.imgur.com/FCY1v.jpg

I can not find the error in the first code example :(

EDIT:

Thanks so much for your answers. With a tip from Bago, I got this to make the code work :) And really, the nfirvine suggestion is reasonable, since I want to display only the matrix in shades of gray.

 def create(self, X,Y): self.IMG = (random((X,Y)) * 255).astype('uint8') return self.IMG def image(self): self.img_data = self.create(X,Y).data.__str__() self.image = pyglet.image.ImageData(X,Y, 'L', self.img_data) return self.image 
+4
source share
4 answers

I think pyglet is expecting uint8, have you tried?

 IMG = ( random((X,Y)) * 255 ).astype('uint8') 
+1
source

I spent the last week playing using NumPy to create random textures. I stumbled upon this post and tried the accepted answers.

I can confirm that the previously accepted answer is NOT CORRECT .

Seems right because you are using gray images. But if you used a color image (like RGBA) and zero GBA channels, you would find it because you will still get the green and blue appearing in your texture.

Using __str __ (), you are actually sending garbage, not the values ​​you really want.

I will use my code to demonstrate this.

 import numpy import pyglet from pyglet.gl import * # the size of our texture dimensions = (16, 16) # we need RGBA textures # which has 4 channels format_size = 4 bytes_per_channel = 1 # populate our array with some random data data = numpy.random.random_integers( low = 0, high = 1, size = (dimensions[ 0 ] * dimensions[ 1 ], format_size) ) # convert any 1 to 255 data *= 255 # set the GB channels (from RGBA) to 0 data[ :, 1:-1 ] = 0 # ensure alpha is always 255 data[ :, 3 ] = 255 # we need to flatten the array data.shape = -1 

Using the answer above, you will do the following

DON'T DO IT!

 tex_data = data.astype('uint8').__str__() 

If you try the code, you will get all the colors, not just the red ones!

Do it instead!

The right way is to convert GLty ctype objects.

 # convert to GLubytes tex_data = (GLubyte * data.size)( *data.astype('uint8') ) 

Then you can pass this into your texture.

 # create an image # pitch is 'texture width * number of channels per element * per channel size in bytes' return pyglet.image.ImageData( dimensions[ 0 ], dimensions[ 1 ], "RGBA", tex_data, pitch = dimensions[ 1 ] * format_size * bytes_per_channel ) 
+5
source

According to Pyglet's docs on pyglet.image , if you want to get grayscale, you should use the 'L' format code, not 'RGB' , since you only have one channel.

+1
source

I played with this to get a dynamic view of the array. @Rebs answer worked, but became ineffective when I wanted to refresh the image with every frame. After profiling, I found that casting ctypes is a speed limiting step, and it can be from_buffer using the from_buffer object's from_buffer method from_buffer to split the main bits in memory between the numpy array and the GLubyte array.

Here is a class that will display between a two-dimensional array and a pyglet image using matplotlib color maps. If you have an empty array, create an ArrayView wrapper around it, and then update and drag it into the on_draw method of the window:

 my_arr = np.random.random((nx, ny)) arr_img = ArrayImage(my_arr) @window.event def on_draw(): arr_img.update() arr_img.image.blit(x, y) 

Full implementation of the class:

 import numpy as np import matplotlib.cm as cmaps from matplotlib.colors import Normalize import pyglet import pyglet.gl class ArrayImage: """Dynamic pyglet image of a 2d numpy array using matplotlib colormaps.""" def __init__(self, array, cmap=cmaps.viridis, norm=None, rescale=True): self.array = array self.cmap = cmap if norm is None: norm = Normalize() self.norm = norm self.rescale = rescale self._array_normed = np.zeros(array.shape+(4,), dtype=np.uint8) # this line below was the bottleneck... # we have removed it by setting the _tex_data array to share the buffer # of the normalised data _array_normed # self._tex_data = (pyglet.gl.GLubyte * self._array_normed_data.size)( *self._array_normed_data ) self._tex_data = (pyglet.gl.GLubyte * self._array_normed.size).from_buffer(self._array_normed) self._update_array() format_size = 4 bytes_per_channel = 1 self.pitch = array.shape[1] * format_size * bytes_per_channel self.image = pyglet.image.ImageData(array.shape[0], array.shape[1], "RGBA", self._tex_data) self._update_image() def set_array(self, data): self.array = data self.update() def _update_array(self): if self.rescale: self.norm.autoscale(self.array) self._array_normed[:] = self.cmap(self.norm(self.array), bytes=True) # don't need the below any more as _tex_data points to _array_normed memory # self._tex_data[:] = self._array_normed def _update_image(self): self.image.set_data("RGBA", self.pitch, self._tex_data) def update(self): self._update_array() self._update_image() 
0
source

Source: https://habr.com/ru/post/1393381/


All Articles