Пигмей и блиттинг: белый на белом = серый? - PullRequest
5 голосов
/ 21 июля 2009

Я использую pygame (1.9.0rc3, хотя это также происходит в 1.8.1), чтобы создать тепловую карту. Для построения тепловой карты я использую небольшое 24-битное PNG-изображение размером 11x11px с белым фоном и серой точкой с очень низкой непрозрачностью, которая останавливается точно по краям:

Точечное изображение 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

Есть ли причина, по которой это происходит? Как я могу обойти это?

Ответы [ 2 ]

6 голосов
/ 21 июля 2009

Попробовав, единственное, что я увидел, было то, что ты на 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 (вы понимаете, о чем я), вместо добавления достаточно ИЛИ 1, и это быстрее.

Обратите внимание, что если вы не выберете ответ 1, по соображениям производительности вам, вероятно, придется написать расширение C вместо непосредственного использования Python.

1 голос
/ 10 ноября 2009

Также столкнулся с этой проблемой, делая тепловые карты, и после прочтения ответа Бальфы решил исправить это «правильным» (если медленнее) способом. Изменить различные

(s * d) >> 8

до

(s * d) / 255 

Это потребовало исправления функций умножения в alphablit.c (хотя я также исправил surface.h). Не уверен, насколько это влияет на производительность, но для конкретного приложения (тепловая карта) он создает намного более красивые изображения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...