Cropping an image with wxPython

I know how to load an image and and display it in wxPython using wx.Image. However, I would like to create a simple application where I can draw a bounding box on top of the image that I can use to crop the image.

I am not sure what the best approach is for drawing the box. Should I be using a DC to load the image instead of wx.Image? How do you translate the beginning and ending position tuples in wxPython to the correct pixel locations in the image?

Any advice is appreciated.

Thanks so much!

  • Mike

Here’s one approach:

  • Create a window class derived from wx.Window or similar, and pass a wx.Image or wx.Bitmap to its __init__ in addition to the usual window parameters.

  • Give it a EVT_PAINT handler where it (re)draws the bitmap.

  • Add mouse event handlers and follow the example in the Overlay sample in the demo for displaying the bounding box.

  • In the mouse-up handler use the starting and ending coordinates to crop your image.

Easy-peasy!

Hi Robin,

Sorry for not getting to this sooner. I don’t really understand what you mean when you say I should pass a wx.Image to the wx.Window's __init__(). Are you saying I should create an instance of wx.Image and then pass it along to the window? Or are you suggesting to do multiple inheritance with the window and image?

Sorry for being a bit dense here. I know how to add a wx.Image to a panel. Just not sure what you mean here.

Thanks,
Mike

Sorry for the confusion, I was just trying to give a glimpse of the whole picture for anybody else that comes along with the same needs.

The part intended to answer your question is to use a wx.Overlay (on a window that displays the image) to manage the bounding box. The Overlay.py sample in the demo can serve as a guide on how to use the overlay. Once the left-up happens you can use the starting and ending positions to crop the image into a new one to be displayed, or whatever you need to do with it.

Ah. Okay. I can probably do that. The part I was worried about is if the image is scaled to fit inside the panel, I wasn’t sure I could get it to crop correctly using an overlay. I suspect the coordinates I get back will be a bit off.

If the image is scaled to fit then I expect that the best that can be done is to keep the scale factor and simply multiply the pixel positions by that scale factor when needed. It won’t be an exact pixel position on the unscaled image, but I expect that the users would not expect it to be so since they can’t see the unscaled pixels anyway. So an approximate location is likely to be good enough in this case.

If being able to select with exact positions is important for your use-case then you can allow the select to zoom in on the image until it gets to a 1:1 scale. Or you can use a wx.ScrolledWindow with a variable zoom that the user chooses so they can zoom in to what they are interested in before making the selection, if they want to, and scroll around in the image as needed. That can get tricky, however, if the user wants to select beyond the visible area of the image. Scrolling the image while selecting is doable, but it raises the complexity factor a bit.

Yeah, I was thinking about this after I posted my response and thought that using the scale factor was the way to go.

I saw some people on StackOverflow mentioning using a ScrolledWindow for this. I agree that that will bump the complexity up quite a bit, which I don’t want right now. That would probably be good for a deep dive into this topic, but not for the short example I was hoping to do.

While I like having these high resolution cameras, you need to have high resolution monitors to be able to view them at their actual size. Most people don’t have the ability.

1080p = 1920x1080
4k = 3840 x 2160

My cell phone shoots photos that are 4032x3024, so I would need an 8K monitor to show it properly.

Thanks for the input. I’ll give it a try.