5

我正在使用 pygame(1.9.0rc3,虽然这也发生在 1.8.1)来创建热图。为了构建热图,我使用了一个小的 24 位 11x11px 点 PNG 图像,具有白色背景和一个非常低不透明度的灰色点,它正好停在边缘:

点图 http://img442.imageshack.us/img442/465/dot.png

点周围的区域是完美的白色,#ffffff,应该是这样。但是,当我使用 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')

运行代码时,您将获得以下图像:

混合后生成的图像 http://img263.imageshack.us/img263/4568/result.png

发生这种情况有原因吗?我该如何解决它?

4

2 回答 2

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. 忽略它,因为对大多数目的来说,一个接一个并不重要。
  2. 添加1到所有结果值。最接近预期的结果,除了你输了零。
  3. 如果整体正确性并不重要,但您需要255 * 255 == 255(您知道我的意思),使用 ORing1而不是添加就足够了,而且速度更快。

请注意,如果您不选择答案 1,出于性能原因,您可能必须编写 C 扩展而不是直接使用 Python。

于 2009-07-21T07:37:34.490 回答
1

在做热图时也遇到了这个问题,在阅读了 balpha 的答案后,选择以“正确”(如果更慢)的方式修复它。改变各种

(s * d) >> 8

(s * d) / 255 

这需要修补乘法函数alphablit.c(尽管我也修补surface.h了)。不确定这对性能有多大影响,但对于特定的(热图)应用程序,它会产生更漂亮的图像。

于 2009-11-10T19:38:30.110 回答