pygame直接修改Surface像素的alpha
Modify alpha of Surface pixels directly in pygame
我在 PyGame 中有一个 Surface。我想直接修改像素的 alpha 值。我已经尝试使用访问 alpha 值的各种方法来实现它,但它们似乎不起作用。
from screeninfo import get_monitors
import pygame, os, numpy.random, pygame.surfarray
pygame.init()
FPS = 60
CLOCK = pygame.time.Clock()
monitor_info = get_monitors()
x = 0
y = 0
width = monitor_info[0].width
height = monitor_info[0].height
if len(monitor_info) > 1:
if monitor_info[0].x < 0:
x = 0
else:
x = monitor_info[0].width
width = monitor_info[1].width
height = monitor_info[1].height
os.environ['SDL_VIDEO_WINDOW_POS'] = "{},0".format(x)
pygame.display.init()
pygame.mouse.set_visible(False)
screen_info = pygame.display.Info()
screen_size = width, height
base_screen = pygame.display.set_mode(screen_size, pygame.NOFRAME)
base_screen.fill([100, 100, 100])
board_size = (int(min(width, height)*0.75), int(min(width, height)*0.75))
surface = pygame.Surface(board_size, pygame.SRCALPHA)
surface.fill([255, 255, 255, 255])
base_screen.blit(surface, (0,0))
pygame.display.flip()
pixels = numpy.random.uniform(low=0, high=255, size=(board_size[0], board_size[1], 3))
transparency = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8')
while True:
events = pygame.event.get()
ms = CLOCK.tick(FPS)
print('\r {} '.format(ms), end='')
# pygame.surfarray.blit_array(surface, pixels)
aa = pygame.surfarray.pixels_alpha(surface)
aa = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8')
del aa
# for i in range(board_size[0]):
# for j in range(board_size[1]):
# a = surface.get_at((i,j))
# a[3] = 0
# surface.set_at((i,j), a)
base_screen.blit(surface, (0,0))
pygame.display.flip()
我在循环中尝试了这两种方法(pixels_array 和 get_at/set_at),但都不起作用——图像只是保持白色(如果我将初始 alpha 设置为 0,它会保持透明的)。有谁知道如何为 Surface 设置每像素 alpha 值?
我发现了你的问题!!看不到alpha的原因是:
a) 你首先将 surface
alpha 设置为 255
, surface.fill([255, 255, 255, 255])
b) 我相信 aa = pygame.surfarray.pixels_alpha(surface)
aa = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8')
不起作用,但是 pygame.surfarray.blit_array(surface, pixels)
确实起作用(产生颜色)但我认为它们没有任何实际的 Alpha。
c) 你需要填充 base_screen 和 THEN blit 你的表面。这是一个常见的错误,但这是主要问题。
最后,蒂姆·罗伯特 (Tim Robert) 关于 for 循环的评论,一定会让您大开眼界!
这里是重写的(没有 screeninfo
因为我目前没有那个库):
import pygame, os, numpy.random, pygame.surfarray
from random import randint
pygame.init()
FPS = 60
CLOCK = pygame.time.Clock()
x = 50
y = 50
width = 500
height = 500
os.environ['SDL_VIDEO_WINDOW_POS'] = "{},0".format(x)
#pygame.display.init(), don't actually need this
pygame.mouse.set_visible(False)
screen_info = pygame.display.Info()
screen_size = width, height
base_screen = pygame.display.set_mode(screen_size, pygame.NOFRAME)
base_screen.fill([100, 100, 100])
board_size = (int(min(width, height)*0.75), int(min(width, height)*0.75))
surface = pygame.Surface(board_size, pygame.SRCALPHA)
surface.fill([255, 0, 0]) ###could also be surface.fill([255,0,0,255]) to set the whole surface's alpha straight up if you didn't want to change each pixel later
while True:
#just so you can quit this program
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
raise SystemExit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
pygame.quit()
raise SystemExit()
ms = CLOCK.tick(FPS)
for i in range(board_size[0]):
for j in range(board_size[1]):
a = surface.get_at((i,j))
a[3] = randint(0, 128)#OR SET TO REQUIRED ALPHA VALUE
surface.set_at((i,j), a)
##################################################
base_screen.fill([100, 100, 100]) #NEED TO DO THIS
##################################################
base_screen.blit(surface, (0,0))
pygame.display.flip()
(顺便说一句,我使用红色作为第二表面颜色,因为我认为它会更突出)
编辑
正如 Eternal Ambiguity 在评论中所述,这里是 much 更快的版本,代替了 for
循环:
aa = pygame.surfarray.pixels_alpha(surface)
aa[:] = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8')
del aa
pygame.Surface.blit()
不会用源表面替换目标表面中的像素。它混合(混合)表面的像素。实际上,您在每一帧都将新表面与以前的旧表面混合。这意味着表面区域会在几毫秒内呈现出均匀的颜色。每一帧都要清屏:
while True:
# [...]
base_screen.fill((0, 0, 0))
base_screen.blit(surface, (0,0))
pygame.display.flip()
最小示例:
import pygame
pygame.init()
width, height = 200, 200
base_screen = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()
board_size = (int(min(width, height)*0.75), int(min(width, height)*0.75))
surface = pygame.Surface(board_size, pygame.SRCALPHA)
surface.fill([255, 0, 0])
for x in range(board_size[0]):
for y in range(board_size[1]):
a = surface.get_at((x, y))
a[3] = round(y / board_size[1] * 255)
surface.set_at((x, y), a)
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
base_screen.fill((100, 100, 100))
base_screen.blit(surface, surface.get_rect(center = base_screen.get_rect().center))
pygame.display.flip()
我在 PyGame 中有一个 Surface。我想直接修改像素的 alpha 值。我已经尝试使用访问 alpha 值的各种方法来实现它,但它们似乎不起作用。
from screeninfo import get_monitors
import pygame, os, numpy.random, pygame.surfarray
pygame.init()
FPS = 60
CLOCK = pygame.time.Clock()
monitor_info = get_monitors()
x = 0
y = 0
width = monitor_info[0].width
height = monitor_info[0].height
if len(monitor_info) > 1:
if monitor_info[0].x < 0:
x = 0
else:
x = monitor_info[0].width
width = monitor_info[1].width
height = monitor_info[1].height
os.environ['SDL_VIDEO_WINDOW_POS'] = "{},0".format(x)
pygame.display.init()
pygame.mouse.set_visible(False)
screen_info = pygame.display.Info()
screen_size = width, height
base_screen = pygame.display.set_mode(screen_size, pygame.NOFRAME)
base_screen.fill([100, 100, 100])
board_size = (int(min(width, height)*0.75), int(min(width, height)*0.75))
surface = pygame.Surface(board_size, pygame.SRCALPHA)
surface.fill([255, 255, 255, 255])
base_screen.blit(surface, (0,0))
pygame.display.flip()
pixels = numpy.random.uniform(low=0, high=255, size=(board_size[0], board_size[1], 3))
transparency = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8')
while True:
events = pygame.event.get()
ms = CLOCK.tick(FPS)
print('\r {} '.format(ms), end='')
# pygame.surfarray.blit_array(surface, pixels)
aa = pygame.surfarray.pixels_alpha(surface)
aa = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8')
del aa
# for i in range(board_size[0]):
# for j in range(board_size[1]):
# a = surface.get_at((i,j))
# a[3] = 0
# surface.set_at((i,j), a)
base_screen.blit(surface, (0,0))
pygame.display.flip()
我在循环中尝试了这两种方法(pixels_array 和 get_at/set_at),但都不起作用——图像只是保持白色(如果我将初始 alpha 设置为 0,它会保持透明的)。有谁知道如何为 Surface 设置每像素 alpha 值?
我发现了你的问题!!看不到alpha的原因是:
a) 你首先将 surface
alpha 设置为 255
, surface.fill([255, 255, 255, 255])
b) 我相信 aa = pygame.surfarray.pixels_alpha(surface)
aa = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8')
不起作用,但是 pygame.surfarray.blit_array(surface, pixels)
确实起作用(产生颜色)但我认为它们没有任何实际的 Alpha。
c) 你需要填充 base_screen 和 THEN blit 你的表面。这是一个常见的错误,但这是主要问题。
最后,蒂姆·罗伯特 (Tim Robert) 关于 for 循环的评论,一定会让您大开眼界!
这里是重写的(没有 screeninfo
因为我目前没有那个库):
import pygame, os, numpy.random, pygame.surfarray
from random import randint
pygame.init()
FPS = 60
CLOCK = pygame.time.Clock()
x = 50
y = 50
width = 500
height = 500
os.environ['SDL_VIDEO_WINDOW_POS'] = "{},0".format(x)
#pygame.display.init(), don't actually need this
pygame.mouse.set_visible(False)
screen_info = pygame.display.Info()
screen_size = width, height
base_screen = pygame.display.set_mode(screen_size, pygame.NOFRAME)
base_screen.fill([100, 100, 100])
board_size = (int(min(width, height)*0.75), int(min(width, height)*0.75))
surface = pygame.Surface(board_size, pygame.SRCALPHA)
surface.fill([255, 0, 0]) ###could also be surface.fill([255,0,0,255]) to set the whole surface's alpha straight up if you didn't want to change each pixel later
while True:
#just so you can quit this program
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
raise SystemExit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
pygame.quit()
raise SystemExit()
ms = CLOCK.tick(FPS)
for i in range(board_size[0]):
for j in range(board_size[1]):
a = surface.get_at((i,j))
a[3] = randint(0, 128)#OR SET TO REQUIRED ALPHA VALUE
surface.set_at((i,j), a)
##################################################
base_screen.fill([100, 100, 100]) #NEED TO DO THIS
##################################################
base_screen.blit(surface, (0,0))
pygame.display.flip()
(顺便说一句,我使用红色作为第二表面颜色,因为我认为它会更突出)
编辑
正如 Eternal Ambiguity 在评论中所述,这里是 much 更快的版本,代替了 for
循环:
aa = pygame.surfarray.pixels_alpha(surface)
aa[:] = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8')
del aa
pygame.Surface.blit()
不会用源表面替换目标表面中的像素。它混合(混合)表面的像素。实际上,您在每一帧都将新表面与以前的旧表面混合。这意味着表面区域会在几毫秒内呈现出均匀的颜色。每一帧都要清屏:
while True:
# [...]
base_screen.fill((0, 0, 0))
base_screen.blit(surface, (0,0))
pygame.display.flip()
最小示例:
import pygame
pygame.init()
width, height = 200, 200
base_screen = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()
board_size = (int(min(width, height)*0.75), int(min(width, height)*0.75))
surface = pygame.Surface(board_size, pygame.SRCALPHA)
surface.fill([255, 0, 0])
for x in range(board_size[0]):
for y in range(board_size[1]):
a = surface.get_at((x, y))
a[3] = round(y / board_size[1] * 255)
surface.set_at((x, y), a)
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
base_screen.fill((100, 100, 100))
base_screen.blit(surface, surface.get_rect(center = base_screen.get_rect().center))
pygame.display.flip()