Pygame 和 blitting:白底白字 = 灰色?

发布于 2024-07-27 14:28:41 字数 1117 浏览 5 评论 0原文

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

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

点周围的区域是完美的白色,#ffffff,正如它应该的那样。 然而,当我使用 pygame 使用 BLEND_MULT 将图像多次传输到新表面时,会出现一个灰色方块,就好像点背景不是完美的白色一样,这是没有意义的。

以下代码加上包含的图像可以重现此内容:

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

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

I'm using pygame (1.9.0rc3, though this also happens in 1.8.1) to create a heatmap. To build the heatmap, I use a small, 24-bit 11x11px dot PNG image with a white background and a very low-opacity grey dot that stops exactly at the edges:

Dot image http://img442.imageshack.us/img442/465/dot.png

The area around the dot is perfect white, #ffffff, as it should be. However, when I use pygame to blit the image multiple times to a new surface using BLEND_MULT, a grey square appears, as though the dot background wasn't perfect white, which doesn't make sense.

The following code, plus included images, can reproduce this:

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')

When you run the code, you will get the following image:

Resulting image after blending http://img263.imageshack.us/img263/4568/result.png

Is there a reason this happens? How can I work around it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

旧竹 2024-08-03 14:28:41

经过尝试后,我唯一能看到的是你是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 实现了乘法混合 as

new_val = old_dest * old_source / 256

和 not,这将是正确的方法,因为

new_val = old_dest * old_source / 255

这可能是完成的出于优化目的——位移比除法快得多。 由于比率 255 / 256 非常接近 1,因此唯一的区别是“相差一”:您得到的值是预期值减一 - 除非您预期为零,在这种情况下,结果是正确的。

因此,您有以下可能性:

  1. 忽略它,因为逐一对于大多数用途来说并不重要。
  2. 1 添加到所有结果值。 最接近预期结果,除了丢失零。
  3. 如果整体正确性并不重要,但您需要 255 * 255 == 255 (您知道我的意思),则 ORing 1 而不是添加就足够了,并且速度更快。

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

After trying around, the only thing I could see was that you're 100% right. Multiplication by 255 results in a subtraction of 1 -- every time. In the end, I downloaded the pygame source code, and the answer is right there, in 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 implements multiply blending as

new_val = old_dest * old_source / 256

and not, which would be the correct way, as

new_val = old_dest * old_source / 255

This is probably done for optimization purposes -- a bit shift is a lot faster than a division. As the ratio 255 / 256 is very close to one, the only difference this makes is an "off by one": The value you get is the expected value minus one -- except if you expected zero, in which case the result is correct.

So, you have these possibilities:

  1. Ignore it, because the off-by-one doesn't matter for most purposes.
  2. Add 1 to all result values. Closest to the expected result, except you lose the zero.
  3. If overall correctness is not important, but you need 255 * 255 == 255 (you know what I mean), ORing 1 instead of adding suffices, and is faster.

Note that if you don't choose answer 1, for performance reasons you'll probably have to write a C extension instead of using Python directly.

深爱不及久伴 2024-08-03 14:28:41

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

(s * d) >> 8

(s * d) / 255 

This required patching multifunctions(尽管我也修补了 surface.h)。 不确定这对性能有多大影响,但对于特定的(热图)应用程序,它会生成更漂亮的图像。

Also encountered this problem doing heatmaps and after reading balpha's answer, chose to fix it the "right" (if slower) way. Change the various

(s * d) >> 8

to

(s * d) / 255 

This required patching multiply functions in alphablit.c (though I patched surface.h as well). Not sure how much this impacts performance, but for the specific (heatmap) application, it produces much prettier images.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文