5

我在使用 pyglet 显示 numpy 数组时遇到问题。我找到了一个非常相似的主题(如何使用 pyglet 显示一个 numpy 数组?),我使用过。我想以灰度显示数组,但 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

如果我保存并加载数组,它可以工作(但速度慢得多):

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

我得到了我想要的:

i.stack.imgur.com/FCY1v.jpg

我在第一个代码示例中找不到错误:(

编辑:

非常感谢您的回答。在 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
4

4 回答 4

5

上周我一直在使用 NumPy 来生成随机纹理。我遇到了这篇文章并尝试了接受的答案。

我可以确认之前接受的答案不是正确的。

这似乎是正确的,因为您使用的是灰度图像。但是,如果您要使用彩色图像(例如 RGBA)并将 GBA 通道归零,您会发现这一点,因为您的纹理中仍然会出现绿色和蓝色。

通过使用 __str__() 你实际上是在发送垃圾而不是你真正想要的值。

我将使用我的代码来演示这一点。

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

使用上面的答案,您将执行以下操作

不要这样做!

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

如果您尝试使用代码,您将获得所有颜色,而不仅仅是红色!

改为这样做!

正确的方法是转换为 ctype GLubytes。

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

然后,您可以将其传递到您的纹理中。

# 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
    )
于 2012-08-14T02:33:03.437 回答
2

我一直在玩这个来获得一个 numpy 数组的动态视图。@Rebs 的答案有效,但是当我想在每一帧更新图像时效率低下。from_buffer经过分析,我发现 ctypes 值转换是速率限制步骤,可以通过使用ctype 类型对象的方法在 numpy 数组和 GLubyte 数组之间共享内存中的底层位来加快速度。

这是一个将在 2d numpy 数组和 pyglet 图像之间映射的类,使用 matplotlib 的颜色映射来执行此操作。如果您有一个 numpy 数组,请在其周围创建一个 ArrayView 包装器,然后在 windowon_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)

全类实现:

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()

于 2019-01-29T19:15:44.140 回答
1

根据Pyglet docs onpyglet.image,如果你想要灰度,你应该使用'L'格式代码,而不是'RGB',因为你只有一个通道。

于 2012-01-27T23:29:09.980 回答
1

我认为 pyglet 期待 uint8,你试过了吗?

IMG = ( random((X,Y)) * 255 ).astype('uint8')
于 2012-01-27T23:33:58.107 回答