Marlin Rowley wrote:
Hey Gary!
Please keep such discussions on the public python-list -- not personal
e-mail.
Scroll down for an answer to your latest question.
Here's what I have that renders fine but I see some optimization that
can be done (as you mentioned):
# Tile Generation
# This is where all the drawing to the client window
# will happen.
def generateTile( txl, tyl, tileWidth, tileHeight, clientWindow ):
# make rgba (8-bit) data structure and zero it out.
rgb = zeros( tileWidth*tileHeight*3, UnsignedInt8 )
alpha = zeros( tileWidth*tileHeight*3, UnsignedInt8 )
#print 'tileWidth: %s' % tileWidth
#print 'tileHeight: %s' % tileHeight
# for each pixel in the tile
# we must invert the rendering of each
# tile for wxPython's Bitmap support.
for y in range( (tileHeight-1),-1,-1 ):
for color in range(4):
# read per scanline
pixelComp = clientWindow.fileIO.read(4*tileWidth) <<<<
HERE'S YOUR OPTIMIZATION!!
for x in range(tileWidth):
# mental ray streams RGBA components across the width
# of every tile. so it first does all the r's,
# then all the g's, then all the b's, etc.. across
# the width.. Then it streams the second row, etc..
# However, wxPython Bitmap class accepts an array of
# tuples or just a byte order of RGBARGBARGBA, etc..
# so we convert, keeping track of an offset.
if color < 3:
index = (3*(y*tileWidth+x))+color
else:
index = (3*(y*tileWidth+x))
# RGBA_FP
if clientWindow.pixelCode == 13:
# unpack the pixel
#fourbytes = pixelComp[:4]
#pixelComp = pixelComp[4:]
buffer = unpack("!f", pixelComp[4*x:4*x+4])
<<<<<<<<<<<<<<<<<< YOUR OPTIMIZATION!!
# convert from 32-bit to 8-bit precision
gamma = clientWindow.gamma
if gamma == 1.0:
pixel = int(255 * buffer[0] + 0.5)
pixel = clamp(pixel,0,255)
if color == 3:
alpha[index+0] = alpha[index+1] =
alpha[index+2] = pixel
else:
rgb[index] = pixel
else:
pixel = int(buffer[0] * GAMMA_BIT_PRECISION + 0.5)
pixel = clamp(pixel,0,GAMMA_BIT_PRECISION-1)
# set the color and alpha
if color == 3:
alpha[index+0] = alpha[index+1] =
alpha[index+2] = clientWindow.frame.gammaTable[pixel]
else:
rgb[index] =
clientWindow.frame.gammaTable[pixel]
# ...
# create an empty rgb and alpha tile
tileRGB = wx.BitmapFromBuffer( tileWidth, tileHeight, rgb )
tileAlpha = wx.BitmapFromBuffer( tileWidth, tileHeight, alpha )
# set up main device to render to the current
# buffers
dc = wx.BufferedDC( None,clientWindow.colorBuffer )
dca = wx.BufferedDC( None,clientWindow.alphaBuffer )
# draw tiles
dc.DrawBitmap( tileRGB, txl, (clientWindow.height-tileHeight)-tyl )
dca.DrawBitmap( tileAlpha, txl, (clientWindow.height-tileHeight)-tyl )
I'm no python expert (as you can tell), but I'm trying.. :)
I started to re-write this function but I'm confused on how to do:
> Reshape the array into a 3D array (i.e., a rectangular array of RGBA
> values)
this without using a for loop.
Yes, easily. No Python loops (although plenty of C-level loops.) (I
think you are using Numeric -- a ancient predecessor of numpy. However,
I think these operations work in Numeric.)
Again I create a small test case. The values will be in the order
rrrrggggbbbb to start with, and rgbrgbrgbrgb afterwards.
Create a test array and examine it:
>>> a = numpy.frombuffer('rrrrggggbbbb', dtype='S1')
>>> a
array(['r', 'r', 'r', 'r', 'g', 'g', 'g', 'g', 'b', 'b', 'b', 'b'],
dtype='|S1')
Isolate each color component (here height*width = 4)
>>> a.shape = (3,4)
>>> a
array([['r', 'r', 'r', 'r'],
['g', 'g', 'g', 'g'],
['b', 'b', 'b', 'b']],
dtype='|S1')
Transpose it. (This creates a new array by copying efficiently.)
>>> b = a.transpose()
>>> b
array([['r', 'g', 'b'],
['r', 'g', 'b'],
['r', 'g', 'b'],
['r', 'g', 'b']],
dtype='|S1')
Reset it's shape to be a width*height array of rgb's.
>>> b.shape = (2,2,3)
>>> b
array([[['r', 'g', 'b'],
['r', 'g', 'b']],
[['r', 'g', 'b'],
['r', 'g', 'b']]],
dtype='|S1')
Put it out in byte array form:
>>> b.tostring()
'rgbrgbrgbrgb'
Done.
Gary Herron
-M
> Date: Thu, 15 May 2008 13:46:06 -0700
> From: [EMAIL PROTECTED]
> CC: python-list@python.org
> Subject: Re: How do I use the unpack function?
>
> Marlin Rowley wrote:
> > Gary,
> >
> > I'm getting streaming tile data from a renderer in order to allow the
> > user to see the rendering of tiles in real-time to create the total
> > image. I'm NOT reading an entire image scanline-by-scanline. The
> > renderer streams in a series of floats (for each tile) and I build
> > this tile up from each individual color component passed in. I then
> > convert it to a small bitmap and blit() it to the window that will
> > eventually make up my entire image. I'm just wanting to make the
> > process as fast as the renderer can render the tiles. I've noticed on
> > scenes that aren't very complex for the renderer that my python
script
> > is spending most of it's time drawing while the renderer is already
> > done. What you've given me has sped up the drawing a lot, but I'm
> > hungry for more optimization!
> >
> > There is no file format to be read. The data is raw bytes and can be
> > any format.
>
> You are misinterpreting what I mean by a format. All data is a string
> of bytes, and interpreting that string of bytes to have some particular
> form is applying a format to it. Your particular format is: each 4
> bytes represents a float, and a string of such floats give the RGBA
> values for a rectangle (of some size) of pixels. I doubt that you are
> the first ever to use that particular format to encode an image, but I
> also don't believe it matches any of the standard image formats.
>
> So... There is still hope to use already written tools to decode your
> format.
>
> Here's a hint on how to use numpy for decoding a byte string into an
> array of floats. My example byte string is a hand coded string of just
> 12 bytes -- you should replace that with a whole row or better yet, a
> whole tile's worth of bytes.
>
> >>> import numpy
> >>> byteString = '[EMAIL PROTECTED]@@'
> >>> b = numpy.frombuffer(byteString, dtype=numpy.float32)
> >>> b
> array([ 1., 2., 3.], dtype=float32)
>
>
> If you want to use the array module instead:
>
> >>> import array
> >>> a = array.array('f')
> >>> a.fromstring(byteString)
> >>> a
> array('f', [1.0, 2.0, 3.0])
>
>
> In either case ANY number of bytes can be decoded into an array of
> floats, in one highly efficient call from Python.
>
> What you do with that array of float afterwards is up to you....
>
> If I read your note correctly, here's what I'd do to turn the array of
> bytes into an image of a tile to be displayed on the screen.
>
> Get the whole tile's worth of bytes with one read into a single string.
> Decode that string into an array of floats (as above).
> Reshape the array into a 3D array (i.e., a rectangular array of RGBA
> values)
> Convert that array of floats into an array of 8-bit integers (scaling
> all by 255).
> Extract (via tostring) that array into a string of bytes.
> Send that string of bytes to the graphics system as an RGBA array of
> pixels.
>
> Each of these calls is one Python call into a highly efficient library.
> This is using Python as a, so called, glue language.
>
> Gary Herron
>
>
>
>
>
>
>
> >
> > > Date: Thu, 15 May 2008 10:09:45 -0700
> > > From: [EMAIL PROTECTED]
> > > CC: python-list@python.org
> > > Subject: Re: How do I use the unpack function?
> > >
> > > John Machin wrote:
> > > > On May 16, 2:11 am, Gary Herron <[EMAIL PROTECTED]>
wrote:
> > > >
> > > >> Marlin Rowley wrote:
> > > >>
> > > >>> All:
> > > >>>
> > > >>> I've got a script that runs really slow because I'm reading
from a
> > > >>> stream a byte at a time:
> > > >>>
> > > >>> // TERRIBLE
> > > >>> for y in range( height ):
> > > >>> for color in range(4):
> > > >>> for x in range( width ):
> > > >>> pixelComponent = fileIO.read(4)
> > > >>> buffer = unpack("!f",pixelComponent) << unpacks ONE
> > > >>>
> > > >
> > > > [snip]
> > > > Perhaps the OP might be able to use the Python Imaging Library
(PIL)
> > > > instead of reinventing an image-file handler.
> > > >
> > >
> > > Indeed. That's why my original answer included the line:
> > > There are probably better ways overall, but this directly answers
> > > your question.
> > >
> > > Other possibilities.
> > >
> > > I don't recognize the file format being read in here, but if it is a
> > > standard image format, the PIL suggestion is a good way to go.
> > >
> > > Or, if it is an image of not too enormous size, read the *whole*
thing
> > > in at once.
> > >
> > > Or rather than manipulate the array by carving off 4 bytes at a
time,
> > > just index through it in 4 byte chunks:
> > > for i in range(width):
> > > buffer = unpack("!f", pixelComponent[4*i:4*i+4])
> > >
> > > Or
> > > for i in range(0,4*width,4):
> > > buffer = unpack("!f", pixelComponent[i:i+4])
> > >
> > > Or
> > > Use numpy. Create an array of floats, and initialize it with the
byte
> > > string, making sure to take endianess int account. (I'm quite
sure this
> > > could be made to work, and then the whole operation is
enormously fast
> > > with only several lines of Python code and *no* Python loops.
> > >
> > > Or
> > > ...?
> > >
> > > Gary Herron
> > >
> > > > --
> > > > http://mail.python.org/mailman/listinfo/python-list
> > > >
> > >
> > > --
> > > http://mail.python.org/mailman/listinfo/python-list
> >
> >
------------------------------------------------------------------------
> > Windows Live SkyDrive lets you share files with faraway friends.
Start
> > sharing.
> >
<http://www.windowslive.com/skydrive/overview.html?ocid=TXT_TAGLM_WL_Refresh_skydrive_052008>
> >
> >
------------------------------------------------------------------------
> >
> > --
> > http://mail.python.org/mailman/listinfo/python-list
>
> --
> http://mail.python.org/mailman/listinfo/python-list
------------------------------------------------------------------------
Get Free (PRODUCT) REDâ„¢ Emoticons, Winks and Display Pics. Check it
out!
<http://joinred.spaces.live.com?ocid=TXT_HMTG_prodredemoticons_052008>
--
http://mail.python.org/mailman/listinfo/python-list