When I was experimenting with opencv a while ago, I created the app below. This uses opencv’s resize() method to resize the images instead of using the StaticBitmap’s SetScaleMode().
When you resize the frame, the images are automatically resized while maintaining the original aspect ratio.
# Based on an example from:
# https://stackoverflow.com/questions/35009984/get-stream-from-webcam-with-opencv-and-wxpython
#
# To install cv2:
# pip install opencv-python
#
import cv2
import wx
from wx.lib.statbmp import GenStaticBitmap
INIT_SIZE = (640, 480)
FRAMES_PER_SECOND = 17
TIMER_INTERVAL = 1000 // FRAMES_PER_SECOND
class ViewWindow(wx.Frame):
def __init__(self, parent, capture, title="Webcam Viewer"):
super(ViewWindow, self).__init__(parent, title=title)
self.capture = capture
self.SetSize(INIT_SIZE)
self.SetBackgroundColour(wx.BLACK)
v_sizer = wx.BoxSizer(wx.VERTICAL)
h_sizer = wx.BoxSizer(wx.HORIZONTAL)
v_sizer.Add(h_sizer, 1, wx.ALIGN_CENTER_HORIZONTAL, 0)
image = wx.Image(INIT_SIZE)
bitmap = wx.Bitmap(image)
self.static_bitmap = GenStaticBitmap(self, wx.ID_ANY, bitmap)
h_sizer.Add(self.static_bitmap, 0, wx.ALIGN_CENTER_VERTICAL, 0)
self.SetSizer(v_sizer)
self.Layout()
self.refreshView()
self.timer = wx.Timer(self)
self.timer.Start(TIMER_INTERVAL)
self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
def refreshView(self):
res, video_frame = self.capture.read()
if res:
cv_image = cv2.cvtColor(video_frame, cv2.COLOR_BGR2RGB)
ih, iw = video_frame.shape[:2]
pw, ph = self.GetSize()
p_ratio = ph / pw
i_ratio = ih / iw
if p_ratio == i_ratio:
rw, rh = pw, ph
else:
if p_ratio > i_ratio:
rw = pw
rh = round(rw * i_ratio)
else: # p_ratio < i_ratio:
rh = ph
rw = round(rh / i_ratio)
cv_image = cv2.resize(cv_image, (rw, rh), interpolation=cv2.INTER_CUBIC)
bitmap = wx.Bitmap.FromBuffer(rw, rh, cv_image)
self.static_bitmap.SetBitmap(bitmap)
self.Refresh()
else:
print("Failed to get video-frame from webcam")
def OnTimer(self, _e):
self.refreshView()
def main():
app = wx.App()
capture = cv2.VideoCapture(0)
if capture.isOpened():
frame = ViewWindow(None, capture)
frame.Center()
frame.Show()
app.MainLoop()
else:
print("Failed to open the webcam.")
if __name__ == '__main__':
main()
Tested on Python 3.10.4 + wxPython 4.2.0 gtk3 (phoenix) wxWidgets 3.2.0 + Linux Mint 21