创建像素方块并稍后显示

时间:2014-03-13 09:25:46

标签: python sdl-2

我很久以前就开始使用Python和SDL2来编写我的心理实验。因此,我的问题可能非常基本。 我想创建一个填充了两种不同颜色的随机像素的正方形,并将其显示在屏幕中间。我已经设法创建了这个像素方块并显示它,但创建它需要一秒钟。因此,我想更早地创建像素方块,即在参与者被其他东西占据的时刻,然后显示它。 我想过两次使用SDL_CreateRenderer(window,-1,0),但我无法做到。有一个非常简单的方法来解决我的问题吗?也许可以将创建的像素方块保存到文件中,然后再加载它?这就是我创建像素方块的方式:

def put_pixel(x,y, color):
      pixel = SDL_Rect(x, y,1,1)        

      if color == "orange":
          SDL_SetRenderDrawColor(sdlRenderer,255,100,0,255) 
      elif color == "blue": 
          SDL_SetRenderDrawColor(sdlRenderer,0,100,255,255)

      SDL_RenderFillRect(sdlRenderer,pixel)
      return sdlRenderer

def pixel_square(n_pixel_x,n_pixel_y, n_pixel_blue):

    seq = range(n_pixel_x*n_pixel_y) 
    random.shuffle(seq)

    lst = range(n_pixel_x*n_pixel_y)
    pos=0
    for i in range(n_pixel_x):
        for j in range(n_pixel_y):
                lst[seq[pos]] = [i,j]
                pos = pos+1 

    #create orange square   
    square_orange=SDL_Rect(MAXX/2-n_pixel_x/2,MAXY/2-n_pixel_y/2,n_pixel_x,n_pixel_y)    
    SDL_SetRenderDrawColor(sdlRenderer,255,100,0,255) #orange
    SDL_RenderFillRect(sdlRenderer,square_orange)     

    #add blue pixels
    for i in range(n_pixel_blue):
       put_pixel(x=MAXX/2-n_pixel_x/2+lst[i][0], y=MAXY/2-n_pixel_y/2+lst[i][1], color="blue")      

    return sdlRenderer  

稍后我使用

SDL_RenderPresent(sdlRenderer)

显示像素方块。

如果你能解决这个问题,我会很高兴的! 谢谢! 的Vero

1 个答案:

答案 0 :(得分:0)

由于计算和循环处理的开销,您创建映像的过程很慢。除了在这里和那里优化它们以及从其他地方预先计算,存储和加载图像之外,我建议使用Numpy动态生成图像(如果适用)。它具有开箱即用的随机分布阵列,并且针对速度进行了大量优化。

一个完整的示例可能如下所示:

import sys
import sdl2
import sdl2.ext
import numpy

SIZE_X = 400
SIZE_Y = 300

# RGB values
RED = 0xFF0000
GREEN = 0x00FF00

def pixelate():
    choices = [RED, GREEN]
    pixelarray = numpy.random.choice(choices,(SIZE_X, SIZE_Y))
    buf = pixelarray.tostring()
    # Create a software surface from the array. The depth and pitch are really
    # important here, since we use a continuous byte buffer access.
    image = sdl2.SDL_CreateRGBSurfaceFrom(buf,
                                          SIZE_X, SIZE_Y,
                                          32,   # Bit depth, we use 32-bit RGB
                                          SIZE_X, # pitch (byte size of a single scanline) - for 32 bit it is SIZE_X
                                          0xFF0000,
                                          0x00FF00,
                                          0x0000FF,
                                          0x0)
    # required to avoid loosing buf. SDL_CreateRGBSurfaceFrom() will
    # reference the byte buffer, not copy it
    image._buffer = buf
    return image

def main():
    sdl2.ext.init()

    window = sdl2.ext.Window("Pixel example", size=(800, 600))
    imgoffset = sdl2.SDL_Rect(200, 150, 0, 0)
    window.show()

    # Software rendering, we also could use hardware rending and use streaming
    # textures, but the example would become more complicated then.
    windowsurface = window.get_surface()

    running = True
    while running:
        events = sdl2.ext.get_events()
        for event in events:
            if event.type == sdl2.SDL_QUIT:
                running = False
                break
            if event.type == sdl2.SDL_MOUSEBUTTONDOWN:
                image = pixelate()
                sdl2.SDL_BlitSurface(image, None, windowsurface, imgoffset)
        window.refresh()
        sdl2.SDL_Delay(10)
    sdl2.ext.quit()
    return 0

if __name__ == "__main__":
    sys.exit(main())

最重要的部分是 pixelate()函数,它创建一个指定大小的2D数组,其中填充了传递值(您的颜色)的随机分布。 SDL2允许您从字节缓冲区创建表面(图像),因此下一步是从2D numpy阵列创建缓冲区并使用该特定缓冲区创建表面。 完成后,只需在屏幕上显示图像即可。

如果您的环境中无法使用Numpy,我会避免使用 put_pixel()方法单独绘制每个像素,因为这会导致至少一个上下文切换SDL2渲染器中的每种颜色变化(最坏情况)。相反,预先计算一个二维数组,用必要的值填充它,然后根据它创建一个软件表面缓冲区(或者再次,一个流纹理),然后在一次操作中在屏幕上进行blit。