Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何从float32的numpy数组创建pygame曲面?_Python_Pygame_Pygame Surface - Fatal编程技术网

Python 如何从float32的numpy数组创建pygame曲面?

Python 如何从float32的numpy数组创建pygame曲面?,python,pygame,pygame-surface,Python,Pygame,Pygame Surface,我有一段代码可以使用 my_surface = pygame.image.load('some_image.png') 这将返回一个pygame曲面。我希望在其他任何地方都使用相同的代码,而是传入一个numpy数组。(实际上,我将有一个if语句来确定我们是否有一个数组或一个图像的路径。在这两种情况下,函数都必须返回相同类型的对象,即pygame曲面。使用上述代码它已经可以工作了。现在,如果脚本使用不同,我必须添加生成相同对象的第二种方法。)我试过使用 my_surface = pygame.p

我有一段代码可以使用

my_surface = pygame.image.load('some_image.png')
这将返回一个pygame曲面。我希望在其他任何地方都使用相同的代码,而是传入一个numpy数组。(实际上,我将有一个if语句来确定我们是否有一个数组或一个图像的路径。在这两种情况下,函数都必须返回相同类型的对象,即pygame曲面。使用上述代码它已经可以工作了。现在,如果脚本使用不同,我必须添加生成相同对象的第二种方法。)我试过使用

my_surface = pygame.pixelcopy.make_surface(my_array)
但问题是这个函数需要一个整数数组。我的数组是一个float32。我可以像这样通过数组来强制它通过

(my_array*10000).astype(int)

但当我稍后显示它时,它看起来像垃圾(想象一下我的惊讶)。所以我的问题是,我们如何从一个小浮点数数组中优雅地创建pygame曲面?

将数据范围转换为范围[0-255],数据大小必须是
mxn
mxnx3

pygame.init()
display = pygame.display.set_mode((350, 350))
x = np.arange(0, 300)
y = np.arange(0, 300)
X, Y = np.meshgrid(x, y)
Z = X + Y
Z = 255*Z/Z.max()
surf = pygame.surfarray.make_surface(Z)

running = True

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    display.blit(surf, (0, 0))
    pygame.display.update()
pygame.quit()

如果需要灰度显示,请执行以下操作:

import pygame
import numpy as np


def gray(im):
    im = 255 * (im / im.max())
    w, h = im.shape
    ret = np.empty((w, h, 3), dtype=np.uint8)
    ret[:, :, 2] = ret[:, :, 1] = ret[:, :, 0] = im
    return ret

pygame.init()
display = pygame.display.set_mode((350, 350))
x = np.arange(0, 300)
y = np.arange(0, 300)
X, Y = np.meshgrid(x, y)
Z = X + Y
Z = 255 * Z / Z.max()
Z = gray(Z)
surf = pygame.surfarray.make_surface(Z)

running = True

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    display.blit(surf, (0, 0))
    pygame.display.update()
pygame.quit()

为了简单起见,假设您只有值[0,1],否则最好将值截断到固定范围,以便通过某些浮点值(例如0,5)始终具有相同的颜色输出。
我将以简单的水平渐变作为输入示例:

W = 300
H = 200
# generate simple gradient in float
F0 = numpy.linspace(0, 1, num = W)
F = numpy.tile(F0, (H, 1))
现在有两种方法来展示它。在这种情况下,我可能会在8位曲面上显示它。在这种情况下,您将需要以下内容以Pygame格式定义调色板:

def make_palette (C1, C2):
    palR = numpy.linspace(C1[0], C2[0], num = 256, dtype = "uint8")
    palG = numpy.linspace(C1[1], C2[1], num = 256, dtype = "uint8")
    palB = numpy.linspace(C1[2], C2[2], num = 256, dtype = "uint8")
    return zip(palR,palG,palB)
要将数据从阵列复制到曲面,请执行以下操作:

def put_arr(Dest, Src):                 
    buf = Dest.get_buffer()
    buf.write(Src.tostring(), 0)
