I'm trying to make a special kind of grating called a Gabor patch, an example of which can be found at the bottom of this tutorial whose code I ported to python.
Using matplotlib's imshow
function, I obtain the following patch.
While the coloring is different, I suspect that this has to do with how matplotlib displays numerical values. In essence, this image is a 2D, 100-by-100 pixel array containing values from -1.0
to 1.0
(inclusive). If anybody would like to try manipulating the array in question, I've saved it as a pickle object here.
My question is as follows: How can I transfer this array to a pygame surface while ensuring that the following conditions are met?
1.9.1release
. For some inexplicable reason, I can't find a way to install 1.9.2
on my OS (Ubuntu 13.04). There appear to be no PPAs and pygame is evidently not on PIP.Thank you very much in advance, and please let me know if I can provide additional information!
Edit
Regarding @Veedrac's solution (which is remarkably similar to my own), here is what my patch looks like when using the grayscale colormap in matplotlib's imshow
. This is what I would like to have:
from matplotlib.pyplot import *
import matplotlib.cm as cm
figure()
imshow(g, cm=cm.Greys_r)
show()
import numpy
import pickle
import pygame
surface = pygame.Surface((100, 100))
Get the pixels, convert to RGBA. Using Joe Kington's reminder that the data ranges from -1 to 1:
base = (pickle.load(open("g.pickle"))+1)/2 * 255
base = base[..., numpy.newaxis].repeat(4, -1).astype("uint8")
Copy the data across
numpy_surface = numpy.frombuffer(surface.get_buffer())
numpy_surface[...] = numpy.frombuffer(base)
del numpy_surface
Show it with:
screen = pygame.display.set_mode((100, 100))
screen.blit(surface, (0, 0))
pygame.display.flip()
and you get
And simplified, once again thanks to Joe Kington's input, using make_surface
:
import numpy
import pickle
import pygame
base = (pickle.load(open("g.pickle"))+1) * 128
base = base[..., None].repeat(3, -1).astype("uint8")
surface = pygame.surfarray.make_surface(base)
screen = pygame.display.set_mode((100, 100))
screen.blit(surface, (0, 0))
pygame.display.flip()
The base[..., None]
is normally spelt base[..., numpy.newaxis]
, but seeing as that was the only instance of numpy
I just "expanded the constant" so as to not need numpy
. It didn't work, though, as the code breaks if you don't import numpy
with a IndexError: bytes to write exceed buffer size
. Thanks, numpy
.
The ...
means "the whole of all of the axis before this point", so you can replace [3:2]
, [:, 3:2]
and [:, :, :, 3:2]
with [..., 3:2]
. In fact, ...
was introduced to Python for this very reason.
The None
, or numpy.newaxis
, slices a new axis (duh). This will transform [a, b, c]
into [[a], [b], [c]]
, for example. This is needed because we then repeat
along this new axis.
Basically, looking at one row, we have
114, 202, 143, ...
and we want
[114, 114, 114], [202, 202, 202], [143, 143, 143], ...
so our [..., None]
got us to
[114], [202], [143], ...
and we just repeat
3
times in axis -1
. Axis -1
is, of course, the last axis, which is the numpy.newaxis
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With