Search code examples
pythonopencvwxpythonwxwidgets

Displaying VideoCapture using OpenCV with python and wxPython in a wx.panel: Show only small region of the video


I'm trying to display OpenCV with Python interface in wxPython. I can display it but only a small region in the top left corner of the video. What is the problem with my code? is it the size of parent panel or something else? note that I use code from this https://stackoverflow.com/a/14818080/2389238 and It can run perfectly but I need to display it in a panel (or other parent frame).

Thank in Advance.

import wx
import cv, cv2

class MainWindow(wx.Panel):
    def __init__(self, parent,capture):
        wx.Panel.__init__(self, parent)
        mainSizer = wx.BoxSizer(wx.VERTICAL)

        self.inputBox = wx.TextCtrl(self)
        mainSizer.Add(self.inputBox, 0, wx.ALL, 5)

        # video
        videoWarper = wx.StaticBox(self, label="Video",size=(640,480))
        videoBoxSizer = wx.StaticBoxSizer(videoWarper, wx.VERTICAL)
        videoFrame = wx.Panel(self, -1,size=(640,480))
        cap = ShowCapture(videoFrame, capture)
        videoBoxSizer.Add(videoFrame,0)
        mainSizer.Add(videoBoxSizer,0)

        parent.Centre()
        self.Show()
        self.SetSizerAndFit(mainSizer)


class ShowCapture(wx.Panel):
    def __init__(self, parent, capture, fps=24):
        wx.Panel.__init__(self, parent)

        self.capture = capture
        ret, frame = self.capture.read()

        height, width = frame.shape[:2]

        parent.SetSize((width, height))

        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

        self.bmp = wx.BitmapFromBuffer(width, height, frame)

        self.timer = wx.Timer(self)
        self.timer.Start(1000./fps)

        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_TIMER, self.NextFrame)


    def OnPaint(self, evt):
        dc = wx.BufferedPaintDC(self)
        dc.DrawBitmap(self.bmp, 0, 0)

    def NextFrame(self, event):
        ret, frame = self.capture.read()
        if ret:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            self.bmp.CopyFromBuffer(frame)
            self.Refresh()


capture = cv2.VideoCapture(0)

app = wx.App(False)
frame = wx.Frame(None,-1,'HGA Count',size=(400, 400))
panel = MainWindow(frame,capture)
frame.Show()
app.MainLoop()

This is the image: http://i58.tinypic.com/2u5t7kh.png Sorry for the link I can't put image here due to low reputation.


Solution

  • Basically, nothing sets your ShowCapture window size to the desired size, so it remains stuck at some default size. The simplest solution would probably be to do without videoFrame at all as it seems to be not needed and just create cap itself with the desired initial size, which will also become the minimal window size.


    Follow up after the question update:

    1. You can resize it automatically using the sizers and ensuring that:
      • The item itself grows, i.e. has positive proportion if you want it to grow in the major direction of the sizer (vertical for wxVERTICAL box sizer, horizontal for... you guessed it) or wxEXPAND flag if you want it to grow in the other direction. Or both, of course, if you want it to grow in both direction.
      • Very important as often forgotten: the containing sizer itself grows as well. I.e. nothing will happen if the window itself grows inside its sizer if its sizer doesn't grow inside its own containing sizer.
    2. videoFrame is not necessary and, in fact, you ought to make your video window child of videoWarper if you're using 3.0 for the best results: since 3.0, the contents of a wxStaticBoxSizer should be created with its wxStaticBox as parent.