Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

878441 Posts in 32923 Topics- by 24333 Members - Latest Member: blackarm

May 21, 2013, 10:31:46 PM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)Per-pixel read/write performance in Pygame
Pages: [1]
Print
Author Topic: Per-pixel read/write performance in Pygame  (Read 980 times)
Guillaume
Level 7
**



View Profile
« on: December 01, 2010, 07:50:44 PM »

Hey guys,

I'm trying to implement a "filter" system in my current game (written with python+pygame)- for example that makes the screen become black and white.

I blit all my surfaces to a buffer surface that I blit on the screen, so I thought: "No problem, I'll just access and modify the pixels from the buffer surface". Thing is, the 2 approaches I tried essentially killed the framerate.

The first thing I did was to use the get_at and set_at methods of the Surface class.

Code:
self.screenBuffer.lock()
for x in range(0,160):
for y in range(0,144):
color=self.screenBuffer.get_at((x,y))
color.r=color.g=color.b=int((0.1*color.r+0.79*color.g+0.11*color.b)/3)
self.screenBuffer.set_at((x,y), color)
self.screenBuffer.unlock()

This was slow, and the documentation was honest with me:

Getting and setting pixels one at a time is generally too slow to be used in a game or realtime situation. It is better to use methods which operate on many pixels at a time like with the blit, fill and draw methods - or by using surfarray/PixelArray.

So I figured I'd use a surface array:

Code:
surfArray=pygame.surfarray.pixels3d(self.screenBuffer) #load the pixels from the surface into a surface array
for x in range(0,160):
for y in range(0,144):
color=surfArray[x][y]
color[0]=color[1]=color[2]=int((color[0]*0.59+color[1]*0.3+color[2]*0.11)/3)
surfArray[x][y]=color

self.screenBuffer=pygame.surfarray.make_surface(surfArray) #transform the pixel array back to a surface

Which was even slower.

Anyone has any tips on what I could do to fix that? The documentation seems to indicate that a pixel array could do the trick, but I have the feeling that one cannot read the value of a single pixel's color from the pixel array.
Logged
BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #1 on: December 02, 2010, 12:42:23 AM »

I believe Pygame's surfarrays work with Numpy, which is a very fast way of doing certain bulk operations on arrays, including simple color operations like you have below.
Logged
eclectocrat
Level 5
*****


Most of your personality is unconscious.


View Profile WWW
« Reply #2 on: December 02, 2010, 12:52:27 AM »

Sorry, not a comprehensive answer, just thought I'd share my own experience with pygame, maybe it'll help (someone).

I wrote an isometric engine in pygame as my first python program. It was running at around 25-30 fps on a 1.6ghz netbook. It turned out to be a problem with too many temporary variables. I don't know pythons internals, but when I removed variable declaration from within loops, the engine got an order of magnitude faster. I am guessing that there needs to be some non-deterministic search for free memory when a temp variable is created (or maybe only after a gazzillion local variables are created).

I really hope that someone can provide you with a solution, but if you are so inclined, you can access pygame's SDL surfaces from within C. So with an extension or C host, you can do blazing fast image transforms, and have all the rest of your code in shiny clean garbage collected python.

Good luck!

EDIT: Whoa! Dude, pixelarray looks like just what you need! I think you can ignore my pointless answer and just try pixelarray.
Logged

I am eclectocrat.
I make Mysterious Castle, a Tactics-Roguelike (TIGSource devlog).
gwar
Level 0
***


View Profile
« Reply #3 on: December 02, 2010, 01:35:59 AM »

local variables

local variables are supposed to be slightly quicker because, something...
I have it bookmarked http://wiki.python.org/moin/PythonSpeed/PerformanceTips

just wanted to add more noise, you can also use cairo to and by default painting to a surface should be alpha blended.
http://code.activestate.com/recipes/498278-access-cairo-surface-from-numpy-and-pygame/
http://alex.matan.ca/install-cairo-wxpyton-pycairo-python-windows
Logged
eclectocrat
Level 5
*****


Most of your personality is unconscious.


View Profile WWW
« Reply #4 on: December 02, 2010, 03:27:22 AM »

Yeah, by local I meant variables were being declared inside for loops. When I declared them outside the loop, and used them inside, everything went faster.

My bad.
Logged

I am eclectocrat.
I make Mysterious Castle, a Tactics-Roguelike (TIGSource devlog).
Kylotan
Level 0
**

8177495 kylotan@hotmail.com kylotan2 worldpretending
View Profile WWW Email
« Reply #5 on: December 02, 2010, 10:47:20 AM »

You don't need that make_surface call at the end of that surfacearray example. pixels3d doesn't load the pixels from the surface into a surface array, it gives you a direct reference to the pixels, meaning you're already modifying a surface in-place.

It may be the case that writing to the screen directly (as you are in the is situation) is a bad idea since the screen buffer is often slow to access. PyGame is a wrapper for SDL, on Windows SDL is a wrapper for DirectDraw, DirectDraw is a thin layer optimised for rendering 2D graphics efficiently on ten-year-old graphics cards, and they tend to take a long time to bring pixels back from video memory to main memory. Consider instead writing to an intermediate buffer which you know is in main memory, performing your monochrome alterations there, then blitting that to the screen.

With those changes, you might find the surfacearray approach is fast enough.

Replace range with xrange - xrange is faster in some circumstances.

And after all that, maybe see if you can get away with just using one of the channels instead of performing the more accurate blend of all 3 channels, as the multiplies and divisions could be adding up.
Logged
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic