2009-07-21 31 views
5

Tôi đang sử dụng pygame (1.9.0rc3, mặc dù điều này cũng xảy ra trong 1.8.1) để tạo bản đồ nhiệt. Xây dựng bản đồ nhiệt, tôi sử dụng một nhỏ, 24-bit 11x11px chấm PNG hình ảnh với một nền trắng và một opacity thấp rất chấm màu xám dừng chính xác ở các cạnh:Pygame và blitting: trắng trên trắng = xám?

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

Khu vực xung quanh chấm là màu trắng hoàn hảo, #ffffff, như nó phải là. Tuy nhiên, khi tôi sử dụng pygame để trích xuất hình ảnh nhiều lần đến một bề mặt mới bằng BLEND_MULT, một hình vuông màu xám xuất hiện, như thể chấm nền không hoàn hảo màu trắng, điều này không có ý nghĩa.

Các mã sau đây, cộng thêm bao gồm hình ảnh, có thể tái sản xuất này:

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

Khi bạn chạy mã này, bạn sẽ nhận được hình ảnh sau:

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

Có một lý do này xảy ra? Làm thế nào tôi có thể làm việc xung quanh nó?

Trả lời

6

Sau khi thử xung quanh, điều duy nhất tôi có thể thấy là bạn đúng 100%. Nhân bằng 255 kết quả trong một phép trừ của 1 - mỗi lần. Cuối cùng, tôi đã tải về mã nguồn pygame, và câu trả lời là đúng đó, trong 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 thực hiện nhân pha trộn như

new_val = old_dest * old_source/256 

và không, đó sẽ là cách chính xác, như

new_val = old_dest * old_source/255 

Điều này có thể được thực hiện cho mục đích tối ưu hóa - thay đổi bit nhanh hơn nhiều so với phân chia. Khi tỷ lệ 255/256 rất gần với một, sự khác biệt duy nhất mà điều này tạo ra là "tắt một": Giá trị bạn nhận được là giá trị kỳ vọng trừ một - ngoại trừ nếu bạn mong đợi bằng không, trong trường hợp đó kết quả là chính xác.

Vì vậy, bạn có những khả năng:

  1. Bỏ qua nó, bởi vì các off-by-one không quan trọng đối với hầu hết các mục đích.
  2. Thêm 1 vào tất cả giá trị kết quả. Gần nhất với kết quả mong đợi, ngoại trừ bạn mất số không.
  3. Nếu độ chính xác tổng thể không quan trọng, nhưng bạn cần 255 * 255 == 255 (bạn biết ý tôi là gì), ORING 1 thay vì thêm đủ và nhanh hơn.

Lưu ý rằng nếu bạn không chọn câu trả lời 1, vì lý do hiệu suất, bạn có thể phải viết phần mở rộng C thay vì sử dụng trực tiếp Python.

+0

Không chỉ hai phút trước tôi đã nhận ra cùng một điều (rằng nó "tắt bởi một"), nhưng tôi không thể tìm thấy nơi trong nguồn pygame tính toán được đặt. Vì lỗi này tạo ra sự khác biệt lớn khi nhân 255 * 255 (tôi cần nó cho bản đồ nhiệt), làm thế nào để tôi thực hiện tùy chọn # 3? Tôi không quen thuộc với C, vì vậy nếu bạn có thể chỉ cho tôi đúng hướng với việc thực hiện, bạn có thể tiết kiệm sự tỉnh táo của tôi (hoặc những gì còn lại, vào thời điểm này). –

+0

Sự thỏa hiệp tốt nhất giữa hiệu suất và tính đơn giản có lẽ sẽ được thực hiện # 2 bằng cách ADD-bliting một bề mặt tất cả (1,1,1) vào kết quả. Tuy nhiên, nếu bạn muốn đào sâu vào các phần mở rộng C, bạn có thể bắt đầu bằng cách nhìn vào cython, là một C-Python-Hybrid: http://www.cython.org. Lưu ý rằng bản thân tôi không có nhiều kinh nghiệm trong lĩnh vực đó. – balpha

+0

Ngoài ra, nếu điều này là khả thi trong trường hợp của bạn, bạn chỉ có thể thay đổi và biên dịch lại pygame chính nó. Tuy nhiên, điều đó sẽ làm cho việc phân phối chương trình của bạn khó hơn, vì bạn sẽ kết thúc với một phiên bản không chuẩn của pygame. – balpha

1

Cũng gặp sự cố này khi thực hiện bản đồ nhiệt và sau khi đọc câu trả lời của balpha, hãy chọn khắc phục sự cố "đúng" (nếu chậm hơn).Thay đổi khác nhau

(s * d) >> 8 

để

(s * d)/255 

này đòi hỏi vá chức năng nhân trong alphablit.c (mặc dù tôi vá surface.h cũng). Không chắc chắn bao nhiêu tác động này hiệu quả, nhưng đối với các ứng dụng cụ thể (heatmap), nó tạo ra nhiều hình ảnh đẹp hơn.

Các vấn đề liên quan