现在,在程序开始时,初始化与阵列和应用调色板大小相同的曲面:

I_surf = pygame.Surface((W, H), 0, 8)           # Pygame surface 
C1 = (0,0,250)
C2 = (250,0,0)
palRGB = make_palette (C1, C2)
I_surf.set_palette(palRGB)
在主循环中,您有如下内容:

I = numpy.rint( F*255 ).astype("uint8")
put_arr(I_surf, I)
...
DISPLAY.blit(I_surf, (100, 100))
注意数组和曲面的类型,在这种情况下它们都必须是8位。
如果一切正常,您必须在窗口中看到:


这是对eyllanesc答案的补充,因为我发现该答案的示例很有用,但如果您想更新图像,可以稍微优化一下

主要的优化是使用8位数组,使用
surfarray.blit_数组
而不是
blit
display.flip
而不是
display.update
。(后两者要求显示器和阵列的大小相同。)

然而,差别并不大——下面的代码在没有优化的情况下让我获得了约15 fps的速度,在优化的情况下获得了20-21 fps的速度。一个基于OpenGL的方法会快得多,但我不知道一个方便的库

import pygame
import numpy as np
from pygame import surfarray

from timeit import default_timer as timer

pygame.init()

w = 1000
h = 800

display = pygame.display.set_mode((w, h))

img = np.zeros((w,h,3),dtype=np.uint8)


init_time = timer()
frames_displayed = 0

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # updating the image
    for i in range(100):
        img[np.random.randint(w),np.random.randint(h)] = np.random.randint(255,size=3,dtype=np.uint8)

    surfarray.blit_array(display, img)
    pygame.display.flip()

    frames_displayed+=1


print("average frame rate:", frames_displayed/(timer()-init_time), "fps")

pygame.quit()

假设您有一个OpenCV图像(这是一个Numpy ndarray)。要加载pygame,我必须执行以下操作:

# I suppose that the image source is a camera of something else, so we already have it as a numpy array.
# Convert the numpy image into a pygame.Surface
pygame_img = pygame.image.frombuffer(your_image.tostring(), your_image.shape[1::-1], "RGB")
your_screen.blit(pygame_img, (pos_x, pos_y))

pygame可能期望像素为单值
0-255
或元组
(0-255,0-255,0-255)
。如果使用不同的值,则可以将它们四舍五入到
0-255
@furas Yes。make_曲面函数的期望值还不是很清楚。所有文档都说“创建一个与数组的数据和格式最相似的新曲面。数组可以是二维或三维的,具有任意大小的整数值。”如果有机会,我将尝试将数组缩放到0-255,并查看make_Surface的反应。不过,似乎应该有一种更直接的方法,我只是不知道,类似于imshow()如何在数组上工作。有一个函数可以将surface转换为array-也许可以尝试一下,看看你得到了什么数组,你就会看到pygame使用了什么数组。我认为你应该提供有关float32数组中的内容的信息,即每个浮点值代表什么以及它有什么形状。否则,很难猜测您想要实现什么。@MikhailV它只是一个2D数字数组,通常范围为0-1,但不完全是(我看到了一些负值)。这些值与入射到探测器上的电子数加上散粒噪声和可能的其他杂散信号(如X射线)成正比。目标是生成一个表示数组的pygame曲面,类似于cv2.imshow(my_array)如何毫无怨言地工作。之后,屏幕上会出现鼠标交互界面。这就像是一种魅力!看起来make_surface使用mxnx3来区分存储在三维空间中的RGB值?然后在gray()函数中将它们设置为相同的值,以“强制”使曲面显示为灰度。我得承认,那太聪明了!你不仅解决了把数组放到一个表面上,而且还解决了把它变成灰度的问题。在pygame中读取事件很重要,如果没有,你可以在会话之间获得空白/灰色屏幕。只要阅读,如果你没有使用它们,就不要对它们做任何事情。换句话说,始终包括以下内容:“对于pygame.event.get()中的事件: