如何优化Pygame中反色掩码代码,提升大尺寸掩码运行效率?
优化特定区域图像反色代码的性能问题
我编写了一个测试函数,可在特定区域和形状内实现图像反色,且支持调整掩码的位置与尺寸。但存在问题:掩码尺寸越大,其移动或放大时运行速度越慢。我尝试过缓存结果、使用numpy数组、检查已修改像素等方法,但均无效果,请问有什么解决方案可加速代码运行?
原代码
import pygame fps = pygame.time.Clock() pygame.init() pygame.event.set_allowed([pygame.QUIT]) # 声明必要变量 image = pygame.image.load('...\\image.png') org_mask_inversion = pygame.image.load('...\\mask_inversion.png') ix, iy = 0, 0 size_x, size_y = 100, 100 current_ix, current_iy = ix, iy current_size_x, current_size_y = size_x, size_y screen = pygame.display.set_mode([960, 720]) mask_inversion = pygame.transform.scale(org_mask_inversion, (size_x, size_y)) image2 = image # 反色函数 def inversion_of_color(r, g, b): return [255 - r, 255 - g, 255 - b] # 区域反色函数 def inversion_of_surface(surface, sx, sy): # 创建与掩码尺寸相同的带透明通道的Surface inverted_surface = pygame.surface.Surface(mask_inversion.get_size(), pygame.SRCALPHA) # 遍历掩码的每个像素 for x in range(mask_inversion.get_width()): for y in range(mask_inversion.get_height()): # 获取掩码像素颜色 m_color = mask_inversion.get_at((x, y)) # 判断是否为绿色像素 if m_color.g == 255: # 检查是否超出屏幕范围 if 0 <= sx + x <= screen.get_width() - 1 and 0 <= sy + y <= screen.get_height() - 1: # 获取原图对应像素颜色 color = surface.get_at((x + sx, y + sy)) # 反色并设置到新Surface inverted_color = inversion_of_color(color.r, color.g, color.b) inverted_surface.set_at((x, y), inverted_color) return inverted_surface running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False fps.tick(60) keys = pygame.key.get_pressed() pygame.display.set_caption(f'Inverted Image {round(fps.get_fps())} x:{ix} y:{iy}') # 移动掩码位置 if keys[pygame.K_LEFT]: ix -= 6 elif keys[pygame.K_RIGHT]: ix += 6 if keys[pygame.K_UP]: iy -= 6 elif keys[pygame.K_DOWN]: iy += 6 # 调整掩码尺寸 if keys[pygame.K_a]: size_x -= 6 size_y -= 6 mask_inversion = pygame.transform.scale(org_mask_inversion, (size_x, size_y)) elif keys[pygame.K_d]: size_x += 6 size_y += 6 mask_inversion = pygame.transform.scale(org_mask_inversion, (size_x, size_y)) # 当掩码位置或尺寸变化时重新生成反色图 if current_ix != ix or current_iy != iy or current_size_x != size_y or current_size_x != size_x: image2 = inversion_of_surface(image, ix, iy) current_ix, current_iy = ix, iy current_size_x, current_size_y = size_x, size_y screen.blit(image, (0, 0)) screen.blit(image2, (ix, iy)) pygame.display.update() pygame.quit()
掩码图片

性能优化方案
1. 替换单像素操作:使用Pygame批量像素处理
原代码中get_at()和set_at()是单像素操作,循环遍历数千个像素时性能极差。改用pygame.PixelArray实现批量处理:
def inversion_of_surface(surface, sx, sy): mask_size = mask_inversion.get_size() inverted_surface = pygame.Surface(mask_size, pygame.SRCALPHA) # 创建像素数组,避免单像素操作 surf_array = pygame.PixelArray(surface) mask_array = pygame.PixelArray(mask_inversion) inv_array = pygame.PixelArray(inverted_surface) # 计算有效区域,避免超出屏幕范围的无效计算 min_x = max(0, -sx) max_x = min(mask_size[0], screen.get_width() - sx) min_y = max(0, -sy) max_y = min(mask_size[1], screen.get_height() - sy) # 遍历有效区域像素 for x in range(min_x, max_x): for y in range(min_y, max_y): mask_pixel = mask_array[x, y] # 提取绿色通道值 g = (mask_pixel >> 8) & 0xFF if g == 255: # 获取原图像素并反色 orig_pixel = surf_array[sx + x, sy + y] r = (orig_pixel >> 16) & 0xFF g_orig = (orig_pixel >> 8) & 0xFF b = orig_pixel & 0xFF inv_pixel = ((255 - r) << 16) | ((255 - g_orig) << 8) | (255 - b) inv_array[x, y] = inv_pixel # 释放像素数组,避免内存泄漏 del surf_array, mask_array, inv_array return inverted_surface
2. 利用Pygame混合模式实现快速反色
不需要手动遍历像素,直接用blit混合模式实现反色,再用掩码遮罩:
# 提前生成全白反色模板(仅需初始化一次) inversion_template = pygame.Surface(image.get_size(), pygame.SRCALPHA) inversion_template.fill((255,255,255)) def inversion_of_surface(surface, sx, sy): mask_size = mask_inversion.get_size() temp_surf = pygame.Surface(mask_size, pygame.SRCALPHA) # 计算原图中需要反色的有效区域 source_rect = pygame.Rect(sx, sy, mask_size[0], mask_size[1]) source_rect.clamp_ip(surface.get_rect()) # 截取原图区域并反色(BLEND_RGB_SUB等价于255-原像素值) temp_surf.blit(surface, (-source_rect.x + sx, -source_rect.y + sy), source_rect) temp_surf.blit(inversion_template, (0,0), special_flags=pygame.BLEND_RGB_SUB) # 用掩码过滤,只保留绿色区域的反色 temp_surf.blit(mask_inversion, (0,0), special_flags=pygame.BLEND_RGBA_MULT) return temp_surf
3. 预处理掩码为Alpha遮罩
提前将绿色掩码转换为Alpha通道遮罩,避免每次判断绿色像素:
# 初始化时预处理掩码 def preprocess_mask(mask_surface): alpha_mask = mask_surface.copy() alpha_array = pygame.PixelArray(alpha_mask) for x in range(alpha_mask.get_width()): for y in range(alpha_mask.get_height()): pixel = alpha_array[x,y] g = (pixel >> 8) & 0xFF # 绿色像素设为完全不透明,其他透明 alpha = 255 if g ==255 else 0 alpha_array[x,y] = (255 << 24) | (255 <<16) | (255 <<8) | alpha del alpha_array return alpha_mask # 替换原掩码初始化逻辑 org_mask_inversion = pygame.image.load('...\\mask_inversion.png') org_alpha_mask = preprocess_mask(org_mask_inversion) mask_inversion = pygame.transform.scale(org_alpha_mask, (size_x, size_y))
4. 减少不必要的重计算
- 仅当掩码尺寸变化时,重新生成掩码和反色Surface
- 掩码位置变化时,直接偏移绘制位置,无需重新计算像素(尺寸不变时)
内容的提问来源于stack exchange,提问作者Ketoketo
相关产品推荐
相关产品推荐

