【问题标题】:Pygame, create grayscale from 2d numpy arrayPygame,从 2d numpy 数组创建灰度
【发布时间】:2017-04-06 23:05:52
【问题描述】:

Python 3.4,pygame==1.9.2b8

我想画灰度图。 现在,下面的代码产生蓝色,但我想在(0,255)范围内制作颜色,其中 0 - 黑色。 255-白色。 怎么可能?!

import pygame 
import numpy as np
s = 300
screen = pygame.display.set_mode((s, s))
screenarray = np.zeros((s,s))
screenarray.fill(200)
pygame.surfarray.blit_array(screen, screenarray)
pygame.display.flip()
input()
  • 事实上,我有更复杂的screenarray,其中每个元素位于 (0,65535) 期间。所以我想把它转成灰度。

非常感谢。

【问题讨论】:

  • pygame 使用颜色作为三个数字(红、绿、蓝),所以白色是 (0,0,0),黑色是 (255,255,255)

标签: python python-3.x numpy pygame pygame-surface


【解决方案1】:

PyGame 使用 24 位颜色作为三个字节 (R,G,B),因此白色是 (0,0,0),黑色是 (255,255,255)

import pygame 
import numpy as np

SIZE = 256

pygame.init()
screen = pygame.display.set_mode((SIZE, SIZE))

screenarray = np.zeros((SIZE, SIZE, 3))

for x in range(SIZE):
    screenarray[x].fill(x)

pygame.surfarray.blit_array(screen, screenarray)

pygame.display.flip()

input()

pygame.quit()

【讨论】:

    【解决方案2】:

    pygame 可以通过两种方式将整数识别为颜色:

    1. RGB 的 3 元素序列,其中每个元素的范围在 0-255 之间。
    2. 一个映射的整数值。

    如果您希望能够拥有一个数组,其中 0-255 之间的每个整数都代表一个灰色阴影,您可以使用此信息创建自己的灰度数组。您可以通过定义一个类来创建自己的数组。


    第一种方法是创建一个 numpy 数组,每个元素都是一个 3 元素序列。

    class GreyArray(object):
    
        def __init__(self, size, value=0):
            self.array = np.zeros((size[0], size[1], 3), dtype=np.uint8)
            self.array.fill(value)
    
        def fill(self, value):
            if 0 <= value <= 255:
                self.array.fill(value)
    
        def render(self, surface):
            pygame.surfarray.blit_array(surface, self.array)
    

    根据映射的整数值创建一个类可能有点抽象。我不知道这些值是如何映射的,但是通过快速测试很容易确定每个灰色阴影都以16843008 的值分隔,从0 的黑色开始。

    class GreyArray(object):
    
        def __init__(self, size, value=0):
            self.array = np.zeros(size, dtype=np.uint32)
            self.array.fill(value)
    
        def fill(self, value):
            if 0 <= value <= 255:
                self.array.fill(value * 16843008)  # 16843008 is the step between every shade of gray.
    
        def render(self, surface):
            pygame.surfarray.blit_array(surface, self.array)
    

    简短的演示。按 1-6 更改灰色阴影。

    import pygame
    import numpy as np
    pygame.init()
    
    s = 300
    screen = pygame.display.set_mode((s, s))
    
    # Put one of the class definitions here!
    
    screen_array = GreyArray(size=(s, s))
    
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_1:
                    screen_array.fill(0)
                elif event.key == pygame.K_2:
                    screen_array.fill(51)
                elif event.key == pygame.K_3:
                    screen_array.fill(102)
                elif event.key == pygame.K_4:
                    screen_array.fill(153)
                elif event.key == pygame.K_5:
                    screen_array.fill(204)
                elif event.key == pygame.K_6:
                    screen_array.fill(255)
    
        screen_array.render(screen)
        pygame.display.update()
    

    【讨论】:

    • 非常好的评论,谢谢!不幸的是,最近基于 pygame 16843008 的方法会渲染成淡黄色的东西。我真的很想知道为什么。
    【解决方案3】:

    从 python 3.6 开始,我得到了以下结果:

    display = pygame.display.set_mode((width, height))
    frame = np.array(framebuf.getData(), copy=False, dtype=np.uint8).reshape((height, width, 1))
    screenarray = np.repeat(frame, 3, axis = 2).swapaxes(0, 1)
    pygame.surfarray.blit_array(display, screenarray)
    pygame.display.flip()
    

    在这个 sn-p 中,frame 是一个 numpy 数组,使用来自framebuf.getData() 的列表进行初始化。因此,它可以是任何灰度位图,而不仅仅是此处其他示例中的常量或渐变。我们将数组重塑为目标显示尺寸。现在我们部署numpy.repeat 将每个灰度字节复制到另外两个通道中。最后,我们必须使用swapaxes 作为反转宽度和高度的最简单方法。与 numpy 正交,pygame 期望 screenarray 具有宽度维度,这使得它看起来有点按列(嗯,什么)?

    总体而言,这在 640x480 下提供了 ~80fps,这非常糟糕,但仍然比任何显式 Python 代码要好得多。我想最好的办法是在本机代码端准备 RGB 帧...

    【讨论】:

      【解决方案4】:

      在灰度图像的情况下,必须使用numpy.reshape更改数组的形状,并且必须使用numpy.repeat将灰度通道扩展为红绿蓝通道:

      cv2Image = np.repeat(cv2Image.reshape(size[1], size[0], 1), 3, axis = 2)
      

      pygame.Surface对象可以由pygame.image.frombuffer生成:

      surface = pygame.image.frombuffer(cv2Image.flatten(), size, 'RGB')
      

      以下函数将形状为 (y, x) 的numpy.array 转换为pygame.Surface 对象:

      import numpy as np
      
      def numpyGrayscaleToSurface(numpyArray):
          size = numpyArray.shape[1::-1]
          numpyArray= np.repeat(numpyArray.reshape(size[1], size[0], 1), 3, axis = 2)
          surface = pygame.image.frombuffer(numpyArray.flatten(), size, 'RGB')
          return surface.convert()
      

      另见How do I convert an OpenCV (cv2) image (BGR and BGRA) to a pygame.Surface object

      【讨论】:

        猜你喜欢
        • 2018-01-15
        • 1970-01-01
        • 2021-04-02
        • 2014-06-02
        • 1970-01-01
        • 2022-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多