I have a data visualization app where I use numpy to generate
sequences of images that I want to view like a movie, so I was excited
to try the new wx.BitmapFromBuffer and friends. Using 2.7.1.3, I'm
actually getting slower times using BitmapFromBuffer than the old way
of wx.ImageFromData + wx.BitmapFromImage.
Anyway, I thought it might be the overhead of allocating a new bitmap
all the time in wx.BitmapFromBuffer, e.g. from _bitmap.i:
wxBitmap* bmp = new wxBitmap(width, height, 24);
so I added a CopyFromBuffer method into _bitmap.i to overwrite a
bitmap's data with a new buffer object, avoiding the memory
allocation. This new method does show to be faster than
wx.BitmapFromBuffer, although it is still not faster than the old
school wx.ImageFromData + wx.BitmapFromImage. (I'm hoping that will
change once I can get wx to build in non-debug mode.)
Also including a test program.
Thanks,
Rob
%extend {
DocStr(CopyFromBuffer, "Copy data from a buffer object to
replace the bitmap pixel data.", "");
void CopyFromBuffer(buffer data, int DATASIZE) {
if (DATASIZE != self->GetWidth()*self->GetHeight()*3) {
wxPyErr_SetString(PyExc_ValueError, "Invalid data
buffer size.");
}
wxNativePixelData pixData(*self, wxPoint(0,0),
wxSize(self->GetWidth(),self->GetHeight()));
if (! pixData) {
// raise an exception...
wxPyErr_SetString(PyExc_RuntimeError,
"Failed to gain raw access to bitmap data.");
}
wxNativePixelData::Iterator p(pixData);
int height=self->GetHeight();
int width=self->GetWidth();
for (int y=0; y<height; y++) {
wxNativePixelData::Iterator rowStart = p;
for (int x=0; x<width; x++) {
p.Red() = *(data++);
p.Green() = *(data++);
p.Blue() = *(data++);
++p;
}
p = rowStart;
p.OffsetY(pixData, 1);
}
}
}
Following up to report that the non-debug build does speed things up.
The CopyFromBuffer method becomes the fastest, and wx.BitmapFromBuffer
speeds up to the same speed as the wx.ImageFromData +
wx.BitmapFromImage.
For my timing test in the demo program (which draws 100 frames), it
reports the following on my linux system:
On 10/29/06, Rob McMullen <rob.mcmullen@gmail.com> wrote:
I have a data visualization app where I use numpy to generate
sequences of images that I want to view like a movie, so I was excited
to try the new wx.BitmapFromBuffer and friends. Using 2.7.1.3, I'm
actually getting slower times using BitmapFromBuffer than the old way
of wx.ImageFromData + wx.BitmapFromImage.
Anyway, I thought it might be the overhead of allocating a new bitmap
all the time in wx.BitmapFromBuffer, e.g. from _bitmap.i:
wxBitmap* bmp = new wxBitmap(width, height, 24);
so I added a CopyFromBuffer method into _bitmap.i to overwrite a
bitmap's data with a new buffer object, avoiding the memory
allocation. This new method does show to be faster than
wx.BitmapFromBuffer, although it is still not faster than the old
school wx.ImageFromData + wx.BitmapFromImage. (I'm hoping that will
change once I can get wx to build in non-debug mode.)
Also including a test program.
Thanks,
Rob
%extend {
DocStr(CopyFromBuffer, "Copy data from a buffer object to
replace the bitmap pixel data.", "");
void CopyFromBuffer(buffer data, int DATASIZE) {
if (DATASIZE != self->GetWidth()*self->GetHeight()*3) {
wxPyErr_SetString(PyExc_ValueError, "Invalid data
buffer size.");
}
wxNativePixelData pixData(*self, wxPoint(0,0),
wxSize(self->GetWidth(),self->GetHeight()));
if (! pixData) {
// raise an exception...
wxPyErr_SetString(PyExc_RuntimeError,
"Failed to gain raw access to bitmap data.");
}
wxNativePixelData::Iterator p(pixData);
int height=self->GetHeight();
int width=self->GetWidth();
for (int y=0; y<height; y++) {
wxNativePixelData::Iterator rowStart = p;
for (int x=0; x<width; x++) {
p.Red() = *(data++);
p.Green() = *(data++);
p.Blue() = *(data++);
++p;
}
p = rowStart;
p.OffsetY(pixData, 1);
}
}
}
The CopyFromBuffer method becomes the fastest, and wx.BitmapFromBuffer
speeds up to the same speed as the wx.ImageFromData +
wx.BitmapFromImage.
Thanks for working on this -- but I'm still perplexed.
wx.ImageFromData + wx.BitmapFromImage.
should be creating at least one full extra copy of the data, and BitmapFromBuffer should be creating none. Unless wx.BitmapFromImage shares data between the Bitmap and Image when possible. But doesn't wx.ImageFrom data make a copy anyway?
So wx.BitmapFromBuffer should be the fastest, but a notable amount.
weird.
-Chris
···
--
Christopher Barker, Ph.D.
Oceanographer
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception
I have a data visualization app where I use numpy to generate
sequences of images that I want to view like a movie, so I was excited
to try the new wx.BitmapFromBuffer and friends. Using 2.7.1.3, I'm
actually getting slower times using BitmapFromBuffer than the old way
of wx.ImageFromData + wx.BitmapFromImage.
Anyway, I thought it might be the overhead of allocating a new bitmap
all the time in wx.BitmapFromBuffer, e.g. from _bitmap.i:
wxBitmap* bmp = new wxBitmap(width, height, 24);
so I added a CopyFromBuffer method into _bitmap.i to overwrite a
bitmap's data with a new buffer object, avoiding the memory
allocation. This new method does show to be faster than
wx.BitmapFromBuffer, although it is still not faster than the old
school wx.ImageFromData + wx.BitmapFromImage.
That surprises me somewhat since I thought that BitmapFromImage was using a similar algorithm to move the bytes into the bitmap, and that BitmapFromBuffer would eliminate the time for the additional buffer copy, however looking closer at the code it is doing a more low level copy using platform APIs, (at least on MSW, haven't looked at the others yet.) So I guess that optimization balances out the overhead needed to make the raw pixelbuffer access be platform independent. (IIRC, on windows it is probably the difference between making a DDB and a DIB...)
However, my times for CopyFromBuffer and wx.ImageFromData + wx.BitmapFromImage on your sample are all within a few milliseconds of each other (again, just tested on MSW so far) so I'm not too disappointed. Anyway, the main purpose of the raw bitmap access addition is for fiddling with the guts of an existing bitmap, rather than for creating whole new bitmaps, so that gives us some good advantages to this new code too, even if it doesn't shine as brightly as I hoped for the bitmap creation.
BTW, I expect that there will be some (possibly big) variations based on platform here.
Thanks for the CopyFromBuffer code. I've tweaked it a bit and added it to _bitmap.i, and will add a RGBA version too.
···
--
Robin Dunn
Software Craftsman http://wxPython.org Java give you jitters? Relax with wxPython!
However, my times for CopyFromBuffer and wx.ImageFromData +
wx.BitmapFromImage on your sample are all within a few milliseconds of
each other (again, just tested on MSW so far) so I'm not too
disappointed. Anyway, the main purpose of the raw bitmap access
addition is for fiddling with the guts of an existing bitmap, rather
than for creating whole new bitmaps, so that gives us some good
advantages to this new code too, even if it doesn't shine as brightly as
I hoped for the bitmap creation.
Yeah, I'm probably pushing the envelope trying to make an app that is
almost a movie player using straight wxPython... I could look at
DirectPython or the equivalent on the other platforms, but I wanted to
use an out-of-the-box wxPython if I could.
BTW, I expect that there will be some (possibly big) variations based on
platform here.
I was only able to test on GTK; I have a windows machine but haven't
purchased the MS dev environment.
Thanks for the CopyFromBuffer code. I've tweaked it a bit and added it
to _bitmap.i, and will add a RGBA version too.
I was only able to test on GTK; I have a windows machine but haven't
purchased the MS dev environment.
FWIW, there is a no-charge version of the MS compiler available, plus you can compile python extensions with MinGW, though I don't think anyone has set up wxPython to be compiled that way.
-CHB
···
--
Christopher Barker, Ph.D.
Oceanographer
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception
FWIW, there is a no-charge version of the MS compiler available, plus
you can compile python extensions with MinGW, though I don't think
anyone has set up wxPython to be compiled that way.
I've used MinGW to build some extensions at work, and thought about
trying to get it to work for wxPython, but never took up the
challenge.
Back in the archives of python-users, there was some discussion about
the use of VC 2005 with Python, but since py is built with VC 2003,
there are library incompatibilities. Bummer.
Rumor has it that py 2.6 will use VC 2005, but until then it appears
that there's no free (beer or speech) option for an end-to-end freely
compilable python system that works with existing binary extensions.
If you look around, you can find the 2003 SDK on the internet.
Alternatively, you can recompile Python using VC 2005. There are some
patches that may or may not have made it into the 2.5-maint branch for
making VC 2005 compilations easier, but if you search the python-dev
archives, there are at least links to patches and/or information.
- Josiah
···
"Rob McMullen" <rob.mcmullen@gmail.com> wrote:
> FWIW, there is a no-charge version of the MS compiler available, plus
> you can compile python extensions with MinGW, though I don't think
> anyone has set up wxPython to be compiled that way.
I've used MinGW to build some extensions at work, and thought about
trying to get it to work for wxPython, but never took up the
challenge.
Back in the archives of python-users, there was some discussion about
the use of VC 2005 with Python, but since py is built with VC 2003,
there are library incompatibilities. Bummer.
Rumor has it that py 2.6 will use VC 2005, but until then it appears
that there's no free (beer or speech) option for an end-to-end freely
compilable python system that works with existing binary extensions.