wx.BitmapFromBuffer inside a thread

Hi All,

I was hoping to find an answer to a problem I have found in my code. I have a GUI that spawns a thread which connects to a database to get pixel data. After I get my pixel data, I do a lot of manipulation on it to convert it to an RGB array and then call wx.BitmapFromBuffer and a few other wx.Bitmap calls before I send the data to be displayed via wx.CallAfter.

As soon as I call the wx.BitmapFromBuffer inside the thread, the program crashes with the error: **python: Fatal IO error 11 (Resource temporarily unavailable) on X server :0.0. **If I move all the image processing to my call after function, everything works fine. I would like to keep all the data manipulation inside the thread if possible. Any help is greatly appreciated.

Best Regards,

Steve

Steve wrote:

I was hoping to find an answer to a problem I have found in my code.

yup -- don't do that.

You can't make GUI calls from another thread, and wx.Bitmap manipulation is a GUI call.

I do a lot of manipulation on it to convert it to an RGB array and then call wx.BitmapFromBuffer and a few other wx.Bitmap calls before I send the data to be displayed via wx.CallAfter.

You'll have to move your wx.Bitmap calls into the main thread. What else are you doing besides wx.BitmapFromBuffer maybe you can do that without wx calls (PIL or numpy or ?).

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Steve wrote:

I was hoping to find an answer to a problem I have found in my code.

yup – don’t do that.

You can’t make GUI calls from another thread, and wx.Bitmap manipulation is a GUI call.

That clears that up. :slight_smile: Thanks.

I do a lot of manipulation on it to convert it to an RGB array and then call wx.BitmapFromBuffer and a few other wx.Bitmap calls before I send the data to be displayed via wx.CallAfter.

You’ll have to move your wx.Bitmap calls into the main thread. What else are you doing besides wx.BitmapFromBuffer maybe you can do that without wx calls (PIL or numpy or ?).

I am basically just reformatting my data so I can call wx.BitmapFromBuffer because I am sent a 1 dim array via the DB. Here is the section of my image processing:

data = numpy.fromstring (msg, dtype = numpy.uint16)

ndimg = data.reshape ((128, 128))

rgb = numpy.zeros ((128, 128, 3), dtype = numpy.uint16)

rgb[:,:,0] = rgb[:,:,1] = rgb[:,:,2] = ndimg

wfsImg = wx.BitmapFromBuffer (rgb.shape[0], rgb.shape[1], rgb)

tmpImg = wx.ImageFromBitmap (wfsImg)

if self.imgSize.GetValue() == 1:

do nothing

pass

if self.imgSize.GetValue() == 2:

tempImg.Rescale (256, 256)

if self.imgSize.GetValue() == 3:

tempImg.Rescale (384, 384)

if self.imgSize.GetValue() == 4:

tempImg.Rescale (512, 512)

self.image = wx.BitmapFromImage (tmpImg)

wx.CallAfter (self.window.UpdateDisplay, self.image)

There doesn’t seem to be any issue when doing it in my main thread, with regard to speed, but I figured I would have the thread do it since it was the one getting the data.

Kind Regards,

Steve

···

On Wed, May 26, 2010 at 1:04 AM, Christopher Barker Chris.Barker@noaa.gov wrote:

-Chris

Christopher Barker, Ph.D.

Oceanographer

Emergency Response Division

NOAA/NOS/OR&R (206) 526-6959 voice

7600 Sand Point Way NE (206) 526-6329 fax

Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com

or visit http://groups.google.com/group/wxPython-users?hl=en

There's nothing wrong with doing long running processes in a separate
thread. In fact, I recommend it. Those things can make the GUI
unresponsive otherwise. The problems occur when you take the result of
the long running process and try to update your GUI with it from
another thread. Sometimes it works and other times it causes your app
to crash. Thus, wx provides some thread-safe methods: wx.CallAfter,
wx.CallLater and wx.PostEvent. I ended up writing an article about
this over the weekend since this is such a common issue:

Good luck!

···

On May 25, 8:35 pm, Steve <ghostra...@gmail.com> wrote:

On Wed, May 26, 2010 at 1:04 AM, Christopher Barker > <Chris.Bar...@noaa.gov>wrote:

> Steve wrote:

>> I was hoping to find an answer to a problem I have found in my code.

> yup -- don't do that.

> You can't make GUI calls from another thread, and wx.Bitmap manipulation is
> a GUI call.

That clears that up. :slight_smile: Thanks.

> I do a lot of manipulation on it to convert it to an RGB array and then
>> call wx.BitmapFromBuffer and a few other wx.Bitmap calls before I send the
>> data to be displayed via wx.CallAfter.

> You'll have to move your wx.Bitmap calls into the main thread. What else
> are you doing besides wx.BitmapFromBuffer maybe you can do that without wx
> calls (PIL or numpy or ?).

I am basically just reformatting my data so I can call wx.BitmapFromBuffer
because I am sent a 1 dim array via the DB. Here is the section of my image
processing:

data = numpy.fromstring (msg, dtype = numpy.uint16)
ndimg = data.reshape ((128, 128))

rgb = numpy.zeros ((128, 128, 3), dtype = numpy.uint16)
rgb[:,:,0] = rgb[:,:,1] = rgb[:,:,2] = ndimg

wfsImg = wx.BitmapFromBuffer (rgb.shape[0], rgb.shape[1], rgb)
tmpImg = wx.ImageFromBitmap (wfsImg)

