我正在使用pygame(1.9.0rc3,尽管这也发生在1.8.1中)来创建热图。为了构建热图,我使用了一个小的24位11x11px点PNG图像,白色背景和非常低不透明度的灰点,它完全停在边缘:
Dot image http://img442.imageshack.us/img442/465/dot.png
点周围的区域是完美的白色,#fffff,应该是。但是,当我使用pygame使用BLEND_MULT将图像多次blit到新表面时,会出现一个灰色方块,好像点背景不是完美的白色,这没有意义。
以下代码以及附带的图片可以重现这一点:
import os
import numpy
import pygame
os.environ['SDL_VIDEODRIVER'] = 'dummy'
pygame.display.init()
pygame.display.set_mode((1,1), 0, 32)
dot_image = pygame.image.load('dot.png').convert_alpha()
surf = pygame.Surface((100, 100), 0, 32)
surf.fill((255, 255, 255))
surf = surf.convert_alpha()
for i in range(50):
surf.blit(dot_image, (20, 40), None, pygame.BLEND_MULT)
for i in range(100):
surf.blit(dot_image, (60, 40), None, pygame.BLEND_MULT)
pygame.image.save(surf, 'result.png')
运行代码时,您将看到以下图像:
Resulting image after blending http://img263.imageshack.us/img263/4568/result.png
这是否有原因?我该如何解决它?
答案 0 :(得分:6)
在尝试之后,我唯一能看到的就是你100%正确。乘以255会导致每次减1。最后,我下载了pygame源代码,答案就在那里,surface.h
:
#define BLEND_MULT(sR, sG, sB, sA, dR, dG, dB, dA) \
dR = (dR && sR) ? (dR * sR) >> 8 : 0; \
dG = (dG && sG) ? (dG * sG) >> 8 : 0; \
dB = (dB && sB) ? (dB * sB) >> 8 : 0;
Pygame将多重混合实现为
new_val = old_dest * old_source / 256
而不是,这将是正确的方式,如
new_val = old_dest * old_source / 255
这可能是出于优化目的而进行的 - 比分割要快得多。由于比率255 / 256
非常接近1,所以唯一的区别是“一个一个”:你得到的值是预期值减一 - 除非你预期为零,在这种情况下结果是对的。
所以,你有这些可能性:
1
添加到所有结果值。最接近预期的结果,除了你失去零。255 * 255 == 255
(您知道我的意思),或者1
而不是添加足够的东西,而且速度更快。请注意,如果您不选择答案1,出于性能原因,您可能必须编写C扩展名而不是直接使用Python。
答案 1 :(得分:1)
在做热图时遇到这个问题,在阅读了balpha的答案之后,选择将其修正为“正确”(如果更慢)的方式。改变各种
(s * d) >> 8
到
(s * d) / 255
这需要在alphablit.c
中修补多个函数(尽管我也修补了surface.h
)。不确定这会影响性能,但对于特定的(热图)应用程序,它会产生更漂亮的图像。