2009-07-21 11 views
5

Używam pygame (1.9.0rc3, choć tak samo dzieje się w 1.8.1), aby utworzyć mapę cieplną. Aby zbudować mapę cieplną, używam małego, 24-bitowy 11x11px dot PNG z białym tłem i bardzo niskiej przezroczystości szare kropki, który zatrzymuje się dokładnie na krawędziach:Pygame i blitting: biały na białym = szary?

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

obszar wokół kropki jest idealnie biały, #ffffff, tak jak być powinien. Jednak gdy używam pygame do wielokrotnego blitowania obrazu na nową powierzchnię za pomocą BLEND_MULT, pojawia się szary kwadrat, tak jakby tło kropki nie było idealnie białe, co nie ma sensu.

następujący kod, plus zamówione obrazy, można odtworzyć to:

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

Po uruchomieniu kodu, otrzymasz następujący obraz:

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

Czy istnieje powód tego dzieje się? Jak mogę obejść to?

Odpowiedz

6

Po wypróbowaniu jedyne co mogłem zobaczyć to to, że masz 100% racji. Mnożenie przez 255 powoduje odjęcie 1 - za każdym razem. W końcu Pobrałem kod źródłowy Pygame, a odpowiedź jest tuż obok, w 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 implementuje pomnożyć mieszania jako

new_val = old_dest * old_source/256 

a nie, który byłby właściwy sposób, jako

new_val = old_dest * old_source/255 

Jest to prawdopodobnie zrobione dla celów optymalizacji - nieco przesunięcie jest dużo szybsze niż podział. Ponieważ stosunek 255/256 jest bardzo zbliżony do jednego, jedyna różnica, która to powoduje, to "off by one": Otrzymywaną wartością jest oczekiwana wartość minus jeden - z wyjątkiem sytuacji, gdy oczekiwane jest zero, w którym to przypadku wynik jest poprawny.

Tak, masz te możliwości:

  1. Zignoruj ​​go, bo się po drugim nie ma znaczenia dla większości zastosowań.
  2. Dodaj 1 do wszystkich wartości wyników. Najbliższy oczekiwanemu wynikowi, chyba że stracisz zero.
  3. Jeśli ogólna poprawność nie jest ważna, ale potrzebujesz 255 * 255 == 255 (wiesz co mam na myśli), ORing 1 zamiast dodawania wystarcza i jest szybszy.

Pamiętaj, że jeśli nie wybierzesz odpowiedzi 1, ze względu na wydajność prawdopodobnie będziesz musiał napisać rozszerzenie C zamiast bezpośrednio używać Pythona.

+0

Niecałe dwie minuty temu zdałem sobie sprawę z tego samego (że jest "wyłączony przez jednego"), ale nie mogłem znaleźć miejsca, w którym znaleziono źródło obliczeń. Ponieważ ten błąd robi ogromną różnicę, gdy pomnożymy 255 * 255 (potrzebuję go w mapach termicznych), w jaki sposób mam zamiar zastosować opcję nr 3? Wcale nie jestem zaznajomiony z C, więc gdybyś mógł wskazać mi właściwy kierunek implementacji, prawdopodobnie uratowałbyś moje zdrowie psychiczne (lub to, co zostało w tym momencie). –

+0

Najlepszy kompromis pomiędzy wydajnością i prostotą prawdopodobnie zapewniłby implementację nr 2 poprzez nałożenie ADD-bliting na powierzchnię all- (1,1,1) na wynik. Jeśli jednak chcesz zagłębić się w rozszerzenia C, możesz zacząć od spojrzenia na cython, który jest C-Python-Hybrid: http://www.cython.org. Zauważ, że ja sam nie mam dużego doświadczenia w tej dziedzinie. – balpha

+0

Ponadto, jeśli jest to możliwe w twoim przypadku, możesz po prostu zmienić i ponownie skompilować pygame. To jednak utrudniłoby dystrybucję twojego programu, ponieważ skończyłbyś z niestandardową wersją pygame. – balpha

1

Również napotkany problem z mapami termicznymi i po przeczytaniu odpowiedzi Balphy, postanowił naprawić "prawy" (jeśli wolniejszy) sposób.Zmieniać różne

(s * d) >> 8 

do

(s * d)/255 

Wymagało to łatanie funkcje rozmnażają się w alphablit.c (choć poprawione surface.h również). Nie wiesz, jak bardzo wpływa to na wydajność, ale w przypadku konkretnej aplikacji (mapa termiczna) zapewnia znacznie ładniejsze obrazy.