[英]numpy array is shown incorrect with pyglet
I have problems with displaying a numpy array with pyglet. 我在使用pyglet显示numpy数组时遇到问题。 I have found a very similar topic ( how to display a numpy array with pyglet? ) that I used.
我找到了一个非常相似的主题( 如何显示带有pyglet的numpy数组? )。 I want to display the array in greyscale, but pyglet displays it with colours see the image: http://i.stack.imgur.com/pL6Yr.jpg
我想以灰度显示数组,但是pyglet用颜色显示它看到图像: 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 instead it works (but it is horrobly 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 wanted: 我得到了我想要的东西:
i.stack.imgur.com/FCY1v.jpg i.stack.imgur.com/FCY1v.jpg
I can't find the mistake in the first code example :( 我在第一个代码示例中找不到错误:(
EDIT: 编辑:
Many thanks for your answers. 非常感谢你的回答。 With the hint from Bago I got this to code to work :) And indeed nfirvine suggestion is reasonable, since I only want to display the matrix in greyscale.
有了Bago的提示我得到了这个代码工作:)确实nfirvine的建议是合理的,因为我只想在灰度显示矩阵。
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
I've spent the last week playing around with using NumPy to generate random textures. 我花了最后一周玩NumPy来生成随机纹理。 I came across this post and tried the accepted answers.
我遇到了这篇文章并尝试了接受的答案。
I can confirm that the previously accepted answer is NOT CORRECT . 我可以确认之前接受的答案是不正确的 。
It seems correct because you are using grey-scale images. 这似乎是正确的,因为您使用的是灰度图像。 But if you were to use a colour image (RGBA for example) and zero the GBA channels you would have discovered this because you would still be getting green and blue showing up in your texture.
但是如果你要使用彩色图像(例如RGBA)并将GBA通道归零,你会发现这一点,因为你的纹理中仍然会出现绿色和蓝色。
By using __str__() you are actually sending garbage and not the values you really want. 通过使用__str __(),您实际上是在发送垃圾而不是您真正想要的值。
I'll 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's 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 would do the following 使用上面的答案,您将执行以下操作
tex_data = data.astype('uint8').__str__()
If you try the code out, you will get all colours, not just red! 如果您尝试使用代码,您将获得所有颜色,而不仅仅是红色!
The proper way is to convert to the ctype GLubytes. 正确的方法是转换为ctype GLubytes。
# convert to GLubytes
tex_data = (GLubyte * data.size)( *data.astype('uint8') )
You can then 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
)
I've been playing with this to get a dynamic view of a numpy array. 我一直在玩这个以获得一个numpy数组的动态视图。 The answer by @Rebs worked, but became inefficient when I wanted to update the image at every frame.
@Rebs的答案有效,但当我想在每一帧更新图像时效率低下。 After profiling, I found that the ctypes value casting was the rate limiting step, and could be sped up by instead using the
from_buffer
method of the ctype type object to share the underlying bits in memory between the numpy array and the GLubyte array. 在分析之后,我发现ctypes值转换是速率限制步骤,并且可以通过使用ctype类型对象的
from_buffer
方法来共享numpy数组和GLubyte数组之间的内存中的基础位来加速。
Here is a class that will map between a 2d numpy array and a pyglet image, using matplotlib's colour maps to do so. 这是一个将在2d numpy数组和pyglet图像之间进行映射的类,使用matplotlib的颜色映射来实现。 If you have a numpy array, create an ArrayView wrapper around it and then update and blit it in the window
on_draw
method: 如果你有一个numpy数组,在它周围创建一个ArrayView包装器,然后在窗口
on_draw
方法中更新并blit它:
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 class implementation: 全班实施:
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()
根据pyglet.image
上的Pyglet文档 ,如果你想要灰度,你应该使用'L'
格式代码,而不是'RGB'
,因为你只有一个通道。
我认为pyglet期待uint8,你试过吗?
IMG = ( random((X,Y)) * 255 ).astype('uint8')
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.