if self.imgSize.GetValue() == 1:
# do nothing
pass
if self.imgSize.GetValue() == 2:
tempImg.Rescale (256, 256)
if self.imgSize.GetValue() == 3:
tempImg.Rescale (384, 384)
if self.imgSize.GetValue() == 4:
tempImg.Rescale (512, 512)

self.image = wx.BitmapFromImage (tmpImg)
wx.CallAfter (self.window.UpdateDisplay, self.image)

There doesn't seem to be any issue when doing it in my main thread, with
regard to speed, but I figured I would have the thread do it since it was
the one getting the data.

Kind Regards,

Steve

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org

Steve wrote:

I am basically just reformatting my data so I can call wx.BitmapFromBuffer because I am sent a 1 dim array via the DB. Here is the section of my image processing:

You can still do the numpy stuff in your thread, that may help. You also May be able to do wxImage stuff in another thread -- I think that's all wx code, not calling into the platform APIs

a couple comments:

data = numpy.fromstring (msg, dtype = numpy.uint16)
ndimg = data.reshape ((128, 128))

rgb = numpy.zeros ((128, 128, 3), dtype = numpy.uint16)
rgb[:,:,0] = rgb[:,:,1] = rgb[:,:,2] = ndimg

is this a 16 bit greyscale image?

wfsImg = wx.BitmapFromBuffer (rgb.shape[0], rgb.shape[1], rgb)

I'm confused -- doesn't wx.BitmapFrom Buffer take 24 bit rgb? i.e. a (h,w,3) numpy array of type uint8? I"d expect some odd results from this.

tmpImg = wx.ImageFromBitmap (wfsImg)

if you do have 24 bit rbg, you should be able to create a wx.Image straight off:

I = wx.ImageFromBuffer(w, h, rgb)

self.image = wx.BitmapFromImage (tmpImg)

then put this in the main thread:

wx.CallAfter (self.window.UpdateDisplay, self.image)

HTH,

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Chris,

Thanks for your help. It has been very informative.

a couple comments:

data = numpy.fromstring (msg, dtype = numpy.uint16)

ndimg = data.reshape ((128, 128))

rgb = numpy.zeros ((128, 128, 3), dtype = numpy.uint16)

rgb[:,:,0] = rgb[:,:,1] = rgb[:,:,2] = ndimg

is this a 16 bit greyscale image?

The data I am getting is from a CCD camera (14 bit) but stuffed into unsigned shorts before I get it. I set my rgb to uint8 but some of the data is wrapping now so the image looks off. Do you have any suggestions for displaying this type of data using the BitmapFromBuffer or ImageFromBuffer so I could get the full range?

wfsImg = wx.BitmapFromBuffer (rgb.shape[0], rgb.shape[1], rgb)

I’m confused – doesn’t wx.BitmapFrom Buffer take 24 bit rgb? i.e. a (h,w,3) numpy array of type uint8? I"d expect some odd results from this.

It does and I was seeing problems until I switch it to uint8, but now I have my wrapping issue.

tmpImg = wx.ImageFromBitmap (wfsImg)

if you do have 24 bit rbg, you should be able to create a wx.Image straight off:

I = wx.ImageFromBuffer(w, h, rgb)

self.image = wx.BitmapFromImage (tmpImg)

Thanks again for your help!!

Best Regards,

Steve

Steve wrote:

a couple comments:

data = numpy.fromstring (msg, dtype = numpy.uint16)

ndimg = data.reshape ((128, 128))

rgb = numpy.zeros ((128, 128, 3), dtype = numpy.uint16)
rgb[:,:,0] = rgb[:,:,1] = rgb[:,:,2] = ndimg

is this a 16 bit greyscale image?

The data I am getting is from a CCD camera (14 bit) but stuffed into
unsigned shorts before I get it. I set my rgb to uint8 but some of the data
is wrapping now so the image looks off. Do you have any suggestions for
displaying this type of data using the BitmapFromBuffer or ImageFromBuffer
so I could get the full range?

you can get the full range, but you'll lose resolution -- something like:

ndimg_8bit = ( ndimg / (max_val/255) ).astype(np.uint8)

where mac_val is the largest number (white?) you get in your data.

HTH,

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

That worked great! Thanks again for your help!!

Best wishes,

Steve

···

On Fri, May 28, 2010 at 5:00 PM, Christopher Barker Chris.Barker@noaa.gov wrote:

Steve wrote:

a couple comments:

data = numpy.fromstring (msg, dtype = numpy.uint16)

ndimg = data.reshape ((128, 128))

rgb = numpy.zeros ((128, 128, 3), dtype = numpy.uint16)

rgb[:,:,0] = rgb[:,:,1] = rgb[:,:,2] = ndimg

is this a 16 bit greyscale image?

The data I am getting is from a CCD camera (14 bit) but stuffed into

unsigned shorts before I get it. I set my rgb to uint8 but some of the data

is wrapping now so the image looks off. Do you have any suggestions for

displaying this type of data using the BitmapFromBuffer or ImageFromBuffer

so I could get the full range?

you can get the full range, but you’ll lose resolution – something like:

ndimg_8bit = ( ndimg / (max_val/255) ).astype(np.uint8)

where mac_val is the largest number (white?) you get in your data.

HTH,

-Chris

Christopher Barker, Ph.D.

Oceanographer

Emergency Response Division

NOAA/NOS/OR&R (206) 526-6959 voice

7600 Sand Point Way NE (206) 526-6329 fax

Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com

or visit http://groups.google.com/group/wxPython-users?hl=en